@rubytech/create-realagent 1.0.816 → 1.0.818
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/lib/graph-search/src/__tests__/fulltext-coverage.test.ts +1 -1
- package/payload/platform/lib/graph-write/dist/index.d.ts +5 -0
- package/payload/platform/lib/graph-write/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/graph-write/dist/index.js +14 -0
- package/payload/platform/lib/graph-write/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-write/src/index.ts +25 -0
- package/payload/platform/neo4j/edge-annotations.json +0 -8
- package/payload/platform/neo4j/migrations/004-prune-alien-accounts.ts +3 -4
- package/payload/platform/neo4j/migrations/005-removed-review-feature.ts +102 -0
- package/payload/platform/neo4j/schema.cypher +1 -22
- package/payload/platform/plugins/admin/PLUGIN.md +1 -8
- package/payload/platform/plugins/admin/mcp/dist/index.js +6 -44
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/onboarding/SKILL.md +2 -2
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.d.ts.map +1 -1
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.js +2 -3
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.js.map +1 -1
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/setup-orchestrator.js +1 -1
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/setup-orchestrator.js.map +1 -1
- package/payload/platform/plugins/docs/references/cloudflare.md +1 -3
- package/payload/platform/plugins/docs/references/memory-guide.md +1 -1
- package/payload/platform/plugins/docs/references/troubleshooting.md +8 -12
- package/payload/platform/plugins/memory/mcp/dist/lib/graph-write-gate.js +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/graph-write-gate.js.map +1 -1
- package/payload/platform/scripts/logs-read.sh +8 -38
- package/payload/server/chunk-AJLGI7Y3.js +10067 -0
- package/payload/server/chunk-ON3LBL2Y.js +1114 -0
- package/payload/server/chunk-P3HTEK33.js +10074 -0
- package/payload/server/chunk-PXQA2MA3.js +2518 -0
- package/payload/server/client-pool-GBY5I2KQ.js +31 -0
- package/payload/server/maxy-edge.js +3 -3
- package/payload/server/neo4j-migrations-STCKDWAL.js +364 -0
- package/payload/server/public/assets/{admin-Cxtmv0wo.js → admin-CdVYoqKD.js} +20 -20
- package/payload/server/public/assets/{graph-C4-jEPDE.js → graph-DeH6ulGh.js} +1 -1
- package/payload/server/public/assets/{page-zuI00fuC.js → page-WIAWD2Oi.js} +1 -1
- package/payload/server/public/graph.html +2 -2
- package/payload/server/public/index.html +2 -2
- package/payload/server/server.js +326 -2236
package/package.json
CHANGED
|
@@ -61,7 +61,7 @@ const EXCLUDED_FROM_INDEX = new Set(["Trashed", "GraphPreference"]);
|
|
|
61
61
|
* writer means extending this list AND the schema's `ON EACH [...]` clause.
|
|
62
62
|
* Discovered via codebase sweep during Task 748 across `memory-write`,
|
|
63
63
|
* `memory-archive-write`, `memory-ingest`, `email-store`, `neo4j-store`,
|
|
64
|
-
* `workflow-create`, `tool-call-writer
|
|
64
|
+
* `workflow-create`, `tool-call-writer`.
|
|
65
65
|
*/
|
|
66
66
|
const CANONICAL_TEXT_PROPERTIES = [
|
|
67
67
|
// Generic
|
|
@@ -14,6 +14,11 @@ export * from "./audit.js";
|
|
|
14
14
|
* hourly [graph-health] signal):
|
|
15
15
|
* - zero relationships → `[graph-write] reject reason=zero-relationships`
|
|
16
16
|
* - unresolved target id → `[graph-write] reject reason=unresolved-target`
|
|
17
|
+
* - removed-feature write → `[graph-write] reject reason=removed-feature`
|
|
18
|
+
* (Task 884 — `:ReviewAlert` and `:Event {actionTool:"review-digest-compose"}`
|
|
19
|
+
* are deleted features; the gate catches doctrine-compliant writers
|
|
20
|
+
* re-introducing them. The vitest tombstone grep is the primary fence
|
|
21
|
+
* for raw `session.run("MERGE …")` callers that bypass this primitive.)
|
|
17
22
|
*
|
|
18
23
|
* The `createdBy.agent` field is advisory, not authoritative — it is sourced
|
|
19
24
|
* from the MCP server's AGENT_SLUG env var, which is set by the trusted
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,cAAc,YAAY,CAAC;AAE3B
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,cAAc,YAAY,CAAC;AAE3B;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,UAAU,GAAG,UAAU,CAAC;IACnC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6FAA6F;IAC7F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uFAAuF;IACvF,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,4EAA4E;IAC5E,aAAa,EAAE,iBAAiB,EAAE,CAAC;IACnC,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,uDAAuD;AACvD,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,EAAE,SAAS,GACnB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQzB;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,wBAAwB,GAC/B,OAAO,CAAC,eAAe,CAAC,CAkI1B"}
|
|
@@ -40,6 +40,20 @@ async function writeNodeWithEdges(params) {
|
|
|
40
40
|
const { session, labels, props, relationships, createdBy } = params;
|
|
41
41
|
const agentLabel = createdBy.agent ?? createdBy.source ?? "unknown";
|
|
42
42
|
const labelCsv = labels.join(",");
|
|
43
|
+
// Task 884: review-detector / review-digest feature is removed entirely.
|
|
44
|
+
// Reject any re-introduction via the doctrine surface. The actionTool check
|
|
45
|
+
// is property-keyed (not label-keyed) so a future scheduled-Event writer
|
|
46
|
+
// re-introducing the daily digest by tool name is caught here even though
|
|
47
|
+
// `:Event` is otherwise a valid label. Fires before the zero-relationships
|
|
48
|
+
// check because the dead-feature rejection is structurally more fundamental.
|
|
49
|
+
const reviewDigestActionTool = typeof props.actionTool === "string" && props.actionTool === "review-digest-compose";
|
|
50
|
+
if (labels.includes("ReviewAlert") || reviewDigestActionTool) {
|
|
51
|
+
const actionToolField = reviewDigestActionTool
|
|
52
|
+
? "review-digest-compose"
|
|
53
|
+
: "n/a";
|
|
54
|
+
process.stderr.write(`[graph-write] reject reason=removed-feature labels=${labelCsv} actionTool=${actionToolField} agent=${agentLabel}\n`);
|
|
55
|
+
throw new Error("Write doctrine violated: review-detector feature removed (Task 884) — `:ReviewAlert` and `:Event {actionTool:'review-digest-compose'}` writes are not allowed.");
|
|
56
|
+
}
|
|
43
57
|
if (!relationships || relationships.length < 1) {
|
|
44
58
|
process.stderr.write(`[graph-write] reject reason=zero-relationships labels=${labelCsv} agent=${agentLabel}\n`);
|
|
45
59
|
throw new Error("Write doctrine violated: a node must be created with at least one relationship. See .docs/neo4j.md (Write doctrine).");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,6 +18,11 @@ export * from "./audit.js";
|
|
|
18
18
|
* hourly [graph-health] signal):
|
|
19
19
|
* - zero relationships → `[graph-write] reject reason=zero-relationships`
|
|
20
20
|
* - unresolved target id → `[graph-write] reject reason=unresolved-target`
|
|
21
|
+
* - removed-feature write → `[graph-write] reject reason=removed-feature`
|
|
22
|
+
* (Task 884 — `:ReviewAlert` and `:Event {actionTool:"review-digest-compose"}`
|
|
23
|
+
* are deleted features; the gate catches doctrine-compliant writers
|
|
24
|
+
* re-introducing them. The vitest tombstone grep is the primary fence
|
|
25
|
+
* for raw `session.run("MERGE …")` callers that bypass this primitive.)
|
|
21
26
|
*
|
|
22
27
|
* The `createdBy.agent` field is advisory, not authoritative — it is sourced
|
|
23
28
|
* from the MCP server's AGENT_SLUG env var, which is set by the trusted
|
|
@@ -88,6 +93,26 @@ export async function writeNodeWithEdges(
|
|
|
88
93
|
const agentLabel = createdBy.agent ?? createdBy.source ?? "unknown";
|
|
89
94
|
const labelCsv = labels.join(",");
|
|
90
95
|
|
|
96
|
+
// Task 884: review-detector / review-digest feature is removed entirely.
|
|
97
|
+
// Reject any re-introduction via the doctrine surface. The actionTool check
|
|
98
|
+
// is property-keyed (not label-keyed) so a future scheduled-Event writer
|
|
99
|
+
// re-introducing the daily digest by tool name is caught here even though
|
|
100
|
+
// `:Event` is otherwise a valid label. Fires before the zero-relationships
|
|
101
|
+
// check because the dead-feature rejection is structurally more fundamental.
|
|
102
|
+
const reviewDigestActionTool =
|
|
103
|
+
typeof props.actionTool === "string" && props.actionTool === "review-digest-compose";
|
|
104
|
+
if (labels.includes("ReviewAlert") || reviewDigestActionTool) {
|
|
105
|
+
const actionToolField = reviewDigestActionTool
|
|
106
|
+
? "review-digest-compose"
|
|
107
|
+
: "n/a";
|
|
108
|
+
process.stderr.write(
|
|
109
|
+
`[graph-write] reject reason=removed-feature labels=${labelCsv} actionTool=${actionToolField} agent=${agentLabel}\n`
|
|
110
|
+
);
|
|
111
|
+
throw new Error(
|
|
112
|
+
"Write doctrine violated: review-detector feature removed (Task 884) — `:ReviewAlert` and `:Event {actionTool:'review-digest-compose'}` writes are not allowed."
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
91
116
|
if (!relationships || relationships.length < 1) {
|
|
92
117
|
process.stderr.write(
|
|
93
118
|
`[graph-write] reject reason=zero-relationships labels=${labelCsv} agent=${agentLabel}\n`
|
|
@@ -96,14 +96,6 @@
|
|
|
96
96
|
"direction": "(Email)-[:RECEIVED_BY]->(Person)",
|
|
97
97
|
"note": "Email recipient."
|
|
98
98
|
},
|
|
99
|
-
"RAISED_BY": {
|
|
100
|
-
"direction": "(ReviewAlert)-[:RAISED_BY]->(*)",
|
|
101
|
-
"note": "Alert provenance."
|
|
102
|
-
},
|
|
103
|
-
"AFFECTS": {
|
|
104
|
-
"direction": "(ReviewAlert)-[:AFFECTS]->(*)",
|
|
105
|
-
"note": "Alert impact surface."
|
|
106
|
-
},
|
|
107
99
|
"BLOCKS": {
|
|
108
100
|
"direction": "(Task)-[:BLOCKS]->(Task)",
|
|
109
101
|
"note": "Task dependency."
|
|
@@ -5,10 +5,9 @@
|
|
|
5
5
|
* `${DATA_ROOT}/accounts/<uuid>/account.json`. Idempotent — silent when
|
|
6
6
|
* the graph is already clean.
|
|
7
7
|
*
|
|
8
|
-
* Why a backstop, not a writer fix: the leaked nodes were written by
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* surface that catches future writer drift before the next gbrain ships.
|
|
8
|
+
* Why a backstop, not a writer fix: the leaked nodes were written by a
|
|
9
|
+
* since-removed writer. With no live writer to fix, this is the surface
|
|
10
|
+
* that catches future writer drift.
|
|
12
11
|
*
|
|
13
12
|
* Hard guard: refuses to run when the on-disk account set is empty
|
|
14
13
|
* (corrupt-install scenario). Refusing to wipe the graph is louder than
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration 005 — Remove review-detector / review-digest feature artefacts (Task 884).
|
|
3
|
+
*
|
|
4
|
+
* The review-detector subsystem was wired into boot, MERGEd a daily `:Event`
|
|
5
|
+
* with `actionTool="review-digest-compose"` on every start, and aggregated
|
|
6
|
+
* `:ReviewAlert` nodes via rule matches. The feature is deleted entirely;
|
|
7
|
+
* this migration is the boot-sweep that removes the residue from existing
|
|
8
|
+
* installs. Idempotent — once the graph is clean, both queries DETACH DELETE
|
|
9
|
+
* zero rows and the log line records `events=0 alerts=0`.
|
|
10
|
+
*
|
|
11
|
+
* Filesystem artefacts (`review.log`, `review-rules.json`, `review-state.json`,
|
|
12
|
+
* `review-pending-alerts.jsonl`) are also removed best-effort — ENOENT is the
|
|
13
|
+
* idempotent no-op; any other errno is logged and ignored so a sticky permission
|
|
14
|
+
* problem does not block boot.
|
|
15
|
+
*
|
|
16
|
+
* Same structural-type pattern as 004-prune-alien-accounts.ts: the runner sits
|
|
17
|
+
* outside `platform/ui/` so depending on the workspace dedupe state the
|
|
18
|
+
* `neo4j-driver` import resolves to a different node_modules copy, and TS
|
|
19
|
+
* treats two same-shape types from different paths as nominally distinct.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { resolve } from "node:path";
|
|
23
|
+
import { unlinkSync } from "node:fs";
|
|
24
|
+
import { homedir } from "node:os";
|
|
25
|
+
import { basename, dirname } from "node:path";
|
|
26
|
+
|
|
27
|
+
type Neo4jDriverLike = {
|
|
28
|
+
session(): {
|
|
29
|
+
run(
|
|
30
|
+
cypher: string,
|
|
31
|
+
params?: Record<string, unknown>,
|
|
32
|
+
): Promise<{ records: Array<{ get(key: string): unknown }> }>;
|
|
33
|
+
close(): Promise<void>;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export async function removeReviewFeature(
|
|
38
|
+
driver: Neo4jDriverLike,
|
|
39
|
+
platformRoot: string,
|
|
40
|
+
): Promise<void> {
|
|
41
|
+
const session = driver.session();
|
|
42
|
+
let eventsDeleted = 0;
|
|
43
|
+
let alertsDeleted = 0;
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
const eventResult = await session.run(
|
|
47
|
+
`MATCH (e:Event)
|
|
48
|
+
WHERE e.actionTool = "review-digest-compose"
|
|
49
|
+
OR e.eventId STARTS WITH "review-digest-"
|
|
50
|
+
DETACH DELETE e
|
|
51
|
+
RETURN count(e) AS deleted`,
|
|
52
|
+
);
|
|
53
|
+
eventsDeleted = toNumber(eventResult.records[0]?.get("deleted"));
|
|
54
|
+
|
|
55
|
+
const alertResult = await session.run(
|
|
56
|
+
`MATCH (a:ReviewAlert)
|
|
57
|
+
DETACH DELETE a
|
|
58
|
+
RETURN count(a) AS deleted`,
|
|
59
|
+
);
|
|
60
|
+
alertsDeleted = toNumber(alertResult.records[0]?.get("deleted"));
|
|
61
|
+
} finally {
|
|
62
|
+
await session.close();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Best-effort filesystem cleanup. The configDir convention is
|
|
66
|
+
// `~/.<installDirName>` where installDir = dirname(platformRoot)
|
|
67
|
+
// (e.g. `~/maxy/platform` → `~/.maxy`).
|
|
68
|
+
const installDirName = basename(dirname(platformRoot));
|
|
69
|
+
const configDir = resolve(homedir(), `.${installDirName}`);
|
|
70
|
+
const artefacts = [
|
|
71
|
+
resolve(configDir, "logs", "review.log"),
|
|
72
|
+
resolve(configDir, "review-rules.json"),
|
|
73
|
+
resolve(configDir, "review-state.json"),
|
|
74
|
+
resolve(configDir, "review-pending-alerts.jsonl"),
|
|
75
|
+
];
|
|
76
|
+
for (const path of artefacts) {
|
|
77
|
+
try {
|
|
78
|
+
unlinkSync(path);
|
|
79
|
+
} catch (err) {
|
|
80
|
+
const code = (err as NodeJS.ErrnoException).code;
|
|
81
|
+
if (code === "ENOENT") continue;
|
|
82
|
+
console.error(
|
|
83
|
+
`[migration] removed-review-feature unlink-skip path=${path} reason=${code ?? "unknown"}`,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
console.error(
|
|
89
|
+
`[migration] removed-review-feature events=${eventsDeleted} alerts=${alertsDeleted}`,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function toNumber(v: unknown): number {
|
|
94
|
+
if (typeof v === "number") return v;
|
|
95
|
+
if (
|
|
96
|
+
v &&
|
|
97
|
+
typeof (v as { toNumber?: () => number }).toNumber === "function"
|
|
98
|
+
) {
|
|
99
|
+
return (v as { toNumber: () => number }).toNumber();
|
|
100
|
+
}
|
|
101
|
+
return 0;
|
|
102
|
+
}
|
|
@@ -284,7 +284,6 @@ OPTIONS {
|
|
|
284
284
|
// - Workflows: Workflow, WorkflowStep, WorkflowRun, StepResult
|
|
285
285
|
// - Onboarding: OnboardingState
|
|
286
286
|
// - Email: Email, EmailAccount
|
|
287
|
-
// - Review signals: ReviewAlert
|
|
288
287
|
// - CV/career sublabels: Position, Credential
|
|
289
288
|
// - Public agents: Agent (Task 837 — projection of file-based public agents)
|
|
290
289
|
//
|
|
@@ -314,7 +313,7 @@ FOR (n:LocalBusiness|Service|PriceSpecification|OpeningHoursSpecification|Organi
|
|
|
314
313
|
|Conversation|AdminConversation|PublicConversation|Message|UserMessage|AssistantMessage|ToolCall
|
|
315
314
|
|Task|Project|Event
|
|
316
315
|
|Workflow|WorkflowStep|WorkflowRun|StepResult
|
|
317
|
-
|OnboardingState|Email|EmailAccount
|
|
316
|
+
|OnboardingState|Email|EmailAccount
|
|
318
317
|
|Position|Credential|Agent)
|
|
319
318
|
ON EACH [n.name, n.firstName, n.lastName, n.givenName, n.familyName,
|
|
320
319
|
n.title, n.currentTitle, n.summary, n.body, n.content, n.text, n.description, n.headline, n.abstract,
|
|
@@ -832,26 +831,6 @@ FOR (au:AdminUser) REQUIRE au.userId IS UNIQUE;
|
|
|
832
831
|
CREATE INDEX graph_preference_account_user IF NOT EXISTS
|
|
833
832
|
FOR (p:GraphPreference) ON (p.accountId, p.userId);
|
|
834
833
|
|
|
835
|
-
// ----------------------------------------------------------
|
|
836
|
-
// ReviewAlert — review-detector rule-match aggregation
|
|
837
|
-
//
|
|
838
|
-
// One alert per (accountId, ruleId); subsequent rule matches bump
|
|
839
|
-
// lastMatchAt and cumulativeMatchCount via ON MATCH. Written by
|
|
840
|
-
// platform/ui/app/lib/review-detector/writer.ts, read by the admin
|
|
841
|
-
// chat's alert-surfacing tools. Listed in FILTER_EXCLUDED_LABELS
|
|
842
|
-
// (graph-labels.ts, Task 626) so it never surfaces as a /graph filter
|
|
843
|
-
// row, but registered in GRAPH_LABEL_COLOURS so neighbourhood-mode
|
|
844
|
-
// drilldown / search hits can still render it.
|
|
845
|
-
//
|
|
846
|
-
// Composite MERGE key (accountId, ruleId) — no UNIQUE constraint for
|
|
847
|
-
// the same reason as GraphPreference: the composite MERGE is
|
|
848
|
-
// idempotent and a composite constraint would add schema surface
|
|
849
|
-
// for no behavioural gain.
|
|
850
|
-
// ----------------------------------------------------------
|
|
851
|
-
|
|
852
|
-
CREATE INDEX review_alert_account_rule IF NOT EXISTS
|
|
853
|
-
FOR (a:ReviewAlert) ON (a.accountId, a.ruleId);
|
|
854
|
-
|
|
855
834
|
// ----------------------------------------------------------
|
|
856
835
|
// ToolCall — durable audit trail for agent tool invocations
|
|
857
836
|
//
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: admin
|
|
3
|
-
description: "Platform administration plugin. Provides system-status, brand-settings, account-manage, account-update, admin-add, admin-remove, admin-list, admin-update-pin, agent-list, agent-config-read, logs-read, plugin-read, render-component, session-reset, session-resume, file-attach, wifi,
|
|
3
|
+
description: "Platform administration plugin. Provides system-status, brand-settings, account-manage, account-update, admin-add, admin-remove, admin-list, admin-update-pin, agent-list, agent-config-read, logs-read, plugin-read, render-component, session-reset, session-resume, file-attach, wifi, adherence-read (attention-weighted adherence ledger), and action-approval tools (action-pending, action-approve, action-reject, action-edit) for managing the Maxy platform."
|
|
4
4
|
tools:
|
|
5
5
|
- system-status
|
|
6
6
|
- brand-settings
|
|
@@ -18,12 +18,6 @@ tools:
|
|
|
18
18
|
- session-reset
|
|
19
19
|
- session-resume
|
|
20
20
|
- file-attach
|
|
21
|
-
- review-rules-list
|
|
22
|
-
- review-rules-suppress
|
|
23
|
-
- review-rules-unsuppress
|
|
24
|
-
- review-rules-add
|
|
25
|
-
- review-rules-remove
|
|
26
|
-
- review-alerts-recent
|
|
27
21
|
- adherence-read
|
|
28
22
|
- action-pending
|
|
29
23
|
- action-approve
|
|
@@ -40,7 +34,6 @@ hidden:
|
|
|
40
34
|
- onboarding-step9-mode
|
|
41
35
|
- qr-generate
|
|
42
36
|
- wifi
|
|
43
|
-
- review-digest-compose
|
|
44
37
|
always: true
|
|
45
38
|
embed: false
|
|
46
39
|
---
|
|
@@ -17,7 +17,6 @@ import { homedir, hostname as osHostname } from "node:os";
|
|
|
17
17
|
import QRCode from "qrcode";
|
|
18
18
|
import { getSession, closeDriver } from "./lib/neo4j.js";
|
|
19
19
|
import { getOnboardingState, completeOnboardingStep } from "./lib/onboarding.js";
|
|
20
|
-
import { registerReviewTools } from "./lib/review-tools.js";
|
|
21
20
|
const server = new McpServer({
|
|
22
21
|
name: "admin",
|
|
23
22
|
version: "0.1.0",
|
|
@@ -1179,8 +1178,8 @@ server.tool("agent-list", "List all public (non-admin) agents with their full co
|
|
|
1179
1178
|
};
|
|
1180
1179
|
}
|
|
1181
1180
|
});
|
|
1182
|
-
server.tool("logs-read", "Read recent logs. Task 532: the stream logs (type=agent-stream/error/session/public) are now per-conversation — pass `conversationId` to retrieve a single conversation's log from first [spawn] to final [process-exit]. type=agent-stream: per-conversation tool-use/tool-result archive (every `[tool-use]` and `[tool-result]` pair with full input + output JSON, plus raw Claude stream-json, agent events, and MCP server stderr via tee). USE THIS when investigating what an agent ACTUALLY did with its tools — server.log only carries `[persist] tool-call persisted` markers, not bodies. (`type=system` is a backwards-compatible alias for the same archive.) type=session: SSE events sent to client. type=error: Claude subprocess stderr (raw — NODE_DEBUG HTTP/NET/UNDICI traces land in agent-stream via the stream tee, not here). type=heartbeat: platform event dispatcher (check-due-events cron). type=public: public agent diagnostic log. type=server: platform server log. type=mcp: MCP server stderr (per-plugin raw). type=vnc: VNC browser viewer lifecycle.
|
|
1183
|
-
type: z.enum(["agent-stream", "system", "session", "error", "heartbeat", "public", "server", "mcp", "vnc"
|
|
1181
|
+
server.tool("logs-read", "Read recent logs. Task 532: the stream logs (type=agent-stream/error/session/public) are now per-conversation — pass `conversationId` to retrieve a single conversation's log from first [spawn] to final [process-exit]. type=agent-stream: per-conversation tool-use/tool-result archive (every `[tool-use]` and `[tool-result]` pair with full input + output JSON, plus raw Claude stream-json, agent events, and MCP server stderr via tee). USE THIS when investigating what an agent ACTUALLY did with its tools — server.log only carries `[persist] tool-call persisted` markers, not bodies. (`type=system` is a backwards-compatible alias for the same archive.) type=session: SSE events sent to client. type=error: Claude subprocess stderr (raw — NODE_DEBUG HTTP/NET/UNDICI traces land in agent-stream via the stream tee, not here). type=heartbeat: platform event dispatcher (check-due-events cron). type=public: public agent diagnostic log. type=server: platform server log. type=mcp: MCP server stderr (per-plugin raw). type=vnc: VNC browser viewer lifecycle. sessionKey: grep legacy sessionKey-tagged lines across all logs (useful for pre-Task-532 artefacts). When conversationId is provided, reads the single per-conversation file for the requested type (or dumps all type files for that conversationId if type is omitted).", {
|
|
1182
|
+
type: z.enum(["agent-stream", "system", "session", "error", "heartbeat", "public", "server", "mcp", "vnc"]).optional(),
|
|
1184
1183
|
lines: z.number().optional(),
|
|
1185
1184
|
sessionKey: z.string().optional(),
|
|
1186
1185
|
conversationId: z.string().optional(),
|
|
@@ -1223,7 +1222,7 @@ server.tool("logs-read", "Read recent logs. Task 532: the stream logs (type=agen
|
|
|
1223
1222
|
const prefix = prefixMap[resolvedType];
|
|
1224
1223
|
if (!prefix) {
|
|
1225
1224
|
return {
|
|
1226
|
-
content: [{ type: "text", text: `type=${resolvedType} is not per-conversation. Valid per-conversation types: agent-stream, error, session, public. For platform-scoped types (server, vnc,
|
|
1225
|
+
content: [{ type: "text", text: `type=${resolvedType} is not per-conversation. Valid per-conversation types: agent-stream, error, session, public. For platform-scoped types (server, vnc, heartbeat, mcp) omit conversationId.` }],
|
|
1227
1226
|
isError: true,
|
|
1228
1227
|
};
|
|
1229
1228
|
}
|
|
@@ -1276,11 +1275,11 @@ server.tool("logs-read", "Read recent logs. Task 532: the stream logs (type=agen
|
|
|
1276
1275
|
};
|
|
1277
1276
|
// When a type is explicitly provided, search only that type's files.
|
|
1278
1277
|
// When type is omitted, search all prefix-based log types (excludes heartbeat — no session context).
|
|
1279
|
-
// server
|
|
1278
|
+
// server and vnc are single-file (configDir-scoped), so they have no prefix search;
|
|
1280
1279
|
// their matches are produced by dedicated blocks below.
|
|
1281
|
-
const searchPrefixes = type && type !== "heartbeat" && type !== "server" && type !== "vnc" &&
|
|
1280
|
+
const searchPrefixes = type && type !== "heartbeat" && type !== "server" && type !== "vnc" && prefixes[type]
|
|
1282
1281
|
? { [type]: prefixes[type] }
|
|
1283
|
-
: (type === "server" || type === "vnc"
|
|
1282
|
+
: (type === "server" || type === "vnc") ? {} : prefixes;
|
|
1284
1283
|
const allFiles = readdirSync(LOG_DIR).filter(f => f.endsWith(".log"));
|
|
1285
1284
|
const sections = [];
|
|
1286
1285
|
// Search account-scoped prefix-based log files
|
|
@@ -1341,25 +1340,6 @@ server.tool("logs-read", "Read recent logs. Task 532: the stream logs (type=agen
|
|
|
1341
1340
|
}
|
|
1342
1341
|
}
|
|
1343
1342
|
}
|
|
1344
|
-
// Search review.log (platform-scoped, in configDir) — the
|
|
1345
|
-
// proactive log-review detector's self-log (Task 385).
|
|
1346
|
-
const includeReview = !type || type === "review";
|
|
1347
|
-
if (includeReview) {
|
|
1348
|
-
const reviewLog = resolve(CONFIG_DIR, "logs", "review.log");
|
|
1349
|
-
if (existsSync(reviewLog)) {
|
|
1350
|
-
try {
|
|
1351
|
-
const result = execFileSync("grep", ["-F", sessionKey, reviewLog], { timeout: 5000 }).toString().trim();
|
|
1352
|
-
if (result) {
|
|
1353
|
-
sections.push(`## review.log (review)\n${result}`);
|
|
1354
|
-
}
|
|
1355
|
-
}
|
|
1356
|
-
catch (grepErr) {
|
|
1357
|
-
const exitCode = grepErr.status;
|
|
1358
|
-
if (exitCode !== 1)
|
|
1359
|
-
throw grepErr;
|
|
1360
|
-
}
|
|
1361
|
-
}
|
|
1362
|
-
}
|
|
1363
1343
|
if (sections.length === 0) {
|
|
1364
1344
|
return { content: [{ type: "text", text: `No log lines found for session key "${sessionKey}".` }] };
|
|
1365
1345
|
}
|
|
@@ -1401,20 +1381,6 @@ server.tool("logs-read", "Read recent logs. Task 532: the stream logs (type=agen
|
|
|
1401
1381
|
}).toString();
|
|
1402
1382
|
return { content: [{ type: "text", text: `# vnc-boot.log\n\n${result}` }] };
|
|
1403
1383
|
}
|
|
1404
|
-
// Review log is a single platform-scoped file written by the in-process
|
|
1405
|
-
// review detector (Task 385). Every scan cycle, rule match, suppression,
|
|
1406
|
-
// rate-limit decision, admin-tool rule mutation, and watchdog event is
|
|
1407
|
-
// here. Use this to answer "did the detector see X?" questions.
|
|
1408
|
-
if (resolvedType === "review") {
|
|
1409
|
-
const reviewLogFile = resolve(CONFIG_DIR, "logs", "review.log");
|
|
1410
|
-
if (!existsSync(reviewLogFile)) {
|
|
1411
|
-
return { content: [{ type: "text", text: `No review log found at ${reviewLogFile} (detector may not have started yet)` }] };
|
|
1412
|
-
}
|
|
1413
|
-
const result = execFileSync("tail", ["-n", String(lines), reviewLogFile], {
|
|
1414
|
-
timeout: 5000,
|
|
1415
|
-
}).toString();
|
|
1416
|
-
return { content: [{ type: "text", text: `# review.log\n\n${result}` }] };
|
|
1417
|
-
}
|
|
1418
1384
|
// Task 850 — agent-stream and the legacy system alias both map to
|
|
1419
1385
|
// claude-agent-stream-. The fall-through default also covers them.
|
|
1420
1386
|
const prefix = resolvedType === "error" ? "claude-agent-stderr-"
|
|
@@ -3229,10 +3195,6 @@ server.tool("adherence-read", "Read the attention-weighted adherence ledger for
|
|
|
3229
3195
|
};
|
|
3230
3196
|
}
|
|
3231
3197
|
});
|
|
3232
|
-
// Review cadence tools (Task 385) — list, suppress, add, remove, etc.
|
|
3233
|
-
// Registered as the final tool bundle because they depend on CONFIG_DIR
|
|
3234
|
-
// and ACCOUNT_ID being resolved above.
|
|
3235
|
-
registerReviewTools(server, { configDir: CONFIG_DIR, accountId: ACCOUNT_ID });
|
|
3236
3198
|
// Cleanup on exit (SIGTERM for systemd service stops on Pi)
|
|
3237
3199
|
const cleanup = async () => {
|
|
3238
3200
|
await closeDriver();
|