@rubytech/create-maxy-code 0.1.57 → 0.1.58
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
CHANGED
|
@@ -79,7 +79,7 @@ The Hono route `POST /api/admin/claude-sessions` at [`platform/ui/server/routes/
|
|
|
79
79
|
|
|
80
80
|
**Body schema.** `{channel?, permissionMode?, initialMessage?}` for operator-driven UI spawns (cookie path — `senderId` resolved from the admin session cookie, `hidden: false`, no `specialist`). The recorder hook posts the loopback variant: `{specialist:'database-operator', initialMessage, originatingSessionId, channel?}` — no synthetic `senderId` marker. The wrapper rejects nothing structurally — string fields are coerced or defaulted (`channel` → `'browser'`, `permissionMode` → undefined, `initialMessage` → null if empty/whitespace) and the session manager validates the rest downstream. The loopback branch refuses the request with `400 originating-session-id-required` if `originatingSessionId` is missing or non-UUID, and `404 originating-session-not-found` if the manager has no StoredSession for it.
|
|
81
81
|
|
|
82
|
-
**Auth surfaces.** Two: `cookie` (Sidebar — `requireAdminSession` validates `session_key` from query/body/multipart and resolves `senderId` from the in-memory session store) and `loopback` (recorder hook — `requireAdminSessionUnlessLoopbackSpawn` skips cookie auth when method is `POST`, path is exactly `/api/admin/claude-sessions`,
|
|
82
|
+
**Auth surfaces.** Two: `cookie` (Sidebar — `requireAdminSession` validates `session_key` from query/body/multipart and resolves `senderId` from the in-memory session store) and `loopback` (recorder hook — `requireAdminSessionUnlessLoopbackSpawn` skips cookie auth when method is `POST`, path is exactly `/api/admin/claude-sessions`, the TCP peer is `127.0.0.1`/`::1`, **and** the request carries no `x-forwarded-for` header; the handler then looks up the operator's `senderId` from `GET {managerBase}/<originatingSessionId>/meta`). The XFF check distinguishes a real in-process recorder hook from a browser request that traversed `maxy-edge`'s reverse proxy and arrived on loopback with `peer=127.0.0.1` — same idiom `requestIsTlsTerminated` uses to disambiguate proxied vs direct TLS. Without the XFF gate, every edge-proxied "+ New session" click would mis-fire the bypass and 400 with `originating-session-id-required` (Task 143). Same trust boundary the claude-session-manager itself relies on — both bind 127.0.0.1 only. The Task-122-era `POST /recorder-spawn` sibling route is gone (Task 134). One route, one shape, two surfaces.
|
|
83
83
|
|
|
84
84
|
**Forwarded endpoints.** Two upstream calls per spawn-with-message: `POST {managerBase}/spawn` (enriched body) returns `{sessionId}`; when `initialMessage` is set, the wrapper then issues `POST {managerBase}/<sessionId>/input { text: <initialMessage> }` synchronously so the PTY has its first turn stimulus before the operator types. The HTTP response streams the spawn upstream body straight through.
|
|
85
85
|
|
|
@@ -89,7 +89,7 @@ The Hono route `POST /api/admin/claude-sessions` at [`platform/ui/server/routes/
|
|
|
89
89
|
|
|
90
90
|
After every completed operator admin turn, the Stop hook `platform/plugins/admin/hooks/turn-completed-graph-write.sh` dispatches one headless `database-operator` session to record any new or missing information from that turn into the Neo4j graph. Exactly four things happen — any deviation is a fault (2026-05-18 doctrine fix).
|
|
91
91
|
|
|
92
|
-
1. **A new admin session is spawned the SAME way a Sidebar "New session" click spawns one.** The hook POSTs to `POST /api/admin/claude-sessions` — the exact same route the Sidebar uses. The Hono wrapper bypasses cookie auth via `requireAdminSessionUnlessLoopbackSpawn` on this exact method+path when the
|
|
92
|
+
1. **A new admin session is spawned the SAME way a Sidebar "New session" click spawns one.** The hook POSTs to `POST /api/admin/claude-sessions` — the exact same route the Sidebar uses. The Hono wrapper bypasses cookie auth via `requireAdminSessionUnlessLoopbackSpawn` on this exact method+path when the TCP peer is `127.0.0.1` **and** the request carries no `x-forwarded-for` header (the recorder is in-process; the edge proxy unconditionally stamps XFF on every browser request — Task 143). The body the hook sends carries only `{specialist:'database-operator', initialMessage, originatingSessionId, channel:'browser'}` — no synthetic `senderId` marker (Task 134 removed it; the loopback bypass is method+path-scoped). The wrapper resolves the operator's real `senderId` from `originatingSessionId` via `GET <managerBase>/<originatingSessionId>/meta`, then forwards a Sidebar-shape body to the manager: real operator `senderId`, `hidden: false`, `channel: 'browser'`, `role: 'admin'`, plus `specialist` and `originatingSessionId`. `aboutOwner` resolves against the operator's account; the recorder appears in the operator's sidebar as a sibling session of the originating one. `userId` is not exposed via `/meta` and is left undefined — `aboutOwner` falls through to senderId-only resolution, which returns the operator's account profile and is adequate for the recorder's single-turn lifecycle.
|
|
93
93
|
2. **The spawned session's specialist is `database-operator`.**
|
|
94
94
|
3. **The initial message is the operator's last turn, prefixed by a literal instruction.** Format:
|
|
95
95
|
```
|
package/payload/server/server.js
CHANGED
|
@@ -8107,8 +8107,10 @@ var requireAdminSessionUnlessLoopbackSpawn = async (c, next) => {
|
|
|
8107
8107
|
if (c.req.method === "POST" && c.req.path === "/api/admin/claude-sessions") {
|
|
8108
8108
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
8109
8109
|
const isLoopback = remoteAddr === "127.0.0.1" || remoteAddr === "::1" || remoteAddr === "::ffff:127.0.0.1";
|
|
8110
|
-
|
|
8111
|
-
|
|
8110
|
+
const xff = c.req.header("x-forwarded-for");
|
|
8111
|
+
const xffPresent = typeof xff === "string" && xff.length > 0;
|
|
8112
|
+
if (isLoopback && !xffPresent) {
|
|
8113
|
+
console.log(`${TAG18} loopback-spawn-bypass remoteAddr=${remoteAddr} xff=absent`);
|
|
8112
8114
|
return next();
|
|
8113
8115
|
}
|
|
8114
8116
|
}
|