@rubytech/create-maxy-code 0.1.64 → 0.1.65
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/docs/references/admin-session.md +4 -2
- package/payload/platform/plugins/docs/references/internals.md +7 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/_helpers/emit-capture.d.ts +22 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/_helpers/emit-capture.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/_helpers/emit-capture.js +44 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/_helpers/emit-capture.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights-emit.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights-emit.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights-emit.test.js +68 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights-emit.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection-emit.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection-emit.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection-emit.test.js +48 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection-emit.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-memory-expunge-emit.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-memory-expunge-emit.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-memory-expunge-emit.test.js +53 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-memory-expunge-emit.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-add-emit.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-add-emit.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-add-emit.test.js +40 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-add-emit.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-remove-emit.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-remove-emit.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-remove-emit.test.js +39 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-remove-emit.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write-emit.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write-emit.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write-emit.test.js +88 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write-emit.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-classify-emit.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-classify-emit.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-classify-emit.test.js +58 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-classify-emit.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-emit.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-emit.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-emit.test.js +58 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-emit.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edit-attachment-emit.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edit-attachment-emit.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edit-attachment-emit.test.js +70 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edit-attachment-emit.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-emit.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-emit.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-emit.test.js +48 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-emit.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-emit.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-emit.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-emit.test.js +74 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-emit.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-extract-emit.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-extract-emit.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-extract-emit.test.js +47 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-extract-emit.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-web-emit.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-web-emit.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-web-emit.test.js +65 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-web-emit.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex-emit.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex-emit.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex-emit.test.js +43 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex-emit.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-rename-attachment-emit.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-rename-attachment-emit.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-rename-attachment-emit.test.js +65 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-rename-attachment-emit.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-restore-emit.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-restore-emit.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-restore-emit.test.js +49 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-restore-emit.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.js +74 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.js +74 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-delete-emit.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-delete-emit.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-delete-emit.test.js +62 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-delete-emit.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-emit.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-emit.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-emit.test.js +76 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-emit.test.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/index.js +75 -2
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +8 -0
- 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 +14 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.d.ts +24 -4
- 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 +39 -9
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.js.map +1 -1
- package/payload/server/server-init.cjs +40 -0
package/package.json
CHANGED
|
@@ -109,7 +109,7 @@ Body overrides relative to a plain Sidebar click:
|
|
|
109
109
|
|
|
110
110
|
**Hook recursion gate.** `pty-spawner` stamps `MAXY_SPECIALIST=<specialist>` on every PTY env. The Stop hook short-circuits when `MAXY_SPECIALIST=database-operator` so the recorder's own end-of-turn does not re-fire the hook.
|
|
111
111
|
|
|
112
|
-
**Observability.** The hook emits exactly two lines per operator turn via `/api/admin/log-ingest`: `[turn-recorder] trigger sessionId=<op> turnIndex=0 transcriptBytes=<n> conversationBytes=<n>` and `[turn-recorder] spawn-request sessionId=<op> specialist=database-operator initialMessageBytes=<n>`. The manager adds `pty-spawn-allowlist specialist=database-operator count=11 sourced-from=agent-frontmatter` and `pty-spawn-start … specialist=database-operator append-system-prompt-bytes=0` before the PTY launches. The remainder of the recorder lifecycle is covered by the Sidebar's existing lines (`pty-spawned`, JSONL events, `auto-archive`). Failure-mode names: `trigger-skipped reason=…` enumerates `role-not-admin | is-recorder | empty-stdin | missing-transcript | conversation-empty`. Hook-side spawn errors emit `[turn-recorder] spawn-failed reason=loopback-http http=<code>`.
|
|
112
|
+
**Observability.** The hook emits exactly two lines per operator turn via `/api/admin/log-ingest`: `[turn-recorder] trigger sessionId=<op> turnIndex=0 transcriptBytes=<n> conversationBytes=<n>` and `[turn-recorder] spawn-request sessionId=<op> specialist=database-operator initialMessageBytes=<n>`. The manager adds `pty-spawn-allowlist specialist=database-operator count=11 stripped=0 sourced-from=agent-frontmatter` and `pty-spawn-start … specialist=database-operator append-system-prompt-bytes=0` before the PTY launches. The remainder of the recorder lifecycle is covered by the Sidebar's existing lines (`pty-spawned`, JSONL events, `auto-archive`). Failure-mode names: `trigger-skipped reason=…` enumerates `role-not-admin | is-recorder | empty-stdin | missing-transcript | conversation-empty`. Hook-side spawn errors emit `[turn-recorder] spawn-failed reason=loopback-http http=<code>`.
|
|
113
113
|
|
|
114
114
|
### Recorder lifecycle diagnostic
|
|
115
115
|
|
|
@@ -118,7 +118,7 @@ When the operator reports "the recorder did nothing this turn", run these six gr
|
|
|
118
118
|
1. **Stop hook fired.** `grep '\[turn-recorder\] trigger sessionId=<op>' ~/.<brand>/logs/server.log` — expects one line of shape `[turn-recorder] trigger sessionId=<op> turnIndex=0 transcriptBytes=<n> conversationBytes=<n>`. Absent: the Stop hook didn't run; check that `MAXY_SESSION_ROLE=admin` was set on the operator PTY and that `MAXY_SPECIALIST!=database-operator` (recursion gate).
|
|
119
119
|
2. **/spawn accepted.** `grep '\[turn-recorder\] spawn-request sessionId=<op>' ~/.<brand>/logs/server.log` — expects `[turn-recorder] spawn-request sessionId=<op> specialist=database-operator initialMessageBytes=<n>`. The response body of this POST carries `<rec>`. Absent: the hook fired but `/api/admin/claude-sessions` rejected; look for `[turn-recorder] spawn-failed reason=loopback-http http=<code>` on the next line.
|
|
120
120
|
3. **PTY started.** `grep 'pty-spawn-start .* specialist=database-operator' ~/.<brand>/logs/server.log` — expects `pty-spawn-start claudeBin=<…> argv-count=<n> append-system-prompt-bytes=0 … specialist=database-operator prompt-positional=yes prompt-bytes=<n>`. Absent: the wrapper accepted but the manager rejected before exec; check the spawn-failure surfaces (`which-claude-not-found | pty-spawn-failed | pid-file-timeout | host-context-unresolved | identity-unresolved | mcp-config-write-failed`).
|
|
121
|
-
4. **Agent file resolved.** `grep 'pty-spawn-allowlist specialist=database-operator count=11 sourced-from=agent-frontmatter' ~/.<brand>/logs/server.log` — expects exactly one line per recorder spawn. Absent (or `count` not equal to the frontmatter's tool count): the agent file at `$CLAUDE_CONFIG_DIR/agents/database-operator.md` is missing the `tools:` line,
|
|
121
|
+
4. **Agent file resolved.** `grep 'pty-spawn-allowlist specialist=database-operator count=11 stripped=0 sourced-from=agent-frontmatter' ~/.<brand>/logs/server.log` — expects exactly one line per recorder spawn. Absent (or `count` not equal to the frontmatter's tool count, or `stripped>0` meaning the brand excluded a plugin the recorder template references — Task 173): the agent file at `$CLAUDE_CONFIG_DIR/agents/database-operator.md` is missing the `tools:` line, the symlink the installer creates never landed, or the brand-aware drift filter dropped tools. Re-run the installer; cross-reference `brand.json#plugins.excluded` against the agent frontmatter.
|
|
122
122
|
5. **Graph write outcome.** `grep '\[mcp:memory\] memory-write .* session=<rec>' ~/.<brand>/logs/server.log` — expects one line ending `result=ok elementId=<id>` or `result=error reason=<slug>` (slug enumerated by the memory MCP write-path observability work). Absent: the recorder loaded but produced no tool calls — model-side decision, not infra. Read the recorder JSONL at `<accountDir>/.claude/projects/<slug>/<rec>.jsonl` to see what the LLM did.
|
|
123
123
|
6. **Auto-archive.** `grep 'auto-archive .* sessionId=<rec> .* specialist=database-operator reason=end-turn' ~/.<brand>/logs/server.log` — expects one line. Absent: the recorder finished but the manager's end-turn watcher didn't fire; the fs-watcher row will get reaped on its TTL but the recorder hung longer than expected. Investigate `pty-spawn-stop` and `pid-file-removed` lines on the same `<rec>`.
|
|
124
124
|
|
|
@@ -163,6 +163,8 @@ grep '\[mcp:memory\] log-ingest-failed' ~/.${brand}/logs/mcp-memory-stderr-*.log
|
|
|
163
163
|
|
|
164
164
|
The existing `mcp-memory-stderr-<date>.log` capture is unchanged on error paths — the new structured line is additive, not a relocation. Crash-mode debugging continues to read the stderr log; routine "did it land?" questions read `server.log`.
|
|
165
165
|
|
|
166
|
+
**Test contract (Task 168).** Each of the 20 wired tools carries a `*-emit.test.ts` fixture under `platform/plugins/memory/mcp/src/tools/__tests__/` that mocks `fetch` and asserts the wire body. A refactor that drops `withWriteEvent` from any tool fails the matching tool's tests with a clear `expected "vi.fn()" to be called 1 times, but got 0 times` error, naming the tool. A shared helper at `__tests__/_helpers/emit-capture.ts` standardises the fetch capture + Neo4j Session stub so each tool test stays a few lines of mocks + one happy + one error assertion. Drift between the helper's body shape and the route's validator is pinned by an end-to-end test at `platform/ui/server/routes/admin/__tests__/log-ingest-mcp-end-to-end.test.ts`, which routes the helper's POST through the real Hono `log-ingest` route with a loopback `remoteAddress` shim.
|
|
167
|
+
|
|
166
168
|
## Out of scope
|
|
167
169
|
|
|
168
170
|
- Public/WhatsApp/Telegram sessions — out of scope. Their sessionKeys remain `crypto.randomUUID()` and follow the existing rejection-on-restart contract.
|
|
@@ -492,7 +492,13 @@ For subagents, the same spawn pushes `--add-dir` for every bundled plugin agents
|
|
|
492
492
|
|
|
493
493
|
A boot gate refuses to start the manager when any admin-allowlisted tool `mcp__<plugin>__*` lacks a registered server. The signal is `boot-failed reason=mcp-allowlist-without-server plugin=<p> tool=<t>` followed by `process.exit(1)`. The remediation is a one-line edit to the named `PLUGIN.md`: add the `mcp:` block. The complementary observability emit `mcp-config-allowlist-coverage admin-tools=A admin-registered=R` (where `A === R`) confirms the invariant per boot.
|
|
494
494
|
|
|
495
|
-
|
|
495
|
+
A second boot gate walks every specialist `.md` under `platform/templates/specialists/agents/`, every bundled `<plugin>/agents/` directory, and the per-account `<accountDir>/specialists/agents/` directory, parses each file's `tools:` frontmatter line, and classifies every tool name as one of: CC-native (Read, Bash, …), bridge-namespace (`mcp__plugin_playwright_*`, `mcp__graph__*`), a tool the loaded `PLUGIN.md` set actually serves, `unknown-tool-in-plugin` (namespace served but tool name absent), `unknown-plugin-namespace` (namespace served by nothing), `brand-excluded-plugin` (namespace served by nothing on this brand, **but** the brand's `brand.json#plugins.excluded` list names it), or `malformed-name` (not CC-native and not `mcp__<plugin>__<tool>`-shaped). The first three pass. The next two refuse boot with one `boot-failed reason=specialist-tool-drift specialist=<name> tool=<t> drift=<class> path=<…>` line per defect, then `process.exit(1)`. `brand-excluded-plugin` is a structural pass: it lands in a per-specialist strip-list, the manager continues to boot, and at spawn time `pty-spawner` removes those tool names from the `--agent <name>` spawn's `--allowed-tools` argv. The complementary observability emit `specialist-tool-strip specialist=<name> plugin=<p> tools=<csv> reason=brand-excluded` fires one line per stripped (specialist, plugin) pair so an operator who reads `server.log` sees the brand filter doing work without cross-referencing `brand.json` against the template. The startup-self-test line `startup-self-test specialist-tool-drift=ok inspected=<N> stripped-specialists=<M>` confirms the gate ran and how many specialists carry strip-lists.
|
|
496
|
+
|
|
497
|
+
This gate was Task 173. The `brand-excluded` branch closes the recurring crash-restart loop on brands that ship without a plugin the shared `personal-assistant.md` template references (e.g. `realagent-code` excludes `telegram` while the template hard-codes `mcp__telegram__*`). The brand-agnostic template stays a single file; the brand-aware filter expresses what the specialist *may* do on this install while the template expresses what it *can* do across brands. Tool typos and renamed plugins still refuse to boot — only namespaces explicitly named in `plugins.excluded` are demoted to strip-and-warn.
|
|
498
|
+
|
|
499
|
+
**Per-spawn signals (server.log).** Every spawn emits `pty-spawn-mcp-config servers=<N> tools=<M> bytes=<B> path=<…>` once, plus one `pty-spawn-agents-dir role=<admin|public> path=<…>` per added directory. Specialist spawns additionally emit `pty-spawn-allowlist specialist=<name> count=<N> stripped=<S> sourced-from=agent-frontmatter` where `stripped` is the count of brand-excluded tool names removed before argv emission. The diagnostic one-liner is `grep -E 'pty-spawn-mcp-config|pty-spawn-agents-dir|pty-spawn-allowlist|mcp-config-allowlist-coverage|specialist-tool-strip|boot-failed reason=' ~/.<brand>/logs/server.log | tail -50`.
|
|
500
|
+
|
|
501
|
+
**Brand-process start counter (Task 173).** `platform/ui/server-init.cjs` increments a persistent counter at `/tmp/server-init-<accountId>-restart.count` on every fresh start and emits `[server-init] start count=<N> account=<accountId> counter-path=<…>` to `server.log`. /tmp clears on reboot, so a clean reboot starts the count fresh; any value `>1` between operator-observed reboots means the brand process (driven by its `Requires=<brand>-claude-session-manager.service` clause) is restarting. The diagnostic one-liner is `grep '\[server-init\] start' ~/.<brand>/logs/server.log | tail -5` — the trailing `count=` value is the loop depth without counting SIGTERMs.
|
|
496
502
|
|
|
497
503
|
**Programmatic spawn entry point.** Every admin PTY spawn that needs a first user prompt — UI click, turn-recorder hook, future automation — routes through the single wrapper at [`platform/ui/server/routes/admin/claude-sessions.ts`](../../../ui/server/routes/admin/claude-sessions.ts). The wrapper owns the per-spawn enrichment (owner profile, dormant/active plugins, specialist domains, tunnel URL) and the `senderId` resolution; it forwards a single `POST /spawn` to the session manager on `127.0.0.1`, with `initialMessage` inlined on that body. The manager appends `initialMessage` as the trailing positional argv to `claude`, so the CLI processes it as the session's first user turn at PTY startup — no separate `POST /<sessionId>/input` call, no bracketed-paste. (Task 153.) See `admin-session.md` "Spawn-with-initialMessage wrapper" for the body schema and caller list.
|
|
498
504
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { vi } from "vitest";
|
|
2
|
+
export interface CapturedEmit {
|
|
3
|
+
tag: string;
|
|
4
|
+
level: "info" | "error" | "warn" | "debug";
|
|
5
|
+
line: string;
|
|
6
|
+
}
|
|
7
|
+
export interface EmitCapture {
|
|
8
|
+
fetchSpy: ReturnType<typeof vi.fn>;
|
|
9
|
+
captures: () => CapturedEmit[];
|
|
10
|
+
restore: () => void;
|
|
11
|
+
}
|
|
12
|
+
export declare function setupEmitCapture(port?: string): EmitCapture;
|
|
13
|
+
/**
|
|
14
|
+
* Build a Neo4j Session stub whose `.run()` returns records constructed from
|
|
15
|
+
* row objects. Each call to `.run()` consumes the next entry from rowSequence.
|
|
16
|
+
* A row is a plain object — its keys are accessed by `record.get(key)`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function makeMockSession(rowSequence?: Array<Array<Record<string, unknown>>>): {
|
|
19
|
+
run: import("vitest").Mock<import("@vitest/spy").Procedure>;
|
|
20
|
+
close: import("vitest").Mock<import("@vitest/spy").Procedure>;
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=emit-capture.d.ts.map
|
package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/_helpers/emit-capture.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit-capture.d.ts","sourceRoot":"","sources":["../../../../src/tools/__tests__/_helpers/emit-capture.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE5B,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;IAC3C,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IACnC,QAAQ,EAAE,MAAM,YAAY,EAAE,CAAC;IAC/B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,gBAAgB,CAAC,IAAI,SAAU,GAAG,WAAW,CAmB5D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,WAAW,GAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAM;;;EAatF"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Task 168 — shared test helper for per-tool emit assertions.
|
|
2
|
+
//
|
|
3
|
+
// Spies global fetch, sets PLATFORM_PORT so withWriteEvent reaches the
|
|
4
|
+
// loopback URL (instead of stderr-fallback), and exposes the captured
|
|
5
|
+
// POST bodies. Each test pairs this with whatever per-tool deps it must
|
|
6
|
+
// mock so the wrapped body either resolves or throws.
|
|
7
|
+
import { vi } from "vitest";
|
|
8
|
+
export function setupEmitCapture(port = "12345") {
|
|
9
|
+
process.env.PLATFORM_PORT = port;
|
|
10
|
+
const originalFetch = globalThis.fetch;
|
|
11
|
+
const fetchSpy = vi.fn().mockResolvedValue(new Response('{"ok":true}', { status: 200 }));
|
|
12
|
+
globalThis.fetch = fetchSpy;
|
|
13
|
+
return {
|
|
14
|
+
fetchSpy,
|
|
15
|
+
captures: () => fetchSpy.mock.calls.map((call) => {
|
|
16
|
+
const init = call[1];
|
|
17
|
+
return JSON.parse(init.body);
|
|
18
|
+
}),
|
|
19
|
+
restore: () => {
|
|
20
|
+
globalThis.fetch = originalFetch;
|
|
21
|
+
delete process.env.PLATFORM_PORT;
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Build a Neo4j Session stub whose `.run()` returns records constructed from
|
|
27
|
+
* row objects. Each call to `.run()` consumes the next entry from rowSequence.
|
|
28
|
+
* A row is a plain object — its keys are accessed by `record.get(key)`.
|
|
29
|
+
*/
|
|
30
|
+
export function makeMockSession(rowSequence = []) {
|
|
31
|
+
let i = 0;
|
|
32
|
+
return {
|
|
33
|
+
run: vi.fn().mockImplementation(async () => {
|
|
34
|
+
const rows = rowSequence[i++] ?? [];
|
|
35
|
+
return {
|
|
36
|
+
records: rows.map((row) => ({
|
|
37
|
+
get: (key) => row[key],
|
|
38
|
+
})),
|
|
39
|
+
};
|
|
40
|
+
}),
|
|
41
|
+
close: vi.fn().mockResolvedValue(undefined),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=emit-capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit-capture.js","sourceRoot":"","sources":["../../../../src/tools/__tests__/_helpers/emit-capture.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,EAAE;AACF,uEAAuE;AACvE,sEAAsE;AACtE,wEAAwE;AACxE,sDAAsD;AAEtD,OAAO,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAc5B,MAAM,UAAU,gBAAgB,CAAC,IAAI,GAAG,OAAO;IAC7C,OAAO,CAAC,GAAG,CAAC,aAAa,GAAG,IAAI,CAAC;IACjC,MAAM,aAAa,GAAG,UAAU,CAAC,KAAK,CAAC;IACvC,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CACxC,IAAI,QAAQ,CAAC,aAAa,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAC7C,CAAC;IACF,UAAU,CAAC,KAAK,GAAG,QAAmC,CAAC;IACvD,OAAO;QACL,QAAQ;QACR,QAAQ,EAAE,GAAG,EAAE,CACb,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAgB,CAAC;YACpC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAc,CAAiB,CAAC;QACzD,CAAC,CAAC;QACJ,OAAO,EAAE,GAAG,EAAE;YACZ,UAAU,CAAC,KAAK,GAAG,aAAa,CAAC;YACjC,OAAO,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;QACnC,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,cAAqD,EAAE;IACrF,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO;QACL,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,KAAK,IAAI,EAAE;YACzC,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;YACpC,OAAO;gBACL,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;oBAC1B,GAAG,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC;iBAC/B,CAAC,CAAC;aACJ,CAAC;QACJ,CAAC,CAAC;QACF,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;KAC5C,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation-archive-derive-insights-emit.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/conversation-archive-derive-insights-emit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Task 168 — per-tool emit assertion for conversation-archive-derive-insights.
|
|
2
|
+
//
|
|
3
|
+
// Read-only inside the wrapper but routed through it because Task 166 wired
|
|
4
|
+
// every write-path tool — here it pins observability for the dispatch path,
|
|
5
|
+
// not data writes. Happy path requires real chunks + Haiku; error path is
|
|
6
|
+
// the natural archive-not-found gate.
|
|
7
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
8
|
+
import { setupEmitCapture, makeMockSession } from "./_helpers/emit-capture.js";
|
|
9
|
+
const mockSession = makeMockSession();
|
|
10
|
+
vi.mock("../../lib/neo4j.js", () => ({
|
|
11
|
+
getSession: () => mockSession,
|
|
12
|
+
}));
|
|
13
|
+
vi.mock("../../../../../../lib/oauth-llm/dist/index.js", () => ({
|
|
14
|
+
callOauthLlm: vi.fn(),
|
|
15
|
+
}));
|
|
16
|
+
import { conversationArchiveDeriveInsights } from "../conversation-archive-derive-insights.js";
|
|
17
|
+
describe("conversation-archive-derive-insights — emit wrapper wired", () => {
|
|
18
|
+
let emit;
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
emit = setupEmitCapture();
|
|
21
|
+
mockSession.run.mockReset();
|
|
22
|
+
});
|
|
23
|
+
afterEach(() => emit.restore());
|
|
24
|
+
it("emits result=error line when archive not found", async () => {
|
|
25
|
+
// loadArchive's MATCH returns no rows → tool throws archive-not-found.
|
|
26
|
+
mockSession.run.mockResolvedValue({ records: [] });
|
|
27
|
+
await expect(conversationArchiveDeriveInsights({
|
|
28
|
+
accountId: "acct-1",
|
|
29
|
+
archiveElementId: "4:missing:1",
|
|
30
|
+
})).rejects.toThrow(/archive-not-found/);
|
|
31
|
+
expect(emit.fetchSpy).toHaveBeenCalledTimes(1);
|
|
32
|
+
const body = emit.captures()[0];
|
|
33
|
+
expect(body.tag).toBe("mcp:memory");
|
|
34
|
+
expect(body.level).toBe("error");
|
|
35
|
+
expect(body.line).toContain("conversation-archive-derive-insights");
|
|
36
|
+
expect(body.line).toContain("result=error");
|
|
37
|
+
});
|
|
38
|
+
it("emits result=ok line on happy path (archive with no chunks to walk)", async () => {
|
|
39
|
+
// loadArchive: one row with archive metadata + totalChunks=1 (totalChunks=0
|
|
40
|
+
// is treated as archive-not-found per loadArchive guard).
|
|
41
|
+
mockSession.run.mockResolvedValueOnce({
|
|
42
|
+
records: [
|
|
43
|
+
{
|
|
44
|
+
get: (k) => {
|
|
45
|
+
if (k === "title")
|
|
46
|
+
return "Stub Archive";
|
|
47
|
+
if (k === "totalChunks")
|
|
48
|
+
return 1;
|
|
49
|
+
return null;
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
});
|
|
54
|
+
// loadChunks: empty — for-loop never iterates so no LLM/related-cypher fires.
|
|
55
|
+
mockSession.run.mockResolvedValueOnce({ records: [] });
|
|
56
|
+
await conversationArchiveDeriveInsights({
|
|
57
|
+
accountId: "acct-1",
|
|
58
|
+
archiveElementId: "4:archive:1",
|
|
59
|
+
});
|
|
60
|
+
expect(emit.fetchSpy).toHaveBeenCalledTimes(1);
|
|
61
|
+
const body = emit.captures()[0];
|
|
62
|
+
expect(body.tag).toBe("mcp:memory");
|
|
63
|
+
expect(body.level).toBe("info");
|
|
64
|
+
expect(body.line).toContain("conversation-archive-derive-insights");
|
|
65
|
+
expect(body.line).toContain("result=ok");
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
//# sourceMappingURL=conversation-archive-derive-insights-emit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation-archive-derive-insights-emit.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/conversation-archive-derive-insights-emit.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation-archive-enrich-rejection-emit.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/conversation-archive-enrich-rejection-emit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Task 168 — per-tool emit assertion for conversation-archive-enrich-rejection.
|
|
2
|
+
//
|
|
3
|
+
// Existing memory MCP test (conversation-archive-enrich-rejection.test.ts)
|
|
4
|
+
// runs the impl against a scratch directory; this companion file isolates
|
|
5
|
+
// the emit-wrapper contract. We mock the underlying derive-insights module's
|
|
6
|
+
// path constants + key helper so the impl runs without needing PLATFORM_ROOT.
|
|
7
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
8
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
9
|
+
import { resolve } from "node:path";
|
|
10
|
+
import { tmpdir } from "node:os";
|
|
11
|
+
import { setupEmitCapture } from "./_helpers/emit-capture.js";
|
|
12
|
+
import { conversationArchiveEnrichRejection } from "../conversation-archive-enrich-rejection.js";
|
|
13
|
+
describe("conversation-archive-enrich-rejection — emit wrapper wired", () => {
|
|
14
|
+
let emit;
|
|
15
|
+
let scratch;
|
|
16
|
+
let origRoot;
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
emit = setupEmitCapture();
|
|
19
|
+
scratch = mkdtempSync(resolve(tmpdir(), "task-168-"));
|
|
20
|
+
origRoot = process.env.PLATFORM_ROOT;
|
|
21
|
+
process.env.PLATFORM_ROOT = resolve(scratch, "platform");
|
|
22
|
+
});
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
emit.restore();
|
|
25
|
+
if (origRoot === undefined)
|
|
26
|
+
delete process.env.PLATFORM_ROOT;
|
|
27
|
+
else
|
|
28
|
+
process.env.PLATFORM_ROOT = origRoot;
|
|
29
|
+
rmSync(scratch, { recursive: true, force: true });
|
|
30
|
+
});
|
|
31
|
+
it("emits result=ok line on happy path (record mode)", async () => {
|
|
32
|
+
await conversationArchiveEnrichRejection({
|
|
33
|
+
accountId: "acct-1",
|
|
34
|
+
archiveElementId: "4:archive:1",
|
|
35
|
+
chunkElementId: "4:chunk:1",
|
|
36
|
+
kind: "mention",
|
|
37
|
+
contentHash: "abcd",
|
|
38
|
+
mode: "record",
|
|
39
|
+
});
|
|
40
|
+
expect(emit.fetchSpy).toHaveBeenCalledTimes(1);
|
|
41
|
+
const body = emit.captures()[0];
|
|
42
|
+
expect(body.tag).toBe("mcp:memory");
|
|
43
|
+
expect(body.level).toBe("info");
|
|
44
|
+
expect(body.line).toContain("conversation-archive-enrich-rejection");
|
|
45
|
+
expect(body.line).toContain("result=ok");
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
//# sourceMappingURL=conversation-archive-enrich-rejection-emit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation-archive-enrich-rejection-emit.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/conversation-archive-enrich-rejection-emit.test.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,EAAE;AACF,2EAA2E;AAC3E,0EAA0E;AAC1E,6EAA6E;AAC7E,8EAA8E;AAE9E,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAM,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAE9D,OAAO,EAAE,kCAAkC,EAAE,MAAM,6CAA6C,CAAC;AAEjG,QAAQ,CAAC,4DAA4D,EAAE,GAAG,EAAE;IAC1E,IAAI,IAAyC,CAAC;IAC9C,IAAI,OAAe,CAAC;IACpB,IAAI,QAA4B,CAAC;IAEjC,UAAU,CAAC,GAAG,EAAE;QACd,IAAI,GAAG,gBAAgB,EAAE,CAAC;QAC1B,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC;QACtD,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,aAAa,GAAG,OAAO,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IACH,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,IAAI,QAAQ,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;;YACxD,OAAO,CAAC,GAAG,CAAC,aAAa,GAAG,QAAQ,CAAC;QAC1C,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,kCAAkC,CAAC;YACvC,SAAS,EAAE,QAAQ;YACnB,gBAAgB,EAAE,aAAa;YAC/B,cAAc,EAAE,WAAW;YAC3B,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,MAAM;YACnB,IAAI,EAAE,QAAQ;SACf,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAE,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACpC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAChC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,uCAAuC,CAAC,CAAC;QACrE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation-memory-expunge-emit.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/conversation-memory-expunge-emit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Task 168 — per-tool emit assertion for conversation-memory-expunge.
|
|
2
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
3
|
+
import { setupEmitCapture } from "./_helpers/emit-capture.js";
|
|
4
|
+
vi.mock("../../lib/neo4j.js", () => ({
|
|
5
|
+
getDriver: () => ({}),
|
|
6
|
+
}));
|
|
7
|
+
vi.mock("../../lib/graph-prune.js", () => ({
|
|
8
|
+
expungeConversationMemory: vi.fn(),
|
|
9
|
+
}));
|
|
10
|
+
import { conversationMemoryExpunge } from "../conversation-memory-expunge.js";
|
|
11
|
+
import { expungeConversationMemory } from "../../lib/graph-prune.js";
|
|
12
|
+
describe("conversation-memory-expunge — emit wrapper wired", () => {
|
|
13
|
+
let emit;
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
emit = setupEmitCapture();
|
|
16
|
+
vi.mocked(expungeConversationMemory).mockReset();
|
|
17
|
+
});
|
|
18
|
+
afterEach(() => emit.restore());
|
|
19
|
+
it("emits result=ok line on happy path", async () => {
|
|
20
|
+
vi.mocked(expungeConversationMemory).mockResolvedValue({
|
|
21
|
+
conversationId: "conv-1",
|
|
22
|
+
pattern: ".*",
|
|
23
|
+
nodesScanned: 0,
|
|
24
|
+
propertiesNulled: 0,
|
|
25
|
+
affectedNodeIds: [],
|
|
26
|
+
});
|
|
27
|
+
await conversationMemoryExpunge({
|
|
28
|
+
accountId: "acct-1",
|
|
29
|
+
conversationId: "conv-1",
|
|
30
|
+
pattern: ".*",
|
|
31
|
+
});
|
|
32
|
+
expect(emit.fetchSpy).toHaveBeenCalledTimes(1);
|
|
33
|
+
const body = emit.captures()[0];
|
|
34
|
+
expect(body.tag).toBe("mcp:memory");
|
|
35
|
+
expect(body.level).toBe("info");
|
|
36
|
+
expect(body.line).toContain("conversation-memory-expunge");
|
|
37
|
+
expect(body.line).toContain("result=ok");
|
|
38
|
+
});
|
|
39
|
+
it("emits result=error line when expungeConversationMemory throws", async () => {
|
|
40
|
+
vi.mocked(expungeConversationMemory).mockRejectedValue(new Error("driver error"));
|
|
41
|
+
await expect(conversationMemoryExpunge({
|
|
42
|
+
accountId: "acct-1",
|
|
43
|
+
conversationId: "conv-1",
|
|
44
|
+
pattern: ".*",
|
|
45
|
+
})).rejects.toThrow(/driver error/);
|
|
46
|
+
expect(emit.fetchSpy).toHaveBeenCalledTimes(1);
|
|
47
|
+
const body = emit.captures()[0];
|
|
48
|
+
expect(body.level).toBe("error");
|
|
49
|
+
expect(body.line).toContain("conversation-memory-expunge");
|
|
50
|
+
expect(body.line).toContain("result=error");
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
//# sourceMappingURL=conversation-memory-expunge-emit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation-memory-expunge-emit.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/conversation-memory-expunge-emit.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-prune-denylist-add-emit.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/graph-prune-denylist-add-emit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Task 168 — per-tool emit assertion for graph-prune-denylist-add.
|
|
2
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
3
|
+
import { setupEmitCapture } from "./_helpers/emit-capture.js";
|
|
4
|
+
vi.mock("../../lib/graph-prune.js", () => ({
|
|
5
|
+
resolveConfigDir: () => "/tmp/task-168-stub",
|
|
6
|
+
loadDenylist: () => ({ values: [] }),
|
|
7
|
+
saveDenylist: vi.fn(),
|
|
8
|
+
}));
|
|
9
|
+
import { graphPruneDenylistAdd } from "../graph-prune-denylist-add.js";
|
|
10
|
+
import * as graphPrune from "../../lib/graph-prune.js";
|
|
11
|
+
describe("graph-prune-denylist-add — emit wrapper wired", () => {
|
|
12
|
+
let emit;
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
emit = setupEmitCapture();
|
|
15
|
+
vi.mocked(graphPrune.saveDenylist).mockReset();
|
|
16
|
+
});
|
|
17
|
+
afterEach(() => emit.restore());
|
|
18
|
+
it("emits result=ok line on happy path", async () => {
|
|
19
|
+
await graphPruneDenylistAdd(["NewLabel"]);
|
|
20
|
+
expect(emit.fetchSpy).toHaveBeenCalledTimes(1);
|
|
21
|
+
const body = emit.captures()[0];
|
|
22
|
+
expect(body.tag).toBe("mcp:memory");
|
|
23
|
+
expect(body.level).toBe("info");
|
|
24
|
+
expect(body.line).toContain("graph-prune-denylist-add");
|
|
25
|
+
expect(body.line).toContain("result=ok");
|
|
26
|
+
});
|
|
27
|
+
it("emits result=error line when saveDenylist throws", async () => {
|
|
28
|
+
vi.mocked(graphPrune.saveDenylist).mockImplementation(() => {
|
|
29
|
+
throw new Error("disk full");
|
|
30
|
+
});
|
|
31
|
+
await expect(graphPruneDenylistAdd(["NewLabel"])).rejects.toThrow(/disk full/);
|
|
32
|
+
expect(emit.fetchSpy).toHaveBeenCalledTimes(1);
|
|
33
|
+
const body = emit.captures()[0];
|
|
34
|
+
expect(body.level).toBe("error");
|
|
35
|
+
expect(body.line).toContain("graph-prune-denylist-add");
|
|
36
|
+
expect(body.line).toContain("result=error");
|
|
37
|
+
expect(body.line).toContain("reason=neo4j-driver-error");
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
//# sourceMappingURL=graph-prune-denylist-add-emit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-prune-denylist-add-emit.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/graph-prune-denylist-add-emit.test.ts"],"names":[],"mappings":"AAAA,mEAAmE;AAEnE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAE9D,EAAE,CAAC,IAAI,CAAC,0BAA0B,EAAE,GAAG,EAAE,CAAC,CAAC;IACzC,gBAAgB,EAAE,GAAG,EAAE,CAAC,oBAAoB;IAC5C,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACpC,YAAY,EAAE,EAAE,CAAC,EAAE,EAAE;CACtB,CAAC,CAAC,CAAC;AAEJ,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,UAAU,MAAM,0BAA0B,CAAC;AAEvD,QAAQ,CAAC,+CAA+C,EAAE,GAAG,EAAE;IAC7D,IAAI,IAAyC,CAAC;IAC9C,UAAU,CAAC,GAAG,EAAE;QACd,IAAI,GAAG,gBAAgB,EAAE,CAAC;QAC1B,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,SAAS,EAAE,CAAC;IACjD,CAAC,CAAC,CAAC;IACH,SAAS,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAEhC,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAClD,MAAM,qBAAqB,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAE,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACpC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAChC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,0BAA0B,CAAC,CAAC;QACxD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE;YACzD,MAAM,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAC/E,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAE,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,0BAA0B,CAAC,CAAC;QACxD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,2BAA2B,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-prune-denylist-remove-emit.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/graph-prune-denylist-remove-emit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Task 168 — per-tool emit assertion for graph-prune-denylist-remove.
|
|
2
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
3
|
+
import { setupEmitCapture } from "./_helpers/emit-capture.js";
|
|
4
|
+
vi.mock("../../lib/graph-prune.js", () => ({
|
|
5
|
+
resolveConfigDir: () => "/tmp/task-168-stub",
|
|
6
|
+
loadDenylist: () => ({ values: ["ExistingLabel"] }),
|
|
7
|
+
saveDenylist: vi.fn(),
|
|
8
|
+
}));
|
|
9
|
+
import { graphPruneDenylistRemove } from "../graph-prune-denylist-remove.js";
|
|
10
|
+
import * as graphPrune from "../../lib/graph-prune.js";
|
|
11
|
+
describe("graph-prune-denylist-remove — emit wrapper wired", () => {
|
|
12
|
+
let emit;
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
emit = setupEmitCapture();
|
|
15
|
+
vi.mocked(graphPrune.saveDenylist).mockReset();
|
|
16
|
+
});
|
|
17
|
+
afterEach(() => emit.restore());
|
|
18
|
+
it("emits result=ok line on happy path", async () => {
|
|
19
|
+
await graphPruneDenylistRemove(["ExistingLabel"]);
|
|
20
|
+
expect(emit.fetchSpy).toHaveBeenCalledTimes(1);
|
|
21
|
+
const body = emit.captures()[0];
|
|
22
|
+
expect(body.tag).toBe("mcp:memory");
|
|
23
|
+
expect(body.level).toBe("info");
|
|
24
|
+
expect(body.line).toContain("graph-prune-denylist-remove");
|
|
25
|
+
expect(body.line).toContain("result=ok");
|
|
26
|
+
});
|
|
27
|
+
it("emits result=error line when saveDenylist throws", async () => {
|
|
28
|
+
vi.mocked(graphPrune.saveDenylist).mockImplementation(() => {
|
|
29
|
+
throw new Error("permission denied");
|
|
30
|
+
});
|
|
31
|
+
await expect(graphPruneDenylistRemove(["ExistingLabel"])).rejects.toThrow(/permission denied/);
|
|
32
|
+
expect(emit.fetchSpy).toHaveBeenCalledTimes(1);
|
|
33
|
+
const body = emit.captures()[0];
|
|
34
|
+
expect(body.level).toBe("error");
|
|
35
|
+
expect(body.line).toContain("graph-prune-denylist-remove");
|
|
36
|
+
expect(body.line).toContain("result=error");
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
//# sourceMappingURL=graph-prune-denylist-remove-emit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-prune-denylist-remove-emit.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/graph-prune-denylist-remove-emit.test.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAE9D,EAAE,CAAC,IAAI,CAAC,0BAA0B,EAAE,GAAG,EAAE,CAAC,CAAC;IACzC,gBAAgB,EAAE,GAAG,EAAE,CAAC,oBAAoB;IAC5C,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;IACnD,YAAY,EAAE,EAAE,CAAC,EAAE,EAAE;CACtB,CAAC,CAAC,CAAC;AAEJ,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,KAAK,UAAU,MAAM,0BAA0B,CAAC;AAEvD,QAAQ,CAAC,kDAAkD,EAAE,GAAG,EAAE;IAChE,IAAI,IAAyC,CAAC;IAC9C,UAAU,CAAC,GAAG,EAAE;QACd,IAAI,GAAG,gBAAgB,EAAE,CAAC;QAC1B,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,SAAS,EAAE,CAAC;IACjD,CAAC,CAAC,CAAC;IACH,SAAS,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAEhC,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAClD,MAAM,wBAAwB,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC;QAClD,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAE,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACpC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAChC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAC;QAC3D,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE;YACzD,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;QAC/F,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAE,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAC;QAC3D,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-archive-write-emit.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/memory-archive-write-emit.test.ts"],"names":[],"mappings":""}
|
package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write-emit.test.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Task 168 — per-tool emit assertion for memory-archive-write.
|
|
2
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
3
|
+
import { setupEmitCapture } from "./_helpers/emit-capture.js";
|
|
4
|
+
const mockSession = {
|
|
5
|
+
run: vi.fn(),
|
|
6
|
+
executeWrite: vi.fn(),
|
|
7
|
+
close: vi.fn().mockResolvedValue(undefined),
|
|
8
|
+
};
|
|
9
|
+
vi.mock("../../lib/neo4j.js", () => ({
|
|
10
|
+
getSession: () => mockSession,
|
|
11
|
+
}));
|
|
12
|
+
import { memoryArchiveWrite } from "../memory-archive-write.js";
|
|
13
|
+
describe("memory-archive-write — emit wrapper wired", () => {
|
|
14
|
+
let emit;
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
emit = setupEmitCapture();
|
|
17
|
+
mockSession.run.mockReset();
|
|
18
|
+
mockSession.executeWrite.mockReset();
|
|
19
|
+
});
|
|
20
|
+
afterEach(() => emit.restore());
|
|
21
|
+
it("emits result=ok line on happy path", async () => {
|
|
22
|
+
// verifyArchive's MATCH: owner found with :Person label and matching account.
|
|
23
|
+
mockSession.run.mockResolvedValue({
|
|
24
|
+
records: [
|
|
25
|
+
{
|
|
26
|
+
get: (k) => {
|
|
27
|
+
if (k === "labels")
|
|
28
|
+
return ["Person"];
|
|
29
|
+
if (k === "accountId")
|
|
30
|
+
return "acct-1";
|
|
31
|
+
return null;
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
});
|
|
36
|
+
const noopCounters = {
|
|
37
|
+
nodesCreated: 0,
|
|
38
|
+
relationshipsCreated: 0,
|
|
39
|
+
propertiesSet: 0,
|
|
40
|
+
};
|
|
41
|
+
// writeBatch wraps personRes / orgRes inside executeWrite. Return the
|
|
42
|
+
// counter shapes the handler reads.
|
|
43
|
+
mockSession.executeWrite.mockImplementation(async (fn) => {
|
|
44
|
+
return fn({
|
|
45
|
+
run: vi.fn().mockResolvedValue({
|
|
46
|
+
summary: { counters: { updates: () => noopCounters } },
|
|
47
|
+
}),
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
await memoryArchiveWrite({
|
|
51
|
+
archiveType: "linkedin-connections",
|
|
52
|
+
ownerNodeId: "4:owner:1",
|
|
53
|
+
accountId: "acct-1",
|
|
54
|
+
rows: [
|
|
55
|
+
{
|
|
56
|
+
firstName: "Alice",
|
|
57
|
+
lastName: "Carter",
|
|
58
|
+
email: "alice@example.com",
|
|
59
|
+
company: "ExampleCo",
|
|
60
|
+
position: "Director",
|
|
61
|
+
connectedOn: "2024-01-01",
|
|
62
|
+
url: "https://www.linkedin.com/in/alice",
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
});
|
|
66
|
+
expect(emit.fetchSpy).toHaveBeenCalledTimes(1);
|
|
67
|
+
const body = emit.captures()[0];
|
|
68
|
+
expect(body.tag).toBe("mcp:memory");
|
|
69
|
+
expect(body.level).toBe("info");
|
|
70
|
+
expect(body.line).toContain("memory-archive-write");
|
|
71
|
+
expect(body.line).toContain("result=ok");
|
|
72
|
+
});
|
|
73
|
+
it("emits result=error line on missing accountId (invalid-input)", async () => {
|
|
74
|
+
await expect(memoryArchiveWrite({
|
|
75
|
+
archiveType: "linkedin-connections",
|
|
76
|
+
ownerNodeId: "4:owner:1",
|
|
77
|
+
accountId: "",
|
|
78
|
+
rows: [{}],
|
|
79
|
+
})).rejects.toThrow(/accountId is required/);
|
|
80
|
+
expect(emit.fetchSpy).toHaveBeenCalledTimes(1);
|
|
81
|
+
const body = emit.captures()[0];
|
|
82
|
+
expect(body.level).toBe("error");
|
|
83
|
+
expect(body.line).toContain("memory-archive-write");
|
|
84
|
+
expect(body.line).toContain("result=error");
|
|
85
|
+
expect(body.line).toContain("reason=invalid-input");
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
//# sourceMappingURL=memory-archive-write-emit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-archive-write-emit.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/memory-archive-write-emit.test.ts"],"names":[],"mappings":"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"}
|
package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-classify-emit.test.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-classify-emit.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/memory-classify-emit.test.ts"],"names":[],"mappings":""}
|