@rubytech/create-maxy-code 0.1.132 → 0.1.138
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/__tests__/installer-specialist-registration.test.js +5 -40
- package/dist/index.js +24 -28
- package/dist/specialist-registration.js +0 -15
- package/package.json +1 -1
- package/payload/platform/lib/graph-search/dist/boosts.d.ts +39 -0
- package/payload/platform/lib/graph-search/dist/boosts.d.ts.map +1 -0
- package/payload/platform/lib/graph-search/dist/boosts.js +57 -0
- package/payload/platform/lib/graph-search/dist/boosts.js.map +1 -0
- package/payload/platform/lib/graph-search/dist/dedup.d.ts +29 -0
- package/payload/platform/lib/graph-search/dist/dedup.d.ts.map +1 -0
- package/payload/platform/lib/graph-search/dist/dedup.js +97 -0
- package/payload/platform/lib/graph-search/dist/dedup.js.map +1 -0
- package/payload/platform/lib/graph-search/dist/index.d.ts +70 -8
- package/payload/platform/lib/graph-search/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/graph-search/dist/index.js +323 -62
- package/payload/platform/lib/graph-search/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-search/dist/query-expansion.d.ts +37 -0
- package/payload/platform/lib/graph-search/dist/query-expansion.d.ts.map +1 -0
- package/payload/platform/lib/graph-search/dist/query-expansion.js +101 -0
- package/payload/platform/lib/graph-search/dist/query-expansion.js.map +1 -0
- package/payload/platform/lib/graph-search/dist/route.d.ts +29 -0
- package/payload/platform/lib/graph-search/dist/route.d.ts.map +1 -0
- package/payload/platform/lib/graph-search/dist/route.js +53 -0
- package/payload/platform/lib/graph-search/dist/route.js.map +1 -0
- package/payload/platform/lib/graph-search/dist/rrf-fusion.d.ts +31 -0
- package/payload/platform/lib/graph-search/dist/rrf-fusion.d.ts.map +1 -0
- package/payload/platform/lib/graph-search/dist/rrf-fusion.js +57 -0
- package/payload/platform/lib/graph-search/dist/rrf-fusion.js.map +1 -0
- package/payload/platform/lib/graph-search/src/__tests__/boosts.test.ts +59 -0
- package/payload/platform/lib/graph-search/src/__tests__/dedup.test.ts +83 -0
- package/payload/platform/lib/graph-search/src/__tests__/query-expansion.test.ts +96 -0
- package/payload/platform/lib/graph-search/src/__tests__/route.test.ts +62 -0
- package/payload/platform/lib/graph-search/src/__tests__/rrf-fusion.test.ts +39 -0
- package/payload/platform/lib/graph-search/src/boosts.ts +61 -0
- package/payload/platform/lib/graph-search/src/dedup.ts +108 -0
- package/payload/platform/lib/graph-search/src/index.ts +407 -65
- package/payload/platform/lib/graph-search/src/query-expansion.ts +129 -0
- package/payload/platform/lib/graph-search/src/route.ts +70 -0
- package/payload/platform/lib/graph-search/src/rrf-fusion.ts +62 -0
- package/payload/platform/neo4j/schema.cypher +80 -1
- package/payload/platform/plugins/admin/hooks/session-end-retrospective.sh +4 -2
- package/payload/platform/plugins/admin/mcp/dist/index.js +6 -4
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/docs/references/internals.md +36 -10
- package/payload/platform/plugins/docs/references/neo4j.md +63 -0
- package/payload/platform/plugins/docs/references/session-retrospective.md +11 -4
- package/payload/platform/plugins/graph-viewer/mcp/dist/tools/graph-render.js +2 -2
- package/payload/platform/plugins/graph-viewer/mcp/dist/tools/graph-render.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/index.js +114 -5
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-property.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-property.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-property.test.js +25 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-property.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/timeline-extractor.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/timeline-extractor.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/timeline-extractor.test.js +70 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/timeline-extractor.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/typed-edge-schema.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/typed-edge-schema.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/typed-edge-schema.test.js +50 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/typed-edge-schema.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-rewriter.d.ts +33 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-rewriter.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-rewriter.js +99 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-rewriter.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/graph-write-gate.d.ts +21 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/graph-write-gate.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/graph-write-gate.js +24 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/graph-write-gate.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/timeline-extractor.d.ts +13 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/timeline-extractor.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/timeline-extractor.js +151 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/timeline-extractor.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-pass.d.ts +55 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-pass.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-pass.js +290 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-pass.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-schema.d.ts +19 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-schema.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-schema.js +102 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-schema.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.js +18 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.js +5 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.js +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js +14 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.d.ts +29 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.js +22 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.d.ts +31 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.js +182 -50
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js +76 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.d.ts +30 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.js +129 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/scripts/backfill-typed-edges.ts +72 -0
- package/payload/platform/plugins/memory/mcp/scripts/generate-edge-docs.ts +75 -0
- package/payload/platform/plugins/memory/mcp/vitest.config.ts +5 -0
- package/payload/platform/plugins/memory/references/schema-base.md +44 -0
- package/payload/platform/scripts/seed-neo4j.sh +49 -0
- package/payload/platform/templates/agents/admin/IDENTITY.md +4 -3
- package/payload/platform/templates/specialists/agents/database-operator.md +9 -1
- package/payload/server/{adminuser-self-heal-QAWOZ3JV.js → adminuser-self-heal-YC47O34W.js} +2 -1
- package/payload/server/{chunk-JSBRDJBE.js → chunk-HYQNUVGO.js} +9 -1
- package/payload/server/{chunk-HCYM5FLU.js → chunk-T3DJD5QR.js} +3 -1
- package/payload/server/maxy-edge.js +3 -2
- package/payload/server/public/assets/{admin-FcRHAL-3.js → admin-BM9aXUUh.js} +1 -1
- package/payload/server/public/assets/{data-Ds37mflX.js → data-Ds2ECtfP.js} +1 -1
- package/payload/server/public/assets/{graph-CmWRhaiS.js → graph-BzxObKMM.js} +1 -1
- package/payload/server/public/assets/{graph-labels-Ch2r00Gt.js → graph-labels-Dwgep_nr.js} +1 -1
- package/payload/server/public/assets/{page-BcHhJXUt.js → page-BlkBsjP2.js} +1 -1
- package/payload/server/public/assets/page-h_SA5SVQ.js +51 -0
- package/payload/server/public/data.html +3 -3
- package/payload/server/public/graph.html +3 -3
- package/payload/server/public/index.html +4 -4
- package/payload/server/server.js +803 -76
- package/payload/server/public/assets/page-BOtNny_4.js +0 -51
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session-retrospective skip-rate visibility tool.
|
|
3
|
+
*
|
|
4
|
+
* Called by the admin agent at session start. Returns the ratio of recent
|
|
5
|
+
* sessions that closed without calling `session-retrospective-mark-complete`
|
|
6
|
+
* — sessions where the typed-edge pass, learnings pass, and SOUL.md pass
|
|
7
|
+
* never ran. The admin agent surfaces the result to the operator if the
|
|
8
|
+
* rate is non-zero so closing via Sidebar Archive / tab-close becomes a
|
|
9
|
+
* visible cost rather than a silent one.
|
|
10
|
+
*
|
|
11
|
+
* Mechanism: count `:Conversation` nodes for this account in the recent
|
|
12
|
+
* window; count those whose corresponding session log contains the
|
|
13
|
+
* sentinel tool-use of `session-retrospective-mark-complete`. The ratio
|
|
14
|
+
* is the skip rate. Pending nodes (prose with `updatedAt` later than the
|
|
15
|
+
* most-recent completed retrospective) carry the deferred typed-edge work
|
|
16
|
+
* that will land at the next /end.
|
|
17
|
+
*/
|
|
18
|
+
export async function sessionRetrospectiveSkipRate(args, session, accountId) {
|
|
19
|
+
const windowSize = Math.max(1, Math.min(args.windowSize ?? 10, 100));
|
|
20
|
+
// Conversations carry `retrospectiveCompletedAt` when the sentinel tool
|
|
21
|
+
// fired (set by the admin mark-complete tool through log-ingest +
|
|
22
|
+
// platform/ui session writer). When the property is null/missing, the
|
|
23
|
+
// retrospective was skipped.
|
|
24
|
+
// The oldest-pending bound is the earliest updatedAt across prose nodes
|
|
25
|
+
// for this account whose updatedAt is *after* the most-recent completed
|
|
26
|
+
// retrospective — i.e. nodes the next session's pass will pick up.
|
|
27
|
+
const cypher = `
|
|
28
|
+
CALL {
|
|
29
|
+
MATCH (c:Conversation {accountId: $accountId})
|
|
30
|
+
RETURN c
|
|
31
|
+
ORDER BY c.updatedAt DESC
|
|
32
|
+
LIMIT $windowSize
|
|
33
|
+
}
|
|
34
|
+
WITH collect(c) AS recent
|
|
35
|
+
WITH recent,
|
|
36
|
+
[c IN recent WHERE c.retrospectiveCompletedAt IS NOT NULL] AS done,
|
|
37
|
+
[c IN recent WHERE c.retrospectiveCompletedAt IS NOT NULL | c.retrospectiveCompletedAt]
|
|
38
|
+
AS doneTimestamps
|
|
39
|
+
WITH size(recent) AS windowSessions,
|
|
40
|
+
size(done) AS completedRetrospectives,
|
|
41
|
+
CASE WHEN size(doneTimestamps) > 0
|
|
42
|
+
THEN apoc.coll.max(doneTimestamps)
|
|
43
|
+
ELSE null END AS lastCompletedAt
|
|
44
|
+
OPTIONAL MATCH (n)
|
|
45
|
+
WHERE n.accountId = $accountId
|
|
46
|
+
AND ANY(l IN labels(n) WHERE l IN $proseLabels)
|
|
47
|
+
AND (lastCompletedAt IS NULL OR n.updatedAt > lastCompletedAt)
|
|
48
|
+
WITH windowSessions, completedRetrospectives, min(n.updatedAt) AS oldestPending
|
|
49
|
+
RETURN windowSessions, completedRetrospectives, oldestPending
|
|
50
|
+
`;
|
|
51
|
+
// APOC is bundled with the Maxy Neo4j install. If unavailable, fall back to
|
|
52
|
+
// a pure-Cypher variant that uses reduce() for max.
|
|
53
|
+
const fallbackCypher = `
|
|
54
|
+
CALL {
|
|
55
|
+
MATCH (c:Conversation {accountId: $accountId})
|
|
56
|
+
RETURN c
|
|
57
|
+
ORDER BY c.updatedAt DESC
|
|
58
|
+
LIMIT $windowSize
|
|
59
|
+
}
|
|
60
|
+
WITH collect(c) AS recent
|
|
61
|
+
WITH recent,
|
|
62
|
+
[c IN recent WHERE c.retrospectiveCompletedAt IS NOT NULL] AS done,
|
|
63
|
+
[c IN recent WHERE c.retrospectiveCompletedAt IS NOT NULL | c.retrospectiveCompletedAt]
|
|
64
|
+
AS doneTimestamps
|
|
65
|
+
WITH size(recent) AS windowSessions,
|
|
66
|
+
size(done) AS completedRetrospectives,
|
|
67
|
+
reduce(acc = null, ts IN doneTimestamps |
|
|
68
|
+
CASE WHEN acc IS NULL OR ts > acc THEN ts ELSE acc END)
|
|
69
|
+
AS lastCompletedAt
|
|
70
|
+
OPTIONAL MATCH (n)
|
|
71
|
+
WHERE n.accountId = $accountId
|
|
72
|
+
AND ANY(l IN labels(n) WHERE l IN $proseLabels)
|
|
73
|
+
AND (lastCompletedAt IS NULL OR n.updatedAt > lastCompletedAt)
|
|
74
|
+
WITH windowSessions, completedRetrospectives, min(n.updatedAt) AS oldestPending
|
|
75
|
+
RETURN windowSessions, completedRetrospectives, oldestPending
|
|
76
|
+
`;
|
|
77
|
+
const proseLabels = [
|
|
78
|
+
"Message",
|
|
79
|
+
"Page",
|
|
80
|
+
"Meeting",
|
|
81
|
+
"Email",
|
|
82
|
+
"Idea",
|
|
83
|
+
"Note",
|
|
84
|
+
"Post",
|
|
85
|
+
"Report",
|
|
86
|
+
];
|
|
87
|
+
let records;
|
|
88
|
+
try {
|
|
89
|
+
const result = await session.run(cypher, {
|
|
90
|
+
accountId,
|
|
91
|
+
windowSize,
|
|
92
|
+
proseLabels,
|
|
93
|
+
});
|
|
94
|
+
records = result.records;
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
const result = await session.run(fallbackCypher, {
|
|
98
|
+
accountId,
|
|
99
|
+
windowSize,
|
|
100
|
+
proseLabels,
|
|
101
|
+
});
|
|
102
|
+
records = result.records;
|
|
103
|
+
}
|
|
104
|
+
if (records.length === 0) {
|
|
105
|
+
return {
|
|
106
|
+
windowSessions: 0,
|
|
107
|
+
completedRetrospectives: 0,
|
|
108
|
+
skipRate: 0,
|
|
109
|
+
oldestPendingSinceIso: null,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
const r = records[0];
|
|
113
|
+
const windowSessions = Number(r.get("windowSessions") ?? 0);
|
|
114
|
+
const completedRetrospectives = Number(r.get("completedRetrospectives") ?? 0);
|
|
115
|
+
const oldestPending = r.get("oldestPending");
|
|
116
|
+
const skipRate = windowSessions > 0
|
|
117
|
+
? Number(((windowSessions - completedRetrospectives) / windowSessions).toFixed(3))
|
|
118
|
+
: 0;
|
|
119
|
+
const accountShort = accountId.slice(0, 8);
|
|
120
|
+
const oldestPendingIso = oldestPending == null ? null : String(oldestPending);
|
|
121
|
+
console.log(`[session-retrospective-skip-rate] accountId=${accountShort}… window=${windowSessions} completed=${completedRetrospectives} skip-rate=${skipRate} oldest-pending=${oldestPendingIso ?? "none"}`);
|
|
122
|
+
return {
|
|
123
|
+
windowSessions,
|
|
124
|
+
completedRetrospectives,
|
|
125
|
+
skipRate,
|
|
126
|
+
oldestPendingSinceIso: oldestPendingIso,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=session-retrospective-skip-rate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-retrospective-skip-rate.js","sourceRoot":"","sources":["../../src/tools/session-retrospective-skip-rate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAgBH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,IAAyB,EACzB,OAAgB,EAChB,SAAiB;IAEjB,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;IAErE,wEAAwE;IACxE,kEAAkE;IAClE,sEAAsE;IACtE,6BAA6B;IAC7B,wEAAwE;IACxE,wEAAwE;IACxE,mEAAmE;IACnE,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;GAuBd,CAAC;IAEF,4EAA4E;IAC5E,oDAAoD;IACpD,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;GAuBtB,CAAC;IAEF,MAAM,WAAW,GAAG;QAClB,SAAS;QACT,MAAM;QACN,SAAS;QACT,OAAO;QACP,MAAM;QACN,MAAM;QACN,MAAM;QACN,QAAQ;KACT,CAAC;IAEF,IAAI,OAAO,CAAC;IACZ,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE;YACvC,SAAS;YACT,UAAU;YACV,WAAW;SACZ,CAAC,CAAC;QACH,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE;YAC/C,SAAS;YACT,UAAU;YACV,WAAW;SACZ,CAAC,CAAC;QACH,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IAC3B,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO;YACL,cAAc,EAAE,CAAC;YACjB,uBAAuB,EAAE,CAAC;YAC1B,QAAQ,EAAE,CAAC;YACX,qBAAqB,EAAE,IAAI;SAC5B,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACrB,MAAM,cAAc,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5D,MAAM,uBAAuB,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,yBAAyB,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9E,MAAM,aAAa,GAAG,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,cAAc,GAAG,CAAC;QACjC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,GAAG,uBAAuB,CAAC,GAAG,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAClF,CAAC,CAAC,CAAC,CAAC;IACN,MAAM,YAAY,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3C,MAAM,gBAAgB,GAAG,aAAa,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IAE9E,OAAO,CAAC,GAAG,CACT,+CAA+C,YAAY,YAAY,cAAc,cAAc,uBAAuB,cAAc,QAAQ,mBAAmB,gBAAgB,IAAI,MAAM,EAAE,CAChM,CAAC;IAEF,OAAO;QACL,cAAc;QACd,uBAAuB;QACvB,QAAQ;QACR,qBAAqB,EAAE,gBAAgB;KACxC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-shot backfill of the typed-edge pass over every existing prose-bearing
|
|
3
|
+
* node for the current account. Idempotent — MERGE handles re-runs cleanly,
|
|
4
|
+
* so a second invocation accepts zero edges.
|
|
5
|
+
*
|
|
6
|
+
* Usage (admin-agent invokable via Bash):
|
|
7
|
+
* cd platform/plugins/memory/mcp
|
|
8
|
+
* node --loader ts-node/esm scripts/backfill-typed-edges.ts
|
|
9
|
+
*
|
|
10
|
+
* Reads ACCOUNT_ID from env (same convention as the MCP server). Loops
|
|
11
|
+
* `runTypedEdgePass` with `sinceIso: null` in 500-node pages until the
|
|
12
|
+
* page returns 0 nodes (exhausted). Logs per-batch progress with
|
|
13
|
+
* `[typed-edge-pass:backfill]`.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { getSession, closeDriver } from "../src/lib/neo4j.js";
|
|
17
|
+
import { runTypedEdgePass } from "../src/lib/typed-edge-pass.js";
|
|
18
|
+
|
|
19
|
+
const PAGE_SIZE = 500;
|
|
20
|
+
|
|
21
|
+
async function main(): Promise<void> {
|
|
22
|
+
const accountId = process.env.ACCOUNT_ID;
|
|
23
|
+
if (!accountId) {
|
|
24
|
+
console.error("ACCOUNT_ID env var is required");
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let batch = 0;
|
|
29
|
+
let totalNodes = 0;
|
|
30
|
+
let totalAccepted = 0;
|
|
31
|
+
let totalRejected = 0;
|
|
32
|
+
let totalFailed = 0;
|
|
33
|
+
|
|
34
|
+
while (true) {
|
|
35
|
+
const session = getSession();
|
|
36
|
+
try {
|
|
37
|
+
const result = await runTypedEdgePass({
|
|
38
|
+
session,
|
|
39
|
+
accountId,
|
|
40
|
+
sinceIso: null,
|
|
41
|
+
conversationId: null,
|
|
42
|
+
maxNodes: PAGE_SIZE,
|
|
43
|
+
});
|
|
44
|
+
batch += 1;
|
|
45
|
+
totalNodes += result.nodes;
|
|
46
|
+
totalAccepted += result.accepted;
|
|
47
|
+
totalRejected += result.rejected;
|
|
48
|
+
totalFailed += result.failed;
|
|
49
|
+
console.log(
|
|
50
|
+
`[typed-edge-pass:backfill] batch=${batch} done=${totalNodes} accepted=${result.accepted} rejected=${result.rejected} failed=${result.failed} ms=${result.ms}`,
|
|
51
|
+
);
|
|
52
|
+
if (result.nodes < PAGE_SIZE || result.accepted === 0) {
|
|
53
|
+
// Exhausted: either the page came back short, or a re-run page
|
|
54
|
+
// produced no new accepted edges (idempotency convergence).
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
} finally {
|
|
58
|
+
await session.close();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
console.log(
|
|
63
|
+
`[typed-edge-pass:backfill] complete batches=${batch} totalNodes=${totalNodes} totalAccepted=${totalAccepted} totalRejected=${totalRejected} totalFailed=${totalFailed}`,
|
|
64
|
+
);
|
|
65
|
+
await closeDriver();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
main().catch(async (err) => {
|
|
69
|
+
console.error(`[typed-edge-pass:backfill] error: ${err instanceof Error ? err.message : String(err)}`);
|
|
70
|
+
await closeDriver();
|
|
71
|
+
process.exit(1);
|
|
72
|
+
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Emit the typed-edge enumeration into the public docs from the
|
|
3
|
+
* `TYPED_EDGE_ALLOWLIST` source of truth, so the prompt, the validator,
|
|
4
|
+
* and the docs cannot drift from each other.
|
|
5
|
+
*
|
|
6
|
+
* Targets:
|
|
7
|
+
* - .docs/neo4j.md (parent maxy-code .docs surface)
|
|
8
|
+
* - platform/plugins/docs/references/neo4j.md (bundled into the payload)
|
|
9
|
+
*
|
|
10
|
+
* Replaces the block delimited by:
|
|
11
|
+
* <!-- TYPED-EDGE-TABLE:START -->
|
|
12
|
+
* <!-- TYPED-EDGE-TABLE:END -->
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* node --loader ts-node/esm scripts/generate-edge-docs.ts
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { writeFileSync, readFileSync, existsSync } from "node:fs";
|
|
19
|
+
import { resolve } from "node:path";
|
|
20
|
+
import { TYPED_EDGE_ALLOWLIST } from "../src/lib/typed-edge-schema.js";
|
|
21
|
+
|
|
22
|
+
const TARGET_PATHS = [
|
|
23
|
+
// maxy-code/.docs/neo4j.md — resolved relative to this script.
|
|
24
|
+
resolve(import.meta.dirname ?? __dirname, "../../../../../.docs/neo4j.md"),
|
|
25
|
+
// bundled docs twin
|
|
26
|
+
resolve(import.meta.dirname ?? __dirname, "../../../docs/references/neo4j.md"),
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
const START_MARKER = "<!-- TYPED-EDGE-TABLE:START -->";
|
|
30
|
+
const END_MARKER = "<!-- TYPED-EDGE-TABLE:END -->";
|
|
31
|
+
|
|
32
|
+
function buildTable(): string {
|
|
33
|
+
const rows = TYPED_EDGE_ALLOWLIST
|
|
34
|
+
.map(({ sourceLabel, edgeType, targetLabel }) => `| ${sourceLabel} | ${edgeType} | ${targetLabel} |`)
|
|
35
|
+
.join("\n");
|
|
36
|
+
return [
|
|
37
|
+
START_MARKER,
|
|
38
|
+
"",
|
|
39
|
+
"<!-- Generated by platform/plugins/memory/mcp/scripts/generate-edge-docs.ts from TYPED_EDGE_ALLOWLIST. Do not edit by hand. -->",
|
|
40
|
+
"",
|
|
41
|
+
"| Source label | Edge type | Target label |",
|
|
42
|
+
"|---|---|---|",
|
|
43
|
+
rows,
|
|
44
|
+
"",
|
|
45
|
+
END_MARKER,
|
|
46
|
+
].join("\n");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function applyToFile(path: string, table: string): "wrote" | "missing" | "no-markers" {
|
|
50
|
+
if (!existsSync(path)) return "missing";
|
|
51
|
+
const current = readFileSync(path, "utf-8");
|
|
52
|
+
const startIdx = current.indexOf(START_MARKER);
|
|
53
|
+
const endIdx = current.indexOf(END_MARKER);
|
|
54
|
+
let next: string;
|
|
55
|
+
if (startIdx === -1 || endIdx === -1) {
|
|
56
|
+
// No markers — append the section under a clear heading rather than
|
|
57
|
+
// failing. Idempotent on subsequent runs because we add the markers.
|
|
58
|
+
next = `${current.trimEnd()}\n\n## Typed-edge allowlist (generated)\n\n${table}\n`;
|
|
59
|
+
writeFileSync(path, next);
|
|
60
|
+
return "wrote";
|
|
61
|
+
}
|
|
62
|
+
next = current.slice(0, startIdx) + table + current.slice(endIdx + END_MARKER.length);
|
|
63
|
+
writeFileSync(path, next);
|
|
64
|
+
return "wrote";
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function main(): void {
|
|
68
|
+
const table = buildTable();
|
|
69
|
+
for (const path of TARGET_PATHS) {
|
|
70
|
+
const result = applyToFile(path, table);
|
|
71
|
+
console.log(`[generate-edge-docs] ${path} -> ${result}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
main();
|
|
@@ -22,6 +22,11 @@ export default defineConfig({
|
|
|
22
22
|
"src/lib/__tests__/schema-cypher-drift.test.ts",
|
|
23
23
|
// Task 350 — label-origin gate (refuse agent-side LocalBusiness writes).
|
|
24
24
|
"src/lib/__tests__/label-origin-gate.test.ts",
|
|
25
|
+
// Task 305 — typed-edge allowlist schema invariants.
|
|
26
|
+
"src/lib/__tests__/typed-edge-schema.test.ts",
|
|
27
|
+
// Task 306 — compiled-truth + timeline.
|
|
28
|
+
"src/lib/__tests__/timeline-extractor.test.ts",
|
|
29
|
+
"src/lib/__tests__/graph-write-gate-property.test.ts",
|
|
25
30
|
],
|
|
26
31
|
testTimeout: 10_000,
|
|
27
32
|
},
|
|
@@ -46,6 +46,7 @@ When loading this reference, confirm which schema files were consulted by noting
|
|
|
46
46
|
| VoiceEdit | `VoiceEdit` | platform-native (Task 356 — operator edit on an agent draft) | — | `accountId`, `adminUserId`, `originalText`, `editedText`, `intent`, `occurredAt` |
|
|
47
47
|
| AEO Audit | `AEOAudit` | platform-native (AEO audit history) | — | `accountId`, `auditId`, `target`, `score`, `heuristicsJson`, `runAt`, `createdByAgent`, `createdBySession`, `createdAt` |
|
|
48
48
|
| Idea | `Idea` | platform-native (signal-detector original-thinking candidate) | — | `accountId`, `body`, `conversationId`, `scope`, `createdByAgent`, `createdBySession`, `createdAt` |
|
|
49
|
+
| TimelineEvent | `TimelineEvent` | platform-native (Task 306 — compiled-truth + timeline doctrine) | — | `accountId`, `timelineEventId`, `occurredAt`, `kind`, `summary`, `source` |
|
|
49
50
|
|
|
50
51
|
**Branding properties on LocalBusiness:** `primaryColor`, `accentColor`, `backgroundColor`, `tagline` — optional, used to brand the public chat endpoint. Hex color values must match `#[0-9a-fA-F]{3,8}`. Logo and icon are linked via `HAS_BRAND_ASSET → ImageObject` with `purpose: "logo"` or `"icon"`.
|
|
51
52
|
|
|
@@ -71,6 +72,49 @@ When loading this reference, confirm which schema files were consulted by noting
|
|
|
71
72
|
|
|
72
73
|
---
|
|
73
74
|
|
|
75
|
+
## Compiled truth + timeline (Task 306)
|
|
76
|
+
|
|
77
|
+
Every `:Person`, `:Organization`, and `:Concept` carries a two-part knowledge shape: a **compiled truth** above the rule (the agent's current best understanding of the subject, rewritten when evidence changes) and an **append-only timeline** below (dated events linked via `:HAS_TIMELINE_EVENT`, never edited).
|
|
78
|
+
|
|
79
|
+
| Property | Type | Purpose |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| `compiledTruth` | string ≤2000 chars | The current summary. Empty on first write. |
|
|
82
|
+
| `compiledTruthUpdatedAt` | datetime | Last rewriter or operator write. Epoch on first write. |
|
|
83
|
+
| `compiledTruthSource` | `'rewriter' \| 'operator'` | Last writer. Operator edits get a 7-day cooldown that the rewriter respects unless `forceRewrite=true` is passed. |
|
|
84
|
+
|
|
85
|
+
The compiled truth is system-managed: direct writes to any of the three properties via `memory-update` are **rejected loudly**. The only paths to mutate are:
|
|
86
|
+
|
|
87
|
+
- `memory-update(nodeId, {}, rewriteCompiledTruth: true)` — invokes the OAuth-LLM rewriter against the most recent 10 `:TimelineEvent` rows.
|
|
88
|
+
- `memory-update(nodeId, {}, rewriteCompiledTruth: true, forceRewrite: true)` — same, but bypasses the 7-day operator cooldown.
|
|
89
|
+
- The graph UI's per-property edit surface — stamps `compiledTruthSource: 'operator'` so the rewriter honours the cooldown.
|
|
90
|
+
|
|
91
|
+
### Timeline events
|
|
92
|
+
|
|
93
|
+
`:TimelineEvent` is distinct from the scheduling plugin's `:Event` (which holds `eventId`-unique calendar/reminder rows). Naming chosen to avoid collision.
|
|
94
|
+
|
|
95
|
+
`:HAS_TIMELINE_EVENT` is distinct from visitor-analytics' `:HAS_EVENT` (`Session → PageView/Click/ScrollMilestone`). Naming chosen to avoid collision.
|
|
96
|
+
|
|
97
|
+
`kind` enum (5 values, no catch-all):
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
mentioned | met | quoted | attended | transacted
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The extractor refuses on ambiguity rather than collapsing to "other". Default on write is `mentioned`; the typed-edge post-write hook (Task 305) upgrades the kind asynchronously when it can.
|
|
104
|
+
|
|
105
|
+
### Write doctrine
|
|
106
|
+
|
|
107
|
+
Path-anchored MERGE — never label-only:
|
|
108
|
+
|
|
109
|
+
```cypher
|
|
110
|
+
MATCH (e) WHERE elementId(e) = $entityId AND e.accountId = $accountId
|
|
111
|
+
MERGE (e)-[:HAS_TIMELINE_EVENT]->(t:TimelineEvent {timelineEventId: $id})
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`memory-write` runs the deterministic date extractor against the `body` property of any `:Person` / `:Organization` / `:Concept` write and creates one `:TimelineEvent` per parseable dated statement.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
74
118
|
## Forbidden Properties
|
|
75
119
|
|
|
76
120
|
Properties listed here are **rejected at write-time** by the schema validator on the listed label. Rejection runs after the synonym pass, so a `firstName → givenName` rewrite still happens before the forbidden-property check. The rule is per-label: `name` is forbidden on `Person` only; `Organization`, `Event`, `Conversation`, `Service`, etc. retain `name` as a canonical property.
|
|
@@ -486,6 +486,55 @@ fi
|
|
|
486
486
|
|
|
487
487
|
echo "$SCHEMA_CYPHER" | "$CYPHER_SHELL" -u "$NEO4J_USER" -p "$NEO4J_PASSWORD" -a "$NEO4J_URI"
|
|
488
488
|
|
|
489
|
+
# ------------------------------------------------------------------
|
|
490
|
+
# 2.4 Compiled-truth + timeline backfill (compiled-truth + timeline)
|
|
491
|
+
# ------------------------------------------------------------------
|
|
492
|
+
# Every existing :Person / :Organization / :Concept gains the three
|
|
493
|
+
# compiled-truth properties on first run. Idempotent — the WHERE clause
|
|
494
|
+
# `compiledTruth IS NULL` makes re-runs a no-op for already-stamped nodes.
|
|
495
|
+
# Rewriter invocation is deferred to operator demand (memory-update with
|
|
496
|
+
# rewriteCompiledTruth:true); fresh installs have no entities anyway.
|
|
497
|
+
#
|
|
498
|
+
# Timeline-event seeding from :Message-[:MENTIONS]->entity edges is also
|
|
499
|
+
# idempotent: the `WHERE NOT EXISTS { ... :TimelineEvent }` guard prevents
|
|
500
|
+
# re-creation across runs. Skips messages without a parseable createdAt.
|
|
501
|
+
COMPILED_TRUTH_BACKFILL_CYPHER=$(cat <<'BACKFILL_EOF'
|
|
502
|
+
// Stamp compiled-truth defaults on existing entities.
|
|
503
|
+
MATCH (n)
|
|
504
|
+
WHERE (n:Person OR n:Organization OR n:Concept)
|
|
505
|
+
AND n.compiledTruth IS NULL
|
|
506
|
+
SET n.compiledTruth = '',
|
|
507
|
+
n.compiledTruthUpdatedAt = datetime('1970-01-01T00:00:00Z'),
|
|
508
|
+
n.compiledTruthSource = 'rewriter'
|
|
509
|
+
RETURN labels(n)[0] AS label, count(n) AS stamped;
|
|
510
|
+
|
|
511
|
+
// Seed :TimelineEvent rows from existing :Message-[:MENTIONS]->entity edges.
|
|
512
|
+
// Guard: only when the Message has a parseable createdAt AND no equivalent
|
|
513
|
+
// :TimelineEvent already exists for this (entity, message) pair.
|
|
514
|
+
MATCH (m:Message)-[:MENTIONS]->(e)
|
|
515
|
+
WHERE (e:Person OR e:Organization OR e:Concept)
|
|
516
|
+
AND m.createdAt IS NOT NULL
|
|
517
|
+
AND NOT EXISTS {
|
|
518
|
+
MATCH (e)-[:HAS_TIMELINE_EVENT]->(t:TimelineEvent {source: m.messageId})
|
|
519
|
+
}
|
|
520
|
+
WITH e, m
|
|
521
|
+
WHERE e.accountId IS NOT NULL
|
|
522
|
+
MERGE (e)-[:HAS_TIMELINE_EVENT]->(t:TimelineEvent {timelineEventId: randomUUID()})
|
|
523
|
+
ON CREATE SET t.accountId = e.accountId,
|
|
524
|
+
t.occurredAt = datetime(m.createdAt),
|
|
525
|
+
t.kind = 'mentioned',
|
|
526
|
+
t.summary = coalesce(substring(m.body, 0, 500), '(no body)'),
|
|
527
|
+
t.source = m.messageId,
|
|
528
|
+
t.matched = '(backfilled from :MENTIONS edge)',
|
|
529
|
+
t.createdAt = datetime(),
|
|
530
|
+
t.scope = coalesce(e.scope, 'admin')
|
|
531
|
+
RETURN labels(e)[0] AS entityLabel, count(t) AS seeded;
|
|
532
|
+
BACKFILL_EOF
|
|
533
|
+
)
|
|
534
|
+
|
|
535
|
+
echo "==> Backfilling compiled-truth + timeline (compiled-truth + timeline)..."
|
|
536
|
+
echo "$COMPILED_TRUTH_BACKFILL_CYPHER" | "$CYPHER_SHELL" -u "$NEO4J_USER" -p "$NEO4J_PASSWORD" -a "$NEO4J_URI" --format plain 2>&1 | sed 's/^/ /'
|
|
537
|
+
|
|
489
538
|
# ------------------------------------------------------------------
|
|
490
539
|
# 2.5 Bootstrap root :LocalBusiness for the account
|
|
491
540
|
# ------------------------------------------------------------------
|
|
@@ -40,17 +40,18 @@ Call `memory-write` or `memory-update` directly only when the write is a one-lin
|
|
|
40
40
|
|
|
41
41
|
When the operator signals end-of-session (`/end`, `/archive`, `end session`, or `archive this session`), the Stop hook blocks this session from closing until you have done three things and called one tool. The hook's instruction block names the three passes verbatim every time it fires; this section is the doctrine behind it.
|
|
42
42
|
|
|
43
|
-
The
|
|
43
|
+
The four passes, each performed against this session's conversation, using tools you already have:
|
|
44
44
|
|
|
45
45
|
- **Technical learnings.** Walk for operator corrections and self-detected mistakes. Each one becomes a Learning or Correction node in the graph; delegate the write to `database-operator` via the Task tool, the same route the Recording section describes.
|
|
46
46
|
- **Operator-relationship updates.** Walk for tonal signals, rejected phrasings, and working-style preferences. Each one worth carrying forward goes into `SOUL.md` via `Write`.
|
|
47
47
|
- **Graph completeness sweep.** Walk for any node, edge, or commitment that surfaced in this session but was never written to the graph in-flight. Each missing write goes to `database-operator` via the Task tool.
|
|
48
|
+
- **Typed-edge auto-extraction.** Delegate to `database-operator` via the Task tool with a prompt that names the typed-edge pass and the session-start timestamp. The specialist calls `memory-typed-edge-pass` with that timestamp and returns the counters (`nodesProcessed`, `accepted`). Capture both for the completion call.
|
|
48
49
|
|
|
49
|
-
Then call `session-retrospective-mark-complete` with the
|
|
50
|
+
Then call `session-retrospective-mark-complete` with the five counts (learningsCount, preferencesCount, graphWriteCount, typedEdgesCount, nodesProcessed) and reply with one short paragraph naming what you wrote. The sentinel tool call is what releases the gate. A prose retrospective without the tool call leaves the gate blocked — the gate reads the JSONL, not your reply.
|
|
50
51
|
|
|
51
52
|
Run the retrospective inside this same session. Do not spawn a new session, do not background anything. The mid-flight Recording route is the primary path for graph writes; this is the catch-net for what slipped through it.
|
|
52
53
|
|
|
53
|
-
|
|
54
|
+
Closing the browser tab, archiving from the sidebar, losing power, or any other exit that is not one of the four typed end-intent tokens skips the retrospective entirely. That means the four passes above do not run for that session: learnings, SOUL.md updates, missing graph writes, and typed-edge auto-extraction all defer to the next session's `/end`. Mid-session writes still happen, so nothing is lost — the extraction just lands one session later. Call `session-retrospective-skip-rate` at session start; if the rate is non-zero, surface one plain-English line to the operator naming how many recent sessions skipped, so they can choose to type `/end` next time.
|
|
54
55
|
|
|
55
56
|
## Stop-hook system directives
|
|
56
57
|
|
|
@@ -3,7 +3,7 @@ name: database-operator
|
|
|
3
3
|
description: "Graph-write executor reachable from admin via the Task tool. Admin names what should land in the graph; database-operator reads the schema, decides operations, executes them against the memory graph, and reports `{label, elementId}` back. (Reachable historically also from the now-dormant Stop hook in `platform/plugins/admin/hooks/turn-completed-graph-write.sh`; that path is preserved as infrastructure but no longer registered, see Task 214.)"
|
|
4
4
|
summary: "Executes graph writes on admin's behalf when delegated via the Task tool."
|
|
5
5
|
model: claude-sonnet-4-6
|
|
6
|
-
tools: Read, mcp__plugin_memory_memory__memory-write, mcp__plugin_memory_memory__memory-update, mcp__plugin_memory_memory__memory-search, mcp__plugin_memory_memory__profile-update, mcp__plugin_memory_memory__profile-read, mcp__plugin_contacts_contacts__contact-create, mcp__plugin_contacts_contacts__contact-update, mcp__plugin_work_work__work-create, mcp__plugin_work_work__work-update, mcp__plugin_work_work__project-create, mcp__plugin_work_work__project-update
|
|
6
|
+
tools: Read, mcp__plugin_memory_memory__memory-write, mcp__plugin_memory_memory__memory-update, mcp__plugin_memory_memory__memory-search, mcp__plugin_memory_memory__memory-typed-edge-pass, mcp__plugin_memory_memory__session-retrospective-skip-rate, mcp__plugin_memory_memory__profile-update, mcp__plugin_memory_memory__profile-read, mcp__plugin_contacts_contacts__contact-create, mcp__plugin_contacts_contacts__contact-update, mcp__plugin_work_work__work-create, mcp__plugin_work_work__work-update, mcp__plugin_work_work__project-create, mcp__plugin_work_work__project-update
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
You are an expert Neo4J graph operator. Admin delegates a graph-write to you through the Task tool; the prompt admin sends names what should land in the graph in plain English.
|
|
@@ -19,3 +19,11 @@ The `accountId` property is supplied by the writers from server-side environment
|
|
|
19
19
|
**Brain-first read before write.** Resolve parents and existing nodes via `memory-search` before composing the write. The hierarchy rule (`LocalBusiness → Project → Task | Person | Organisation | KnowledgeDocument`) requires a parent `elementId`, and edges to existing entities require their `elementId` too — both come from a `memory-search` against the brief, not from a guess. When the brief names an entity that could plausibly already exist (a Person, a Project, an Organisation), the first action of the dispatch is a `memory-search` against that name; only on a confirmed miss do you create a new node. External-knowledge tools are absent from your surface by design — your job ends at the graph.
|
|
20
20
|
|
|
21
21
|
Decide the precise operations against the schema, execute them with the writers in your tool surface, and report each write back to admin as `{label, elementId}` so admin can confirm the outcome to the operator. If admin's brief is ambiguous about which label, which edge type, or which existing node to attach to, name the ambiguity in your reply rather than guessing.
|
|
22
|
+
|
|
23
|
+
## Typed-edge auto-extraction pass (session-end)
|
|
24
|
+
|
|
25
|
+
When admin's brief names the typed-edge pass (Task 305) and supplies a `sinceIso` timestamp, call `memory-typed-edge-pass` with that timestamp exactly once. The tool reads prose-bearing nodes (Message/Page/Meeting/Email/Idea/Note/Post/Report) the account wrote since `sinceIso`, asks Haiku for typed-edge proposals against a closed allowlist, validates each one, and MERGEs accepted edges with `createdBy` provenance. Return the full counter object verbatim — admin needs `nodesProcessed` and `accepted` for the `session-retrospective-mark-complete` call. Do not reinterpret the counts or summarise them.
|
|
26
|
+
|
|
27
|
+
## Skip-rate visibility (session-start)
|
|
28
|
+
|
|
29
|
+
When admin's brief names the skip-rate check, call `session-retrospective-skip-rate` once and return its result verbatim. The tool reports how many of the last N sessions for this account closed without firing the retrospective. Admin uses the rate to inform the operator that closing via Sidebar Archive or tab-close defers the typed-edge pass to the next `/end`. Pass the `windowSize` admin provides; default 10 is fine when absent.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
|
|
2
|
+
import "./chunk-HYQNUVGO.js";
|
|
2
3
|
|
|
3
4
|
// app/lib/adminuser-self-heal.ts
|
|
4
5
|
var UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
|
|
1
2
|
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
6
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var
|
|
8
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
9
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
10
|
+
}) : x)(function(x) {
|
|
11
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
12
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
13
|
+
});
|
|
14
|
+
var __commonJS = (cb, mod) => function __require2() {
|
|
8
15
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
9
16
|
};
|
|
10
17
|
var __copyProps = (to, from, except, desc) => {
|
|
@@ -25,6 +32,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
25
32
|
));
|
|
26
33
|
|
|
27
34
|
export {
|
|
35
|
+
__require,
|
|
28
36
|
__commonJS,
|
|
29
37
|
__toESM
|
|
30
38
|
};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
|
|
2
|
+
|
|
1
3
|
// node_modules/hono/dist/compose.js
|
|
2
4
|
var compose = (middleware, onError, onNotFound) => {
|
|
3
5
|
return (context, next) => {
|
|
@@ -4099,7 +4101,7 @@ function getSession() {
|
|
|
4099
4101
|
return getDriver().session();
|
|
4100
4102
|
}
|
|
4101
4103
|
async function runAdminUserSelfHeal(args) {
|
|
4102
|
-
const { selfHealAdminUser } = await import("./adminuser-self-heal-
|
|
4104
|
+
const { selfHealAdminUser } = await import("./adminuser-self-heal-YC47O34W.js");
|
|
4103
4105
|
return selfHealAdminUser({ driver: getDriver(), ...args });
|
|
4104
4106
|
}
|
|
4105
4107
|
process.on("SIGINT", async () => {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
|
|
1
2
|
import {
|
|
2
3
|
Hono,
|
|
3
4
|
LOG_DIR,
|
|
@@ -13,8 +14,8 @@ import {
|
|
|
13
14
|
sanitizeClientCorrId,
|
|
14
15
|
vncLog,
|
|
15
16
|
websockifyLog
|
|
16
|
-
} from "./chunk-
|
|
17
|
-
import "./chunk-
|
|
17
|
+
} from "./chunk-T3DJD5QR.js";
|
|
18
|
+
import "./chunk-HYQNUVGO.js";
|
|
18
19
|
|
|
19
20
|
// server/edge.ts
|
|
20
21
|
import { createServer, request as httpRequest } from "http";
|