@rubytech/create-maxy-code 0.1.330 → 0.1.331
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/dist/index.js +19 -2
- package/package.json +1 -1
- package/payload/platform/config/brand.json +1 -0
- package/payload/platform/lib/account-enumeration/dist/index.d.ts +33 -0
- package/payload/platform/lib/account-enumeration/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/account-enumeration/dist/index.js +76 -0
- package/payload/platform/lib/account-enumeration/dist/index.js.map +1 -1
- package/payload/platform/lib/account-enumeration/src/index.ts +78 -0
- package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +13 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js +102 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/tools/__tests__/account-lifecycle.test.d.ts +2 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/__tests__/account-lifecycle.test.d.ts.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/__tests__/account-lifecycle.test.js +57 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/__tests__/account-lifecycle.test.js.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts +34 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js +78 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js.map +1 -0
- package/payload/platform/plugins/admin/skills/plainly/SKILL.md +7 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +2 -2
- package/payload/platform/plugins/contacts/mcp/dist/index.js +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/contact-lookup.test.d.ts +2 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/contact-lookup.test.d.ts.map +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/contact-lookup.test.js +71 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/contact-lookup.test.js.map +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.d.ts +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.d.ts.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.js +10 -3
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.js.map +1 -1
- package/payload/platform/plugins/contacts/mcp/package.json +4 -2
- package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
- package/payload/platform/plugins/memory/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/memory/PLUGIN.md +1 -1
- package/payload/platform/plugins/memory/mcp/dist/index.js +3 -1
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-lookup-by-name.test.js +39 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-lookup-by-name.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-lookup-by-name.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-lookup-by-name.js +13 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-lookup-by-name.js.map +1 -1
- package/payload/platform/scripts/__tests__/provision-role-stamp.test.sh +40 -0
- package/payload/platform/scripts/__tests__/sweep-durability.test.sh +103 -0
- package/payload/platform/scripts/lib/provision-account-dir.sh +319 -0
- package/payload/platform/scripts/lib/resolve-account-dir.sh +79 -132
- package/payload/platform/scripts/setup-account.sh +28 -361
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +4 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/config.d.ts +18 -0
- package/payload/platform/services/claude-session-manager/dist/config.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/config.js +63 -7
- package/payload/platform/services/claude-session-manager/dist/config.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +30 -2
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +16 -1
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +7 -0
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts +5 -0
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js +8 -0
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/stuck-turn.d.ts +6 -0
- package/payload/platform/services/claude-session-manager/dist/stuck-turn.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/stuck-turn.js +17 -5
- package/payload/platform/services/claude-session-manager/dist/stuck-turn.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/instructions.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/instructions.js +25 -1
- package/payload/platform/services/webchat-channel/dist/instructions.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/notification.d.ts +17 -0
- package/payload/platform/services/webchat-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/notification.js +14 -0
- package/payload/platform/services/webchat-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/server.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/server.js +66 -2
- package/payload/platform/services/webchat-channel/dist/server.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/turn-follow.d.ts +28 -0
- package/payload/platform/services/webchat-channel/dist/turn-follow.d.ts.map +1 -0
- package/payload/platform/services/webchat-channel/dist/turn-follow.js +188 -0
- package/payload/platform/services/webchat-channel/dist/turn-follow.js.map +1 -0
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js +24 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
- package/payload/platform/templates/account.json +2 -0
- package/payload/server/public/assets/AdminLoginScreens-DexSvtjD.js +1 -0
- package/payload/server/public/assets/AdminShell-Bf9tndNg.js +1 -0
- package/payload/server/public/assets/{Checkbox-1flpB9H0.js → Checkbox-D58GsKoQ.js} +1 -1
- package/payload/server/public/assets/{OperatorConversations-DrPqB9Ym.css → OperatorConversations-CDdp2nVn.css} +1 -1
- package/payload/server/public/assets/OperatorConversations-RmqANYz8.js +9 -0
- package/payload/server/public/assets/{admin-BWJTvagN.js → admin-CH5Vkkt4.js} +1 -1
- package/payload/server/public/assets/{browser-XM5e-fn1.js → browser-BwDtzSlr.js} +1 -1
- package/payload/server/public/assets/chat-3GY0LmYH.js +1 -0
- package/payload/server/public/assets/data-CttrzhfL.js +1 -0
- package/payload/server/public/assets/{graph-CIIz9Dmh.js → graph-CZSdF2jv.js} +3 -3
- package/payload/server/public/assets/{graph-labels-BRKvhE0e.js → graph-labels-Bi0fu8Ns.js} +1 -1
- package/payload/server/public/assets/operator-BEivxmRy.js +1 -0
- package/payload/server/public/assets/page-DUvT07SB.js +30 -0
- package/payload/server/public/assets/{public-BPlZnopr.js → public-B3eIlVbd.js} +1 -1
- package/payload/server/public/browser.html +4 -4
- package/payload/server/public/chat.html +5 -5
- package/payload/server/public/data.html +4 -4
- package/payload/server/public/graph.html +6 -6
- package/payload/server/public/index.html +6 -6
- package/payload/server/public/operator.html +7 -7
- package/payload/server/public/public.html +5 -5
- package/payload/server/server.js +314 -222
- package/payload/server/public/assets/AdminLoginScreens-BnuaXvxN.js +0 -1
- package/payload/server/public/assets/AdminShell-Br0DJQNu.js +0 -1
- package/payload/server/public/assets/OperatorConversations-C8sITz2_.js +0 -9
- package/payload/server/public/assets/chat-COFMxaoC.js +0 -1
- package/payload/server/public/assets/data-BHtJozT2.js +0 -1
- package/payload/server/public/assets/operator-9hbxrXKm.js +0 -1
- package/payload/server/public/assets/page-CXkBfOhG.js +0 -30
|
@@ -1,184 +1,131 @@
|
|
|
1
|
-
# resolve-account-dir.sh —
|
|
1
|
+
# resolve-account-dir.sh — house-account resolver + registry-membership reporter
|
|
2
2
|
# Sourced by setup-account.sh and seed-neo4j.sh. Defines `resolve_and_sweep_account_dir`.
|
|
3
3
|
#
|
|
4
|
+
# Multi-account managed-service model (Task 983): an install may host N accounts
|
|
5
|
+
# under data/accounts/ — exactly one carries role:"house", the rest role:"client".
|
|
6
|
+
# The registry is the set of dirs holding a parseable account.json. EVERY
|
|
7
|
+
# registered account is durable: this resolver never trashes a dir with an
|
|
8
|
+
# account.json. It resolves ACCOUNT_DIR/ACCOUNT_ID to the single role:"house"
|
|
9
|
+
# account (or the sole account in the pre-migration window, before
|
|
10
|
+
# setup-account.sh stamps role:"house").
|
|
11
|
+
#
|
|
12
|
+
# Sweep is LOG-ONLY this sprint. The destructive `mv` to .trash/ was removed to
|
|
13
|
+
# eliminate any chance of deleting a registered account during the multi-account
|
|
14
|
+
# rollout; restoring a guarded destructive sweep is tracked as a follow-up task.
|
|
15
|
+
# Orphan dirs (no account.json) are reported, never moved.
|
|
16
|
+
#
|
|
4
17
|
# Invariant: the TypeScript `resolveAccount()` at platform/ui/app/lib/claude-agent.ts
|
|
5
|
-
# is READ-ONLY. This bash helper is the SOLE
|
|
6
|
-
# the only safe moment to mutate
|
|
7
|
-
# refactor must preserve that asymmetry.
|
|
18
|
+
# is READ-ONLY. This bash helper is the SOLE filesystem-mutation surface for the
|
|
19
|
+
# account layout, because seed-time is the only safe moment to mutate it.
|
|
8
20
|
#
|
|
9
21
|
# Contract (inputs via env vars):
|
|
10
22
|
# ACCOUNTS_DIR — {installDir}/data/accounts
|
|
11
|
-
# USERS_FILE — $HOME/<brand.configDir>/users.json
|
|
23
|
+
# USERS_FILE — $HOME/<brand.configDir>/users.json (read-tolerant; unused for sweep)
|
|
12
24
|
#
|
|
13
25
|
# Contract (outputs via env vars):
|
|
14
|
-
# ACCOUNT_ID — resolved uuid (existing kept, or freshly minted)
|
|
15
|
-
# ACCOUNT_DIR — full path to the live account dir
|
|
26
|
+
# ACCOUNT_ID — resolved house uuid (existing kept, or freshly minted on fresh install)
|
|
27
|
+
# ACCOUNT_DIR — full path to the live house account dir
|
|
16
28
|
#
|
|
17
29
|
# Exit:
|
|
18
|
-
# 0 on success; non-zero on abort (
|
|
30
|
+
# 0 on success; non-zero on abort (registry drift: zero-house with >1 candidate,
|
|
31
|
+
# or multiple houses).
|
|
19
32
|
|
|
20
|
-
# Helper:
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
|
|
24
|
-
# 0 = admins[] contains userId (match)
|
|
25
|
-
# 1 = account.json readable and parsed; userId absent from admins[] (no match)
|
|
26
|
-
# 2 = account.json missing, unreadable, or unparseable (undetermined — caller must abort)
|
|
27
|
-
_account_dir_matches() {
|
|
33
|
+
# Helper: print the `role` field of the account.json at $1, or empty string when
|
|
34
|
+
# absent/unparseable. Trichotomy is unnecessary here — a missing role just means
|
|
35
|
+
# "not a house candidate"; corruption discipline lives in the enumeration step.
|
|
36
|
+
_account_dir_role() {
|
|
28
37
|
local config="$1/account.json"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
python3 - "$config" "$uid" <<'PY'
|
|
38
|
+
[ -f "$config" ] || { echo ""; return 0; }
|
|
39
|
+
python3 - "$config" <<'PY' 2>/dev/null || echo ""
|
|
32
40
|
import json, sys
|
|
33
41
|
try:
|
|
34
42
|
cfg = json.load(open(sys.argv[1]))
|
|
35
43
|
except Exception:
|
|
36
|
-
sys.exit(
|
|
37
|
-
|
|
38
|
-
uid = sys.argv[2]
|
|
39
|
-
for a in admins:
|
|
40
|
-
if isinstance(a, dict) and a.get('userId') == uid:
|
|
41
|
-
sys.exit(0)
|
|
42
|
-
sys.exit(1)
|
|
44
|
+
print(""); sys.exit(0)
|
|
45
|
+
print(cfg.get("role") or "")
|
|
43
46
|
PY
|
|
44
47
|
}
|
|
45
48
|
|
|
46
|
-
#
|
|
47
|
-
#
|
|
49
|
+
# House-account resolver. Enumerate registered candidates (dirs with account.json),
|
|
50
|
+
# classify by role, resolve the house (or sole-unlabelled), report orphans, and
|
|
51
|
+
# emit the registry snapshot. Never mutates the filesystem layout.
|
|
48
52
|
resolve_and_sweep_account_dir() {
|
|
49
53
|
mkdir -p "$ACCOUNTS_DIR"
|
|
50
54
|
|
|
51
55
|
# Enumerate candidates: direct children with account.json, basenames not starting with '.'
|
|
52
|
-
local candidates=()
|
|
56
|
+
local candidates=() orphans=()
|
|
53
57
|
local dir base
|
|
54
58
|
for dir in "$ACCOUNTS_DIR"/*/; do
|
|
55
59
|
[ -d "$dir" ] || continue
|
|
56
60
|
base="$(basename "$dir")"
|
|
57
61
|
case "$base" in .*) continue ;; esac
|
|
58
|
-
[ -f "$dir/account.json" ]
|
|
59
|
-
|
|
62
|
+
if [ -f "$dir/account.json" ]; then
|
|
63
|
+
candidates+=("$base")
|
|
64
|
+
else
|
|
65
|
+
orphans+=("$base")
|
|
66
|
+
fi
|
|
60
67
|
done
|
|
61
68
|
|
|
62
|
-
# Read target userId from users.json (if present and valid)
|
|
63
|
-
local target_user_id=""
|
|
64
|
-
if [ -f "$USERS_FILE" ]; then
|
|
65
|
-
target_user_id=$(python3 - "$USERS_FILE" <<'PY' 2>/dev/null || true
|
|
66
|
-
import json, sys
|
|
67
|
-
try:
|
|
68
|
-
data = json.load(open(sys.argv[1]))
|
|
69
|
-
if isinstance(data, list) and data and isinstance(data[0], dict):
|
|
70
|
-
uid = data[0].get('userId')
|
|
71
|
-
if uid:
|
|
72
|
-
print(uid)
|
|
73
|
-
except Exception:
|
|
74
|
-
pass
|
|
75
|
-
PY
|
|
76
|
-
)
|
|
77
|
-
fi
|
|
78
|
-
|
|
79
69
|
local n=${#candidates[@]}
|
|
80
70
|
|
|
81
71
|
# Case 0: no candidates — fresh install, mint new UUID.
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
# then losing X/account.json (cron stamped X/logs/ first); the next
|
|
86
|
-
# install sees zero candidates and mints Y, orphaning X/logs/. The
|
|
87
|
-
# guard turns that silent regression into an operator-actionable abort.
|
|
72
|
+
# Atomic-mint discipline: refuse to mint if any stub dir (subdir present,
|
|
73
|
+
# account.json missing) exists — a half-provisioned account from a crashed
|
|
74
|
+
# prior install must be operator-repaired, not silently orphaned.
|
|
88
75
|
if [ "$n" -eq 0 ]; then
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
[ -d "$dir" ] || continue
|
|
92
|
-
base="$(basename "$dir")"
|
|
93
|
-
case "$base" in .*) continue ;; esac
|
|
94
|
-
[ -f "$dir/account.json" ] && continue
|
|
95
|
-
stub_dirs+=("$base")
|
|
96
|
-
done
|
|
97
|
-
if [ "${#stub_dirs[@]}" -gt 0 ]; then
|
|
98
|
-
echo "==> [seed] FAIL phase=mint reason=\"stub-account-dirs present (no account.json): ${stub_dirs[*]}\" — refusing to mint a fresh accountId; remove or repair the stub before re-running install" >&2
|
|
76
|
+
if [ "${#orphans[@]}" -gt 0 ]; then
|
|
77
|
+
echo "==> [seed] FAIL phase=mint reason=\"stub-account-dirs present (no account.json): ${orphans[*]}\" — refusing to mint a fresh accountId; remove or repair the stub before re-running install" >&2
|
|
99
78
|
return 1
|
|
100
79
|
fi
|
|
101
80
|
ACCOUNT_ID="$(cat /proc/sys/kernel/random/uuid 2>/dev/null || python3 -c 'import uuid; print(uuid.uuid4())')"
|
|
102
81
|
ACCOUNT_DIR="$ACCOUNTS_DIR/$ACCOUNT_ID"
|
|
82
|
+
echo "==> [seed] op=registry-snapshot houses=0 clients=0"
|
|
103
83
|
return 0
|
|
104
84
|
fi
|
|
105
85
|
|
|
106
|
-
#
|
|
107
|
-
|
|
108
|
-
# accept-with-flag rather than abort because the users.json regeneration on PIN
|
|
109
|
-
# change would otherwise brick legitimate installs).
|
|
110
|
-
if [ "$n" -eq 1 ]; then
|
|
111
|
-
ACCOUNT_ID="${candidates[0]}"
|
|
112
|
-
ACCOUNT_DIR="$ACCOUNTS_DIR/$ACCOUNT_ID"
|
|
113
|
-
if [ -n "$target_user_id" ]; then
|
|
114
|
-
local rc=0
|
|
115
|
-
_account_dir_matches "$ACCOUNT_DIR" "$target_user_id" || rc=$?
|
|
116
|
-
case "$rc" in
|
|
117
|
-
0) echo "==> [seed] identity-match: kept=${ACCOUNT_ID:0:8} via userId=${target_user_id:0:8}" ;;
|
|
118
|
-
1) echo "==> [seed] WARN: single account does not match users.json userId=${target_user_id:0:8} — accepting but flagging" >&2 ;;
|
|
119
|
-
*) echo "==> [seed] identity-match FAILED: sole candidate $ACCOUNT_ID has unreadable or unparseable account.json — aborting" >&2
|
|
120
|
-
return 1 ;;
|
|
121
|
-
esac
|
|
122
|
-
fi
|
|
123
|
-
return 0
|
|
124
|
-
fi
|
|
125
|
-
|
|
126
|
-
# Case 2+: multi-candidate — identity-match-or-abort.
|
|
127
|
-
# First classify everything, THEN decide and act.
|
|
128
|
-
if [ -z "$target_user_id" ]; then
|
|
129
|
-
echo "==> [seed] identity-match FAILED: users.json missing or unreadable, $n candidates — aborting" >&2
|
|
130
|
-
for uuid in "${candidates[@]}"; do echo " candidate: $uuid" >&2; done
|
|
131
|
-
return 1
|
|
132
|
-
fi
|
|
133
|
-
|
|
134
|
-
local matches=()
|
|
135
|
-
local orphans=()
|
|
136
|
-
local rc
|
|
86
|
+
# Classify candidates by role.
|
|
87
|
+
local houses=() clients=() uuid role
|
|
137
88
|
for uuid in "${candidates[@]}"; do
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
1) orphans+=("$uuid") ;;
|
|
143
|
-
*) echo "==> [seed] identity-match FAILED: candidate $uuid has unreadable or unparseable account.json — aborting" >&2
|
|
144
|
-
for u in "${candidates[@]}"; do echo " candidate: $u" >&2; done
|
|
145
|
-
return 1 ;;
|
|
89
|
+
role="$(_account_dir_role "$ACCOUNTS_DIR/$uuid")"
|
|
90
|
+
case "$role" in
|
|
91
|
+
house) houses+=("$uuid") ;;
|
|
92
|
+
*) clients+=("$uuid") ;; # client OR unlabelled (legacy)
|
|
146
93
|
esac
|
|
147
94
|
done
|
|
148
95
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
for uuid in "${candidates[@]}"; do echo " candidate: $uuid" >&2; done
|
|
152
|
-
return 1
|
|
153
|
-
fi
|
|
96
|
+
# Pre-action registry snapshot — the count the post-seed census must match.
|
|
97
|
+
echo "==> [seed] op=registry-snapshot houses=${#houses[@]} clients=${#clients[@]}"
|
|
154
98
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
99
|
+
# Report orphans (dirs with no account.json). Log-only — never moved this sprint.
|
|
100
|
+
# Guard the empty-array expansion: under `set -u` (setup-account.sh uses
|
|
101
|
+
# `set -euo pipefail`), bash 3.2 treats "${orphans[@]}" on an empty array as an
|
|
102
|
+
# unbound variable and aborts.
|
|
103
|
+
local ts; ts=$(date -u +%Y%m%dT%H%M%SZ 2>/dev/null || echo unknown)
|
|
104
|
+
if [ "${#orphans[@]}" -gt 0 ]; then
|
|
105
|
+
for uuid in "${orphans[@]}"; do
|
|
106
|
+
echo "==> [seed] op=sweep uuid=${uuid:0:8} registered=false action=skipped-guarded ts=$ts"
|
|
107
|
+
done
|
|
159
108
|
fi
|
|
160
109
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
110
|
+
# Resolve the house.
|
|
111
|
+
if [ "${#houses[@]}" -eq 1 ]; then
|
|
112
|
+
ACCOUNT_ID="${houses[0]}"
|
|
113
|
+
ACCOUNT_DIR="$ACCOUNTS_DIR/$ACCOUNT_ID"
|
|
114
|
+
echo "==> [seed] house-resolved: ${ACCOUNT_ID:0:8}"
|
|
115
|
+
return 0
|
|
116
|
+
fi
|
|
164
117
|
|
|
165
|
-
#
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if ! mv "$ACCOUNTS_DIR/$uuid" "$dest"; then
|
|
173
|
-
echo "==> [seed] ERROR: failed to move $uuid → $dest — aborting" >&2
|
|
174
|
-
return 1
|
|
175
|
-
fi
|
|
176
|
-
echo "==> [seed] swept orphan: ${uuid:0:8} → .trash/${uuid:0:8}-${ts}"
|
|
177
|
-
moved=$((moved + 1))
|
|
178
|
-
done
|
|
179
|
-
if [ "$moved" -gt 0 ]; then
|
|
180
|
-
echo "==> [seed] orphan sweep: moved $moved → $ACCOUNTS_DIR/.trash/"
|
|
118
|
+
# Pre-migration tolerance: zero labelled house but exactly one account → it is
|
|
119
|
+
# the house (setup-account.sh stamps role:"house" on it).
|
|
120
|
+
if [ "${#houses[@]}" -eq 0 ] && [ "$n" -eq 1 ]; then
|
|
121
|
+
ACCOUNT_ID="${candidates[0]}"
|
|
122
|
+
ACCOUNT_DIR="$ACCOUNTS_DIR/$ACCOUNT_ID"
|
|
123
|
+
echo "==> [seed] house-resolved: ${ACCOUNT_ID:0:8} (sole account, pre-migration)"
|
|
124
|
+
return 0
|
|
181
125
|
fi
|
|
182
126
|
|
|
183
|
-
|
|
127
|
+
# Genuine drift — loud-fail.
|
|
128
|
+
echo "==> [seed] FAIL phase=resolve-house reason=\"houses=${#houses[@]} total=$n — expected exactly one role:house (or a single unlabelled account)\" — aborting" >&2
|
|
129
|
+
for uuid in "${candidates[@]}"; do echo " candidate: $uuid role=$(_account_dir_role "$ACCOUNTS_DIR/$uuid")" >&2; done
|
|
130
|
+
return 1
|
|
184
131
|
}
|