@rubytech/create-maxy-code 0.1.219 → 0.1.222
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 +46 -1
- package/package.json +1 -1
- package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.js +60 -23
- package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.js.map +1 -1
- package/payload/platform/lib/graph-write/dist/index.d.ts +4 -1
- package/payload/platform/lib/graph-write/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/graph-write/dist/index.js +17 -5
- package/payload/platform/lib/graph-write/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-write/src/__tests__/action-provenance-gate.test.ts +58 -31
- package/payload/platform/lib/graph-write/src/index.ts +16 -7
- package/payload/platform/plugins/admin/PLUGIN.md +2 -3
- package/payload/platform/plugins/admin/__tests__/admin-can-enumerate.test.sh +129 -0
- package/payload/platform/plugins/admin/hooks/archive-ingest-surface-gate.sh +1 -2
- package/payload/platform/plugins/admin/hooks/lib/hook-emit.sh +3 -2
- package/payload/platform/plugins/admin/mcp/dist/index.js +41 -9
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/references/publish-site-routing.md +44 -0
- package/payload/platform/plugins/admin/skills/admin-user-management/SKILL.md +1 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +11 -4
- package/payload/platform/plugins/admin/skills/plugin-management/SKILL.md +2 -2
- package/payload/platform/plugins/contacts/PLUGIN.md +2 -2
- package/payload/platform/plugins/docs/references/internals.md +1 -1
- package/payload/platform/plugins/docs/references/platform.md +2 -2
- package/payload/platform/plugins/docs/references/troubleshooting.md +7 -0
- package/payload/platform/plugins/memory/PLUGIN.md +1 -1
- package/payload/platform/plugins/memory/references/graph-primitives.md +2 -2
- package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.d.ts +2 -1
- package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.d.ts.map +1 -1
- package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.js +27 -21
- package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.js.map +1 -1
- package/payload/platform/scripts/check-no-esm-require.mjs +3 -0
- package/payload/platform/scripts/setup-account.sh +0 -15
- package/payload/platform/services/claude-session-manager/dist/auth-snapshot.d.ts +4 -0
- package/payload/platform/services/claude-session-manager/dist/auth-snapshot.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/auth-snapshot.js +50 -0
- package/payload/platform/services/claude-session-manager/dist/auth-snapshot.js.map +1 -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 +19 -2
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +39 -19
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +24 -0
- 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 +100 -11
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.d.ts +8 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.js +7 -2
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.js.map +1 -1
- package/payload/server/public/assets/{AdminShell-BcxEZnpu.js → AdminShell-BiEwDSRL.js} +1 -1
- package/payload/server/public/assets/{Checkbox-DL-HdT29.js → Checkbox-COiFXiXL.js} +1 -1
- package/payload/server/public/assets/{admin-DMo5DWKH.js → admin-Ca9ckLZx.js} +1 -1
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-BoUw4oYz.js → architectureDiagram-Q4EWVU46-DI6JZI13.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DOscnO3m.js → blockDiagram-DXYQGD6D-dgDvswLd.js} +1 -1
- package/payload/server/public/assets/{brand-SZW-27T7.css → brand-CAMMU5lz.css} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-aZ1IuZ_F.js → c4Diagram-AHTNJAMY-odaGY4GZ.js} +1 -1
- package/payload/server/public/assets/channel-DfwLbKck.js +1 -0
- package/payload/server/public/assets/{chunk-336JU56O-DS3ksXBG.js → chunk-336JU56O-BpbY8F27.js} +2 -2
- package/payload/server/public/assets/{chunk-426QAEUC-BLRn2STO.js → chunk-426QAEUC-BWbVhEVC.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-BrhOvJ01.js → chunk-4TB4RGXK-C3IfRdvA.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-BZZwZX5Q.js → chunk-5FUZZQ4R-CSRMBAGr.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-YXZKnPCz.js → chunk-5PVQY5BW-CGAe6GJJ.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-DAMCJHKQ.js → chunk-EDXVE4YY-BnXC8cYQ.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-DsD95Bqn.js → chunk-ENJZ2VHE-7qfDalAB.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-DxtrRClx.js → chunk-ICPOFSXX-TRvVGIDw.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-CN4kLK-H.js → chunk-OYMX7WX6-Cfv8vBvI.js} +1 -1
- package/payload/server/public/assets/{chunk-U2HBQHQK-BPTv3Oj1.js → chunk-U2HBQHQK-BfLvbEyu.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-DxBry33v.js → chunk-X2U36JSP-Cj3k-dYC.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-BZ4N75oy.js → chunk-YZCP3GAM-CygW6I0h.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-Dqr161Q1.js → chunk-ZZ45TVLE-CBF3hFJH.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-CE0XZQre.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-Bj41Y3XD.js +1 -0
- package/payload/server/public/assets/clone-DTd5nONj.js +1 -0
- package/payload/server/public/assets/{dagre-DtZ0wKkH.js → dagre-BTGABQJX.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-BPKhT-ZX.js → dagre-KV5264BT-B2lbkuGd.js} +1 -1
- package/payload/server/public/assets/{data-D6IQdm0R.js → data-CHdaTjgn.js} +1 -1
- package/payload/server/public/assets/{diagram-5BDNPKRD-CATnafi7.js → diagram-5BDNPKRD-BUK4LqT8.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-ChZYQfji.js → diagram-G4DWMVQ6-e49HrvxL.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-DHW6kYd3.js → diagram-MMDJMWI5-k4Kx_qWe.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-CnS4Zci8.js → diagram-TYMM5635-DzavOUdK.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-DKYv2YWp.js → erDiagram-SMLLAGMA-CJKecRhi.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-BWvoZWlh.js → flowDiagram-DWJPFMVM-GM7H1TDt.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-CpCb-xKy.js → ganttDiagram-T4ZO3ILL-kDEA1A-3.js} +1 -1
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-CvHrDKQ-.js → gitGraphDiagram-UUTBAWPF-jVZZdeg2.js} +1 -1
- package/payload/server/public/assets/{graph-labels-CWJy0O4w.js → graph-labels-CavkO4DG.js} +1 -1
- package/payload/server/public/assets/{graph-PkZKVkWD.js → graph-tqCqSngu.js} +1 -1
- package/payload/server/public/assets/{graphlib-DjnyHqGy.js → graphlib-DFU2rJiY.js} +1 -1
- package/payload/server/public/assets/{infoDiagram-42DDH7IO-D_MywcVn.js → infoDiagram-42DDH7IO-CFxVoRBy.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-N9m-f-Eb.js → ishikawaDiagram-UXIWVN3A-CDvZs3Ua.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-DE0q7uSM.js → journeyDiagram-VCZTEJTY-DUI1m9vW.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-Dj5hb9Bq.js → kanban-definition-6JOO6SKY-C_jSVK7W.js} +1 -1
- package/payload/server/public/assets/{line-C6ph0i4M.js → line-DfwJeo6J.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-BrfmEvCA.js → mermaid-parser.core-BN-2kBfU.js} +1 -1
- package/payload/server/public/assets/{mermaid.core-DYnHKfDv.js → mermaid.core-C6amhHAQ.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-DaSaZfhR.js → mindmap-definition-QFDTVHPH-eTKDlw3c.js} +1 -1
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-BAu9Ezbv.js → pieDiagram-DEJITSTG-DNX5VeMZ.js} +1 -1
- package/payload/server/public/assets/{public-UKgkJxKv.js → public-BADBLzOZ.js} +3 -3
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-DRsbL1Xd.js → quadrantDiagram-34T5L4WZ-BFnmYiHX.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-B9QcsXV6.js → requirementDiagram-MS252O5E-DvHvTyzu.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-DsZbvIlD.js → sankeyDiagram-XADWPNL6-CMFnNT1G.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-BlT4O2N8.js → sequenceDiagram-FGHM5R23-BYon1ouU.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-JFgk1K3Y.js → stateDiagram-FHFEXIEX-n6l3hcuJ.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CS46-Mhi.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-DOsHw1ip.js → timeline-definition-GMOUNBTQ-DFPFHrQF.js} +1 -1
- package/payload/server/public/assets/{useSelectionMode-JDGvwvIk.js → useSelectionMode-iqIyL24g.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-CQWIhqZY.js → vennDiagram-DHZGUBPP-DZLturYa.js} +1 -1
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-D5Fh7YVL.js → wardleyDiagram-NUSXRM2D-BBt2pdjM.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-C-tINQEs.js → xychartDiagram-5P7HB3ND-DOZxLvEi.js} +1 -1
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +6 -6
- package/payload/server/public/index.html +6 -6
- package/payload/server/public/public.html +5 -5
- package/payload/server/server.js +49 -6
- package/payload/platform/plugins/admin/hooks/__tests__/pre-tool-use-admin-tool-gate.test.sh +0 -109
- package/payload/platform/plugins/admin/hooks/__tests__/pre-tool-use-base64-guard.test.sh +0 -204
- package/payload/platform/plugins/admin/hooks/__tests__/pre-tool-use-memory-write-passthrough.test.sh +0 -118
- package/payload/platform/plugins/admin/hooks/pre-tool-use.sh +0 -337
- package/payload/server/public/assets/channel-CzcSNxDm.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-DFOM3vCn.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-HplDfaL1.js +0 -1
- package/payload/server/public/assets/clone-G-2rqnSR.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-NXz27DaV.js +0 -1
- /package/payload/server/public/assets/{brand-SzZmKKjz.js → brand-DfykKss4.js} +0 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# admin-can-enumerate.test.sh
|
|
3
|
+
#
|
|
4
|
+
# Acceptance gate for Task 579. Verifies that a fresh admin session
|
|
5
|
+
# locates a file under <accountDir>/sites/ on the FIRST enumeration
|
|
6
|
+
# attempt — no slug guessing, no `EISDIR`, no false-empty 200s, no
|
|
7
|
+
# "Log directory does not exist" against a path that resolves
|
|
8
|
+
# elsewhere. The gate runs from the installer post-install step against
|
|
9
|
+
# the freshly-deployed payload, before systemd services are restarted
|
|
10
|
+
# into it. A non-zero exit aborts the deploy and the old payload keeps
|
|
11
|
+
# running.
|
|
12
|
+
#
|
|
13
|
+
# Required environment:
|
|
14
|
+
# CLAUDE_CONFIG_DIR per-brand .claude directory (e.g. ~/.realagent-code/.claude)
|
|
15
|
+
# INSTALL_DIR the brand install root (e.g. ~/realagent-code)
|
|
16
|
+
#
|
|
17
|
+
# Exit codes:
|
|
18
|
+
# 0 pass — admin enumerated and emitted the seeded path within budget
|
|
19
|
+
# 1 fail — one or more assertions tripped (see stderr for the line)
|
|
20
|
+
# 2 setup error — could not seed test account or could not invoke claude
|
|
21
|
+
|
|
22
|
+
set -euo pipefail
|
|
23
|
+
|
|
24
|
+
CONFIG_DIR="${CLAUDE_CONFIG_DIR:?CLAUDE_CONFIG_DIR not set}"
|
|
25
|
+
INSTALL_DIR="${INSTALL_DIR:?INSTALL_DIR not set}"
|
|
26
|
+
|
|
27
|
+
if ! command -v claude >/dev/null 2>&1; then
|
|
28
|
+
echo "[admin-enumerate-gate] setup-error reason=claude-not-on-path" >&2
|
|
29
|
+
exit 2
|
|
30
|
+
fi
|
|
31
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
32
|
+
echo "[admin-enumerate-gate] setup-error reason=jq-not-on-path" >&2
|
|
33
|
+
exit 2
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
ACCOUNTS_DIR="$INSTALL_DIR/data/accounts"
|
|
37
|
+
TEST_ACCT_ID="enumerate-gate-$$"
|
|
38
|
+
TEST_ACCT_DIR="$ACCOUNTS_DIR/$TEST_ACCT_ID"
|
|
39
|
+
JSONL_OUT=$(mktemp)
|
|
40
|
+
EXIT=0
|
|
41
|
+
|
|
42
|
+
cleanup() {
|
|
43
|
+
rm -rf "$TEST_ACCT_DIR"
|
|
44
|
+
if [ "$EXIT" -eq 0 ]; then
|
|
45
|
+
rm -f "$JSONL_OUT"
|
|
46
|
+
else
|
|
47
|
+
echo "[admin-enumerate-gate] evidence-jsonl=$JSONL_OUT" >&2
|
|
48
|
+
fi
|
|
49
|
+
}
|
|
50
|
+
trap cleanup EXIT
|
|
51
|
+
|
|
52
|
+
# Seed: one target site + 5 decoys. Target index.html is the file the
|
|
53
|
+
# agent must locate and emit the absolute path for.
|
|
54
|
+
mkdir -p "$TEST_ACCT_DIR/sites/exp-uk-got-talent"
|
|
55
|
+
echo "<html><body>eXp Has Got Talent</body></html>" > "$TEST_ACCT_DIR/sites/exp-uk-got-talent/index.html"
|
|
56
|
+
for decoy in alpha-corp-careers beta-properties gamma-events delta-news epsilon-portal; do
|
|
57
|
+
mkdir -p "$TEST_ACCT_DIR/sites/$decoy"
|
|
58
|
+
echo "<html>decoy</html>" > "$TEST_ACCT_DIR/sites/$decoy/index.html"
|
|
59
|
+
done
|
|
60
|
+
|
|
61
|
+
TARGET_PATH="$TEST_ACCT_DIR/sites/exp-uk-got-talent/index.html"
|
|
62
|
+
|
|
63
|
+
PROMPT="find the eXp Has Got Talent site in this account and print the absolute path to its index.html"
|
|
64
|
+
|
|
65
|
+
# Spawn claude headless against the test account. ACCOUNT_ID + the
|
|
66
|
+
# MAXY_SESSION_ROLE/PLATFORM_ROOT env are what the platform MCPs read
|
|
67
|
+
# to scope themselves; PLATFORM_ROOT resolves the on-disk payload that
|
|
68
|
+
# was just deployed. JSONL goes to a file we parse below.
|
|
69
|
+
ACCOUNT_ID="$TEST_ACCT_ID" \
|
|
70
|
+
MAXY_SESSION_ROLE="admin" \
|
|
71
|
+
PLATFORM_ROOT="$INSTALL_DIR/platform" \
|
|
72
|
+
CLAUDE_CONFIG_DIR="$CONFIG_DIR" \
|
|
73
|
+
claude -p "$PROMPT" --output-format=stream-json --verbose \
|
|
74
|
+
> "$JSONL_OUT" 2>&1 \
|
|
75
|
+
|| { echo "[admin-enumerate-gate] setup-error reason=claude-spawn-failed exit=$?" >&2; EXIT=2; exit 2; }
|
|
76
|
+
|
|
77
|
+
fail() {
|
|
78
|
+
echo "[admin-enumerate-gate] FAIL $1" >&2
|
|
79
|
+
EXIT=1
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
# Assertion 1: the target path appears verbatim in some assistant turn
|
|
83
|
+
# or tool-use input. Either as the agent's final message or as an arg
|
|
84
|
+
# passed to a tool.
|
|
85
|
+
if ! grep -F -q "$TARGET_PATH" "$JSONL_OUT"; then
|
|
86
|
+
fail "correct-path-not-emitted target=$TARGET_PATH"
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
# Assertion 2: zero forbidden error patterns from the surfaces this
|
|
90
|
+
# task fixed.
|
|
91
|
+
FORBIDDEN_HITS=$(grep -E -c "EISDIR|Log directory does not exist|Plugin file not found|page has no readable text content" "$JSONL_OUT" || true)
|
|
92
|
+
if [ "${FORBIDDEN_HITS:-0}" -gt 0 ]; then
|
|
93
|
+
fail "forbidden-error-patterns=$FORBIDDEN_HITS"
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# Assertion 3: total tool-use calls from the user prompt to the
|
|
97
|
+
# correct-path emission are at most 3. The earlier failing run issued
|
|
98
|
+
# ~15.
|
|
99
|
+
TOOL_USE_COUNT=$(jq -r 'select(.type=="assistant") | .message.content[]? | select(.type=="tool_use") | .name' < "$JSONL_OUT" 2>/dev/null | wc -l | tr -d ' ' || echo 0)
|
|
100
|
+
if [ "${TOOL_USE_COUNT:-0}" -gt 3 ]; then
|
|
101
|
+
fail "tool-use-budget-exceeded count=$TOOL_USE_COUNT cap=3"
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
# Assertion 4: the FIRST disk-listing tool call returns an enumeration
|
|
105
|
+
# of <accountDir>/sites/. "Disk-listing" means LS, Glob, or Bash with
|
|
106
|
+
# `ls`. We accept any of those as the first relevant call; what we
|
|
107
|
+
# reject is a Read against a directory path.
|
|
108
|
+
FIRST_DIR_TOOL=$(jq -r 'select(.type=="assistant") | .message.content[]? | select(.type=="tool_use") | {name, input} | @json' < "$JSONL_OUT" 2>/dev/null \
|
|
109
|
+
| jq -r 'select(.name=="LS" or .name=="Glob" or (.name=="Bash" and (.input.command // "" | test("\\bls\\b")))) | .name' \
|
|
110
|
+
| head -1)
|
|
111
|
+
if [ -z "$FIRST_DIR_TOOL" ]; then
|
|
112
|
+
fail "no-disk-listing-tool-call-emitted"
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
# Assertion 5: no Read tool call against a path under <accountDir>/sites/
|
|
116
|
+
# that is a directory (would have produced EISDIR pre-fix; should not
|
|
117
|
+
# even be attempted now).
|
|
118
|
+
BAD_READ=$(jq -r 'select(.type=="assistant") | .message.content[]? | select(.type=="tool_use" and .name=="Read") | .input.file_path // ""' < "$JSONL_OUT" 2>/dev/null \
|
|
119
|
+
| while read -r p; do
|
|
120
|
+
[ -n "$p" ] && [ -d "$p" ] && echo "$p"
|
|
121
|
+
done | head -1)
|
|
122
|
+
if [ -n "$BAD_READ" ]; then
|
|
123
|
+
fail "read-against-directory path=$BAD_READ"
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
if [ "$EXIT" -eq 0 ]; then
|
|
127
|
+
echo "[admin-enumerate-gate] PASS target=$TARGET_PATH tool-use-count=$TOOL_USE_COUNT first-dir-tool=$FIRST_DIR_TOOL"
|
|
128
|
+
fi
|
|
129
|
+
exit "$EXIT"
|
|
@@ -52,8 +52,7 @@
|
|
|
52
52
|
# server.log alongside the [whatsapp-ingest] script lines.
|
|
53
53
|
#
|
|
54
54
|
# Exit codes follow Claude Code hook protocol: 0 = allow, 2 = block (stderr
|
|
55
|
-
# message shown to the agent). Fail-closed on terminal stdin
|
|
56
|
-
# pre-tool-use.sh.
|
|
55
|
+
# message shown to the agent). Fail-closed on terminal stdin.
|
|
57
56
|
|
|
58
57
|
set -uo pipefail
|
|
59
58
|
|
|
@@ -130,8 +130,9 @@ PY
|
|
|
130
130
|
|
|
131
131
|
# hook_block_with_emit <agentId> <hookName> <toolName> <reason>
|
|
132
132
|
# <userMessage> [durationMs]
|
|
133
|
-
# Convenience wrapper for
|
|
134
|
-
# echoes the user-facing block message to stderr,
|
|
133
|
+
# Convenience wrapper for any PreToolUse hook that records a block decision:
|
|
134
|
+
# emits the propagation record, echoes the user-facing block message to stderr,
|
|
135
|
+
# and exits 2.
|
|
135
136
|
hook_block_with_emit() {
|
|
136
137
|
local agentId="$1" hookName="$2" toolName="$3" reason="$4"
|
|
137
138
|
local userMessage="$5" durationMs="${6:-0}"
|
|
@@ -755,8 +755,8 @@ eagerTool(server, "account-update", "Update a user-configurable setting in accou
|
|
|
755
755
|
}
|
|
756
756
|
});
|
|
757
757
|
// Plugin enable/disable: deterministic write to account.json.enabledPlugins.
|
|
758
|
-
//
|
|
759
|
-
// so the agent
|
|
758
|
+
// IDENTITY.md doctrine forbids the agent's direct Edit on account.json,
|
|
759
|
+
// so the agent must not toggle enablement by hand-editing the file. This
|
|
760
760
|
// tool is the legitimate path: validates the plugin name, refuses core plugins,
|
|
761
761
|
// confirms the plugin directory exists, and atomically updates the array.
|
|
762
762
|
// Entitlement-bearing fields (tier, purchasedPlugins) are NOT writable here.
|
|
@@ -1397,6 +1397,15 @@ eagerTool(server, "logs-read", "Read recent logs. Stream logs (type=agent-stream
|
|
|
1397
1397
|
if (!ACCOUNT_ID)
|
|
1398
1398
|
return refuseNoAccount("logs-read");
|
|
1399
1399
|
try {
|
|
1400
|
+
// Account-scoped per-session log dir. `<installDir>/data/accounts/
|
|
1401
|
+
// <accountId>/logs/` mirrors the resolution in
|
|
1402
|
+
// `platform/scripts/logs-read.sh`. This dir may not exist on a Pi
|
|
1403
|
+
// where no claude session has yet tee'd stream output — that is NOT
|
|
1404
|
+
// a fatal condition for platform-scoped types like `server` / `vnc`,
|
|
1405
|
+
// which resolve against CONFIG_DIR below. Task 579 — the previous
|
|
1406
|
+
// early-existence check returned "Log directory does not exist" for
|
|
1407
|
+
// every type, including those whose actual target file lived
|
|
1408
|
+
// elsewhere. Each branch now checks its own resolved path.
|
|
1400
1409
|
const LOG_DIR = resolve(getAccountDir(), "logs");
|
|
1401
1410
|
// sessionKey is the single identifier on disk.
|
|
1402
1411
|
// `sessionId` is retained as a legacy alias that maps to the
|
|
@@ -1404,7 +1413,12 @@ eagerTool(server, "logs-read", "Read recent logs. Stream logs (type=agent-stream
|
|
|
1404
1413
|
const idForResolve = sessionKey ?? sessionId;
|
|
1405
1414
|
if (idForResolve) {
|
|
1406
1415
|
if (!existsSync(LOG_DIR)) {
|
|
1407
|
-
return {
|
|
1416
|
+
return {
|
|
1417
|
+
content: [{
|
|
1418
|
+
type: "text",
|
|
1419
|
+
text: `No per-session logs for this account yet (resolved dir does not exist on disk): ${LOG_DIR}. The directory is created on first claude session spawn.`,
|
|
1420
|
+
}],
|
|
1421
|
+
};
|
|
1408
1422
|
}
|
|
1409
1423
|
const prefixMap = {
|
|
1410
1424
|
"agent-stream": "claude-agent-stream",
|
|
@@ -1443,9 +1457,10 @@ eagerTool(server, "logs-read", "Read recent logs. Stream logs (type=agent-stream
|
|
|
1443
1457
|
}],
|
|
1444
1458
|
};
|
|
1445
1459
|
}
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1460
|
+
// Note: no early existence check on LOG_DIR here. Platform-scoped
|
|
1461
|
+
// types (server, vnc, heartbeat) resolve against CONFIG_DIR below
|
|
1462
|
+
// and must run even when the account log dir has not been created
|
|
1463
|
+
// yet. Account-scoped types check LOG_DIR before they reach for it.
|
|
1449
1464
|
// --- Session-key filtered mode: grep across log files ---
|
|
1450
1465
|
if (sessionKey) {
|
|
1451
1466
|
const prefixes = {
|
|
@@ -1463,7 +1478,13 @@ eagerTool(server, "logs-read", "Read recent logs. Stream logs (type=agent-stream
|
|
|
1463
1478
|
const searchPrefixes = type && type !== "heartbeat" && type !== "server" && type !== "vnc" && prefixes[type]
|
|
1464
1479
|
? { [type]: prefixes[type] }
|
|
1465
1480
|
: (type === "server" || type === "vnc") ? {} : prefixes;
|
|
1466
|
-
|
|
1481
|
+
// LOG_DIR may not exist on a Pi with no per-session logs yet. The
|
|
1482
|
+
// platform-scoped fallback dirs (CONFIG_DIR/logs/) are searched
|
|
1483
|
+
// below; this branch simply contributes nothing rather than
|
|
1484
|
+
// throwing on readdir.
|
|
1485
|
+
const allFiles = existsSync(LOG_DIR)
|
|
1486
|
+
? readdirSync(LOG_DIR).filter(f => f.endsWith(".log"))
|
|
1487
|
+
: [];
|
|
1467
1488
|
const sections = [];
|
|
1468
1489
|
// Search account-scoped prefix-based log files
|
|
1469
1490
|
for (const [logType, prefix] of Object.entries(searchPrefixes)) {
|
|
@@ -1571,13 +1592,24 @@ eagerTool(server, "logs-read", "Read recent logs. Stream logs (type=agent-stream
|
|
|
1571
1592
|
: resolvedType === "public" ? "public-agent-stream-"
|
|
1572
1593
|
: resolvedType === "mcp" ? "mcp-"
|
|
1573
1594
|
: "claude-agent-stream-";
|
|
1574
|
-
// Find the most recently modified file with the matching prefix
|
|
1595
|
+
// Find the most recently modified file with the matching prefix.
|
|
1596
|
+
// LOG_DIR may not exist yet on a Pi with no per-session logs; return
|
|
1597
|
+
// the resolved path in the error envelope so the operator can
|
|
1598
|
+
// verify on disk in one step rather than re-tracing the resolver.
|
|
1599
|
+
if (!existsSync(LOG_DIR)) {
|
|
1600
|
+
return {
|
|
1601
|
+
content: [{
|
|
1602
|
+
type: "text",
|
|
1603
|
+
text: `No per-session logs for this account yet (resolved dir does not exist on disk): ${LOG_DIR}. The directory is created on first claude session spawn.`,
|
|
1604
|
+
}],
|
|
1605
|
+
};
|
|
1606
|
+
}
|
|
1575
1607
|
const match = readdirSync(LOG_DIR)
|
|
1576
1608
|
.filter(f => f.startsWith(prefix) && f.endsWith(".log"))
|
|
1577
1609
|
.map(f => ({ file: f, mtime: statSync(resolve(LOG_DIR, f)).mtimeMs }))
|
|
1578
1610
|
.sort((a, b) => b.mtime - a.mtime)[0];
|
|
1579
1611
|
if (!match) {
|
|
1580
|
-
return { content: [{ type: "text", text: `No log file found for type '${resolvedType}'
|
|
1612
|
+
return { content: [{ type: "text", text: `No log file found for type '${resolvedType}' (resolved dir: ${LOG_DIR}, prefix: ${prefix})` }] };
|
|
1581
1613
|
}
|
|
1582
1614
|
const logFile = resolve(LOG_DIR, match.file);
|
|
1583
1615
|
const result = execFileSync("tail", ["-n", String(lines), logFile], {
|