@rubytech/create-maxy-code 0.1.275 → 0.1.277
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/plugins/admin/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +1 -4
- package/payload/platform/plugins/admin/mcp/dist/index.js +0 -8
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +3 -3
- package/payload/platform/plugins/docs/references/admin-identity-gate.md +77 -81
- package/payload/platform/plugins/docs/references/admin-ui.md +2 -2
- package/payload/platform/scripts/check-no-esm-require.mjs +3 -0
- package/payload/platform/scripts/setup-account.sh +0 -5
- 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 +0 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +5 -0
- 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 +52 -10
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +8 -17
- 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 +4 -5
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.d.ts +8 -0
- package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.js +13 -0
- package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/wa-channel-store.d.ts +29 -0
- package/payload/platform/services/claude-session-manager/dist/wa-channel-store.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/wa-channel-store.js +124 -0
- package/payload/platform/services/claude-session-manager/dist/wa-channel-store.js.map +1 -0
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +23 -0
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js +26 -0
- package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/server.js +41 -14
- package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/index.js +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/index.js.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.d.ts +2 -0
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.d.ts.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.js +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.js.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/src/index.ts +1 -1
- package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-distil-profile.ts +3 -1
- package/payload/server/{chunk-W4EM7RK4.js → chunk-QHD5TKLQ.js} +2 -0
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/server.js +551 -405
- package/payload/platform/plugins/admin/hooks/__tests__/pin-identity-gate.test.sh +0 -96
- package/payload/platform/plugins/admin/hooks/pin-identity-gate.sh +0 -146
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Regression test for pin-identity-gate.sh (Task 619).
|
|
3
|
-
#
|
|
4
|
-
# Covers:
|
|
5
|
-
# 1. Non-admin role → ALLOW (no-op)
|
|
6
|
-
# 2. admin, unauthenticated, ordinary tool → BLOCK (op=pin-prompted)
|
|
7
|
-
# 3. admin, already authenticated (state file) → ALLOW
|
|
8
|
-
# 4. admin, auth tool, endpoint match → ALLOW + state written (op=pin-bound)
|
|
9
|
-
# 5. admin, auth tool, endpoint miss → BLOCK (op=session-terminated)
|
|
10
|
-
# 6. admin, auth tool, endpoint unavailable → BLOCK (op=pin-unavailable)
|
|
11
|
-
# 7. admin, auth tool, endpoint unreachable → BLOCK (op=pin-error)
|
|
12
|
-
#
|
|
13
|
-
# The validate endpoint is stubbed via a `curl` shim on PATH whose response is
|
|
14
|
-
# driven by $FAKE_VALIDATE_KIND.
|
|
15
|
-
|
|
16
|
-
set -u
|
|
17
|
-
HOOK="$(cd "$(dirname "$0")/.." && pwd)/pin-identity-gate.sh"
|
|
18
|
-
[ -x "$HOOK" ] || { echo "FAIL: $HOOK not executable" >&2; exit 1; }
|
|
19
|
-
|
|
20
|
-
TMP_DIR=$(mktemp -d)
|
|
21
|
-
trap 'rm -rf "$TMP_DIR"' EXIT
|
|
22
|
-
mkdir -p "$TMP_DIR/bin" "$TMP_DIR/state"
|
|
23
|
-
|
|
24
|
-
# curl shim: emit a canned validate response based on $FAKE_VALIDATE_KIND.
|
|
25
|
-
cat > "$TMP_DIR/bin/curl" <<'SHIM'
|
|
26
|
-
#!/usr/bin/env bash
|
|
27
|
-
case "${FAKE_VALIDATE_KIND:-}" in
|
|
28
|
-
match) echo '{"kind":"match","userId":"user-0001"}' ;;
|
|
29
|
-
miss) echo '{"kind":"miss"}' ;;
|
|
30
|
-
unavailable) echo '{"kind":"unavailable"}' ;;
|
|
31
|
-
corrupt) echo '{"kind":"corrupt"}' ;;
|
|
32
|
-
unreachable) echo '' ;;
|
|
33
|
-
*) echo '' ;;
|
|
34
|
-
esac
|
|
35
|
-
SHIM
|
|
36
|
-
chmod +x "$TMP_DIR/bin/curl"
|
|
37
|
-
|
|
38
|
-
AUTH_TOOL='mcp__plugin_admin_admin__admin-identity-authenticate'
|
|
39
|
-
PASS=0; FAIL=0
|
|
40
|
-
|
|
41
|
-
# run <role> <kind> <stdin-json> [specialist] ; sets EXIT and ERR
|
|
42
|
-
run() {
|
|
43
|
-
ERR=$(printf '%s' "$3" | \
|
|
44
|
-
PATH="$TMP_DIR/bin:$PATH" \
|
|
45
|
-
MAXY_SESSION_ROLE="$1" \
|
|
46
|
-
MAXY_SPECIALIST="${4:-}" \
|
|
47
|
-
FAKE_VALIDATE_KIND="$2" \
|
|
48
|
-
MAXY_IDENTITY_GATE_STATE_DIR="$TMP_DIR/state" \
|
|
49
|
-
MAXY_IDENTITY_VALIDATE_URL="http://stub/validate" \
|
|
50
|
-
bash "$HOOK" 2>&1 >/dev/null)
|
|
51
|
-
EXIT=$?
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
check() { # <label> <want-exit> <grep-or-->
|
|
55
|
-
if [ "$EXIT" != "$2" ]; then echo "FAIL[$1]: exit=$EXIT want=$2 err=$ERR"; FAIL=$((FAIL+1)); return; fi
|
|
56
|
-
if [ "$3" != "-" ] && ! printf '%s' "$ERR" | grep -q "$3"; then echo "FAIL[$1]: missing '$3' in: $ERR"; FAIL=$((FAIL+1)); return; fi
|
|
57
|
-
echo "PASS[$1]"; PASS=$((PASS+1))
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
# 1. non-admin → allow
|
|
61
|
-
run public '' '{"session_id":"s1","tool_name":"Bash","tool_input":{}}'
|
|
62
|
-
check non-admin 0 -
|
|
63
|
-
|
|
64
|
-
# 1b. admin but specialist subagent (MAXY_SPECIALIST set) → allow (no-op)
|
|
65
|
-
run admin '' '{"session_id":"s1b","tool_name":"Bash","tool_input":{}}' database-operator
|
|
66
|
-
check specialist-exempt 0 -
|
|
67
|
-
|
|
68
|
-
# 2. admin unauth, ordinary tool → block
|
|
69
|
-
run admin '' '{"session_id":"s2","tool_name":"Bash","tool_input":{}}'
|
|
70
|
-
check unauth-block 2 "op=pin-prompted"
|
|
71
|
-
|
|
72
|
-
# 3. admin, authenticated (state file present) → allow
|
|
73
|
-
echo '{"userId":"user-0001"}' > "$TMP_DIR/state/s3.json"
|
|
74
|
-
run admin '' '{"session_id":"s3","tool_name":"Bash","tool_input":{}}'
|
|
75
|
-
check authed-allow 0 -
|
|
76
|
-
|
|
77
|
-
# 4. admin, auth tool, match → allow + state written + pin-bound
|
|
78
|
-
run admin match "{\"session_id\":\"s4\",\"tool_name\":\"$AUTH_TOOL\",\"tool_input\":{\"pin\":\"1234\"}}"
|
|
79
|
-
check match-allow 0 "op=pin-bound"
|
|
80
|
-
[ -f "$TMP_DIR/state/s4.json" ] && { echo "PASS[match-state-written]"; PASS=$((PASS+1)); } || { echo "FAIL[match-state-written]"; FAIL=$((FAIL+1)); }
|
|
81
|
-
|
|
82
|
-
# 5. admin, auth tool, miss → block + terminate
|
|
83
|
-
run admin miss "{\"session_id\":\"s5\",\"tool_name\":\"$AUTH_TOOL\",\"tool_input\":{\"pin\":\"9999\"}}"
|
|
84
|
-
check miss-block 2 "op=session-terminated"
|
|
85
|
-
|
|
86
|
-
# 6. admin, auth tool, unavailable → block
|
|
87
|
-
run admin unavailable "{\"session_id\":\"s6\",\"tool_name\":\"$AUTH_TOOL\",\"tool_input\":{\"pin\":\"1\"}}"
|
|
88
|
-
check unavailable-block 2 "op=pin-unavailable"
|
|
89
|
-
|
|
90
|
-
# 7. admin, auth tool, unreachable endpoint → block (fail-closed)
|
|
91
|
-
run admin unreachable "{\"session_id\":\"s7\",\"tool_name\":\"$AUTH_TOOL\",\"tool_input\":{\"pin\":\"1\"}}"
|
|
92
|
-
check unreachable-block 2 "op=pin-error"
|
|
93
|
-
|
|
94
|
-
echo "---"
|
|
95
|
-
echo "PASS=$PASS FAIL=$FAIL"
|
|
96
|
-
[ "$FAIL" = 0 ] || exit 1
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Native-CC admin PIN identity gate (Task 619).
|
|
3
|
-
#
|
|
4
|
-
# PreToolUse hook, registered under the universal (no-matcher) entry so it fires
|
|
5
|
-
# for EVERY tool call on a native-CC admin session. It denies all tools until the
|
|
6
|
-
# operator authenticates: the agent must call `admin-identity-authenticate` with a
|
|
7
|
-
# PIN that the loopback validate endpoint matches against users.json. On match the
|
|
8
|
-
# hook records per-session auth state (keyed by the conversation `session_id` it
|
|
9
|
-
# reads from stdin) and lets every subsequent tool through. Enforcement is here —
|
|
10
|
-
# a model that skips the prompt cannot reach any other tool.
|
|
11
|
-
#
|
|
12
|
-
# Scope: only native loopback admin sessions (MAXY_SESSION_ROLE=admin). Specialist
|
|
13
|
-
# subagents dispatched via the Task tool share the parent conversation's
|
|
14
|
-
# session_id, so they pass once the operator session is authenticated.
|
|
15
|
-
#
|
|
16
|
-
# Protocol: exit 0 = allow, exit 2 = block (stderr message shown to the agent),
|
|
17
|
-
# matching the sibling gate hooks. Fail-closed on terminal stdin.
|
|
18
|
-
#
|
|
19
|
-
# Lifecycle (one [admin-identity] line per step, correlated by sessionId):
|
|
20
|
-
# op=loopback-spawn-received → op=pin-prompted → (op=pin-bound source=pin |
|
|
21
|
-
# op=pin-miss → op=session-terminated) ; the MCP tool emits op=about-owner-loaded.
|
|
22
|
-
|
|
23
|
-
set -uo pipefail
|
|
24
|
-
|
|
25
|
-
# Task 681 — PIN identity gate SUSPENDED. The hard PreToolUse PIN block is
|
|
26
|
-
# removed pending a new multi-admin authentication design. The block made every
|
|
27
|
-
# tool (including the WhatsApp channel reply tool) unreachable until a PIN was
|
|
28
|
-
# entered, which is impossible on non-interactive surfaces like the WhatsApp
|
|
29
|
-
# channel (Task 677). This hook now allows every tool. The original gating logic
|
|
30
|
-
# is retained below the early exit for reference and quick revert; the
|
|
31
|
-
# replacement auth (channel-bindings + per-admin identity) is Task 681.
|
|
32
|
-
# Silent exit (no per-tool-call log line) — this fires on every tool call.
|
|
33
|
-
exit 0
|
|
34
|
-
|
|
35
|
-
if [ -t 0 ]; then
|
|
36
|
-
echo "Blocked: pin-identity-gate received no stdin (cannot inspect tool call). Failing closed." >&2
|
|
37
|
-
exit 2
|
|
38
|
-
fi
|
|
39
|
-
INPUT=$(cat)
|
|
40
|
-
|
|
41
|
-
# Only native loopback admin OPERATOR sessions are in scope:
|
|
42
|
-
# - MAXY_SESSION_ROLE=admin excludes public/access sessions.
|
|
43
|
-
# - MAXY_SPECIALIST empty excludes pty-spawned specialist/recorder sessions,
|
|
44
|
-
# which carry role=admin but are not human operators and never enter a PIN
|
|
45
|
-
# (mirrors the recursion guard the other admin hooks use). Task-tool
|
|
46
|
-
# specialist subagents share the operator's session_id + empty MAXY_SPECIALIST,
|
|
47
|
-
# so they pass via the operator's auth-state file once it is bound.
|
|
48
|
-
[ "${MAXY_SESSION_ROLE:-}" = "admin" ] || exit 0
|
|
49
|
-
[ -z "${MAXY_SPECIALIST:-}" ] || exit 0
|
|
50
|
-
|
|
51
|
-
# ----- Parse fields from stdin (python3, robust on nested tool_input) -------
|
|
52
|
-
SESSION_ID=$(printf '%s' "$INPUT" | python3 -c 'import json,sys
|
|
53
|
-
try: d=json.load(sys.stdin)
|
|
54
|
-
except Exception: d={}
|
|
55
|
-
print(d.get("session_id","") or "")' 2>/dev/null)
|
|
56
|
-
TOOL_NAME=$(printf '%s' "$INPUT" | python3 -c 'import json,sys
|
|
57
|
-
try: d=json.load(sys.stdin)
|
|
58
|
-
except Exception: d={}
|
|
59
|
-
print(d.get("tool_name","") or "")' 2>/dev/null)
|
|
60
|
-
|
|
61
|
-
SID8="${SESSION_ID:0:8}"; [ -z "$SID8" ] && SID8='-'
|
|
62
|
-
log() { echo "[admin-identity] $1" >&2; }
|
|
63
|
-
|
|
64
|
-
# ----- Resolve account/state dir -------------------------------------------
|
|
65
|
-
# The account dir basename IS the ACCOUNT_ID (resolve-account-dir.sh), and the
|
|
66
|
-
# rc child env carries ACCOUNT_ID, so resolve deterministically rather than
|
|
67
|
-
# `find | head -1` — which does not skip dotfiles and could pick the sibling
|
|
68
|
-
# `data/accounts/.trash/`, diverging from the manager's `spawnCwd` (= the
|
|
69
|
-
# account dir) and stranding state the standing audit can never reconcile.
|
|
70
|
-
HOOK_DIR="$(cd "$(dirname "$0")" 2>/dev/null && pwd)"
|
|
71
|
-
PLATFORM_ROOT_RESOLVED="${HOOK_DIR}/../../.."
|
|
72
|
-
ACCOUNTS_DIR="${PLATFORM_ROOT_RESOLVED}/../data/accounts"
|
|
73
|
-
ACCOUNT_DIR=""
|
|
74
|
-
if [ -n "${ACCOUNT_ID:-}" ]; then
|
|
75
|
-
ACCOUNT_DIR="${ACCOUNTS_DIR}/${ACCOUNT_ID}"
|
|
76
|
-
elif [ -d "$ACCOUNTS_DIR" ]; then
|
|
77
|
-
# Defensive fallback only when ACCOUNT_ID is unset — exclude dot-entries.
|
|
78
|
-
ACCOUNT_DIR=$(find "$ACCOUNTS_DIR" -mindepth 1 -maxdepth 1 -type d ! -name '.*' 2>/dev/null | head -1)
|
|
79
|
-
fi
|
|
80
|
-
STATE_DIR="${MAXY_IDENTITY_GATE_STATE_DIR:-${ACCOUNT_DIR}/state/admin-identity}"
|
|
81
|
-
STATE_FILE="${STATE_DIR}/${SESSION_ID}.json"
|
|
82
|
-
|
|
83
|
-
AUTH_TOOL='mcp__plugin_admin_admin__admin-identity-authenticate'
|
|
84
|
-
VALIDATE_URL="${MAXY_IDENTITY_VALIDATE_URL:-http://127.0.0.1:${MAXY_UI_INTERNAL_PORT:-0}/api/admin/identity/validate}"
|
|
85
|
-
|
|
86
|
-
# Already authenticated for this conversation → pass everything through.
|
|
87
|
-
if [ -n "$SESSION_ID" ] && [ -f "$STATE_FILE" ]; then
|
|
88
|
-
exit 0
|
|
89
|
-
fi
|
|
90
|
-
|
|
91
|
-
log "op=loopback-spawn-received sessionId=${SID8}"
|
|
92
|
-
|
|
93
|
-
# ----- The authenticate tool: validate, bind on match, terminate on miss ----
|
|
94
|
-
if [ "$TOOL_NAME" = "$AUTH_TOOL" ]; then
|
|
95
|
-
PIN=$(printf '%s' "$INPUT" | python3 -c 'import json,sys
|
|
96
|
-
try: d=json.load(sys.stdin)
|
|
97
|
-
except Exception: d={}
|
|
98
|
-
ti=d.get("tool_input") or {}
|
|
99
|
-
print(ti.get("pin","") or "")' 2>/dev/null)
|
|
100
|
-
|
|
101
|
-
REQ=$(python3 -c 'import json,sys
|
|
102
|
-
print(json.dumps({"pin": sys.argv[1], "sessionId": sys.argv[2]}))' "$PIN" "$SESSION_ID" 2>/dev/null)
|
|
103
|
-
RESP=$(printf '%s' "$REQ" | curl -s --max-time 5 -X POST -H 'content-type: application/json' -d @- "$VALIDATE_URL" 2>/dev/null)
|
|
104
|
-
KIND=$(printf '%s' "$RESP" | python3 -c 'import json,sys
|
|
105
|
-
try: print((json.load(sys.stdin) or {}).get("kind","") or "")
|
|
106
|
-
except Exception: print("")' 2>/dev/null)
|
|
107
|
-
|
|
108
|
-
case "$KIND" in
|
|
109
|
-
match)
|
|
110
|
-
USERID=$(printf '%s' "$RESP" | python3 -c 'import json,sys
|
|
111
|
-
print(json.load(sys.stdin).get("userId","") or "")' 2>/dev/null)
|
|
112
|
-
mkdir -p "$STATE_DIR" 2>/dev/null
|
|
113
|
-
printf '{"userId":%s,"ts":"%s"}' \
|
|
114
|
-
"$(python3 -c 'import json,sys;print(json.dumps(sys.argv[1]))' "$USERID")" \
|
|
115
|
-
"$(date -u +%FT%TZ)" > "$STATE_FILE" 2>/dev/null
|
|
116
|
-
log "op=pin-bound sessionId=${SID8} userId=${USERID:0:8} source=pin authSurface=loopback"
|
|
117
|
-
exit 0
|
|
118
|
-
;;
|
|
119
|
-
miss)
|
|
120
|
-
log "op=pin-miss sessionId=${SID8} reason=no-matching-user"
|
|
121
|
-
log "op=session-terminated sessionId=${SID8} reason=pin-auth-failed"
|
|
122
|
-
echo "PIN did not match. This session is being terminated. Start a new session and enter a valid PIN." >&2
|
|
123
|
-
exit 2
|
|
124
|
-
;;
|
|
125
|
-
unavailable)
|
|
126
|
-
log "op=pin-unavailable sessionId=${SID8} reason=users-json-empty"
|
|
127
|
-
echo "No admin PIN is configured for this install. Complete onboarding before using the admin agent." >&2
|
|
128
|
-
exit 2
|
|
129
|
-
;;
|
|
130
|
-
corrupt)
|
|
131
|
-
log "op=pin-error sessionId=${SID8} reason=users-json-corrupt"
|
|
132
|
-
echo "Admin user configuration is corrupt. Re-run the seed script before authenticating." >&2
|
|
133
|
-
exit 2
|
|
134
|
-
;;
|
|
135
|
-
*)
|
|
136
|
-
log "op=pin-error sessionId=${SID8} reason=validate-unreachable"
|
|
137
|
-
echo "Identity validation is unavailable; cannot proceed without authentication." >&2
|
|
138
|
-
exit 2
|
|
139
|
-
;;
|
|
140
|
-
esac
|
|
141
|
-
fi
|
|
142
|
-
|
|
143
|
-
# ----- Unauthenticated and not the auth tool → block -----------------------
|
|
144
|
-
log "op=pin-prompted sessionId=${SID8}"
|
|
145
|
-
echo "Authenticate first: call admin-identity-authenticate with the operator's PIN. No other tool is reachable until a matching PIN is bound for this session." >&2
|
|
146
|
-
exit 2
|