mem-os-python 1.6.27__py3-none-any.whl
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.
- mem_os_python-1.6.27.dist-info/METADATA +1032 -0
- mem_os_python-1.6.27.dist-info/RECORD +253 -0
- mem_os_python-1.6.27.dist-info/WHEEL +4 -0
- mem_os_python-1.6.27.dist-info/entry_points.txt +2 -0
- mem_os_python-1.6.27.dist-info/licenses/LICENSE +21 -0
- memos/__init__.py +16 -0
- memos/_js/adapters/anthropic.d.ts +279 -0
- memos/_js/adapters/anthropic.d.ts.map +1 -0
- memos/_js/adapters/anthropic.js +348 -0
- memos/_js/adapters/anthropic.js.map +1 -0
- memos/_js/adapters/base.d.ts +10 -0
- memos/_js/adapters/base.d.ts.map +1 -0
- memos/_js/adapters/base.js +2 -0
- memos/_js/adapters/base.js.map +1 -0
- memos/_js/adapters/openai.d.ts +264 -0
- memos/_js/adapters/openai.d.ts.map +1 -0
- memos/_js/adapters/openai.js +342 -0
- memos/_js/adapters/openai.js.map +1 -0
- memos/_js/apps/explorer.d.ts +244 -0
- memos/_js/apps/explorer.d.ts.map +1 -0
- memos/_js/apps/explorer.js +738 -0
- memos/_js/apps/explorer.js.map +1 -0
- memos/_js/citations.d.ts +65 -0
- memos/_js/citations.d.ts.map +1 -0
- memos/_js/citations.js +143 -0
- memos/_js/citations.js.map +1 -0
- memos/_js/cli-browse.d.ts +3 -0
- memos/_js/cli-browse.d.ts.map +1 -0
- memos/_js/cli-browse.js +129 -0
- memos/_js/cli-browse.js.map +1 -0
- memos/_js/cli-completion.d.ts +31 -0
- memos/_js/cli-completion.d.ts.map +1 -0
- memos/_js/cli-completion.js +340 -0
- memos/_js/cli-completion.js.map +1 -0
- memos/_js/cli-help.d.ts +18 -0
- memos/_js/cli-help.d.ts.map +1 -0
- memos/_js/cli-help.js +357 -0
- memos/_js/cli-help.js.map +1 -0
- memos/_js/cli.d.ts +28 -0
- memos/_js/cli.d.ts.map +1 -0
- memos/_js/cli.js +2880 -0
- memos/_js/cli.js.map +1 -0
- memos/_js/compression.d.ts +25 -0
- memos/_js/compression.d.ts.map +1 -0
- memos/_js/compression.js +319 -0
- memos/_js/compression.js.map +1 -0
- memos/_js/confidence-machine.d.ts +99 -0
- memos/_js/confidence-machine.d.ts.map +1 -0
- memos/_js/confidence-machine.js +222 -0
- memos/_js/confidence-machine.js.map +1 -0
- memos/_js/context-pack.d.ts +506 -0
- memos/_js/context-pack.d.ts.map +1 -0
- memos/_js/context-pack.js +1435 -0
- memos/_js/context-pack.js.map +1 -0
- memos/_js/contradictions.d.ts +160 -0
- memos/_js/contradictions.d.ts.map +1 -0
- memos/_js/contradictions.js +255 -0
- memos/_js/contradictions.js.map +1 -0
- memos/_js/dashboard.d.ts +30 -0
- memos/_js/dashboard.d.ts.map +1 -0
- memos/_js/dashboard.js +302 -0
- memos/_js/dashboard.js.map +1 -0
- memos/_js/ebbinghaus.d.ts +29 -0
- memos/_js/ebbinghaus.d.ts.map +1 -0
- memos/_js/ebbinghaus.js +32 -0
- memos/_js/ebbinghaus.js.map +1 -0
- memos/_js/embedding-queue.d.ts +190 -0
- memos/_js/embedding-queue.d.ts.map +1 -0
- memos/_js/embedding-queue.js +316 -0
- memos/_js/embedding-queue.js.map +1 -0
- memos/_js/embeddings.d.ts +187 -0
- memos/_js/embeddings.d.ts.map +1 -0
- memos/_js/embeddings.js +633 -0
- memos/_js/embeddings.js.map +1 -0
- memos/_js/entity-extraction.d.ts +54 -0
- memos/_js/entity-extraction.d.ts.map +1 -0
- memos/_js/entity-extraction.js +325 -0
- memos/_js/entity-extraction.js.map +1 -0
- memos/_js/entity-index.d.ts +93 -0
- memos/_js/entity-index.d.ts.map +1 -0
- memos/_js/entity-index.js +165 -0
- memos/_js/entity-index.js.map +1 -0
- memos/_js/event-memory.d.ts +147 -0
- memos/_js/event-memory.d.ts.map +1 -0
- memos/_js/event-memory.js +290 -0
- memos/_js/event-memory.js.map +1 -0
- memos/_js/external-import.d.ts +98 -0
- memos/_js/external-import.d.ts.map +1 -0
- memos/_js/external-import.js +669 -0
- memos/_js/external-import.js.map +1 -0
- memos/_js/fidelity.d.ts +367 -0
- memos/_js/fidelity.d.ts.map +1 -0
- memos/_js/fidelity.js +911 -0
- memos/_js/fidelity.js.map +1 -0
- memos/_js/graph-expansion.d.ts +119 -0
- memos/_js/graph-expansion.d.ts.map +1 -0
- memos/_js/graph-expansion.js +213 -0
- memos/_js/graph-expansion.js.map +1 -0
- memos/_js/graph-mermaid.d.ts +13 -0
- memos/_js/graph-mermaid.d.ts.map +1 -0
- memos/_js/graph-mermaid.js +32 -0
- memos/_js/graph-mermaid.js.map +1 -0
- memos/_js/graph.d.ts +170 -0
- memos/_js/graph.d.ts.map +1 -0
- memos/_js/graph.js +482 -0
- memos/_js/graph.js.map +1 -0
- memos/_js/harness.d.ts +63 -0
- memos/_js/harness.d.ts.map +1 -0
- memos/_js/harness.js +93 -0
- memos/_js/harness.js.map +1 -0
- memos/_js/importance.d.ts +118 -0
- memos/_js/importance.d.ts.map +1 -0
- memos/_js/importance.js +144 -0
- memos/_js/importance.js.map +1 -0
- memos/_js/index.d.ts +51 -0
- memos/_js/index.d.ts.map +1 -0
- memos/_js/index.js +53 -0
- memos/_js/index.js.map +1 -0
- memos/_js/mcp.d.ts +58 -0
- memos/_js/mcp.d.ts.map +1 -0
- memos/_js/mcp.js +1853 -0
- memos/_js/mcp.js.map +1 -0
- memos/_js/memory.d.ts +1762 -0
- memos/_js/memory.d.ts.map +1 -0
- memos/_js/memory.js +6283 -0
- memos/_js/memory.js.map +1 -0
- memos/_js/procedural.d.ts +74 -0
- memos/_js/procedural.d.ts.map +1 -0
- memos/_js/procedural.js +125 -0
- memos/_js/procedural.js.map +1 -0
- memos/_js/project-config.d.ts +68 -0
- memos/_js/project-config.d.ts.map +1 -0
- memos/_js/project-config.js +59 -0
- memos/_js/project-config.js.map +1 -0
- memos/_js/proof-of-forgetting.d.ts +57 -0
- memos/_js/proof-of-forgetting.d.ts.map +1 -0
- memos/_js/proof-of-forgetting.js +80 -0
- memos/_js/proof-of-forgetting.js.map +1 -0
- memos/_js/provenance.d.ts +122 -0
- memos/_js/provenance.d.ts.map +1 -0
- memos/_js/provenance.js +182 -0
- memos/_js/provenance.js.map +1 -0
- memos/_js/quarantine-commands.d.ts +23 -0
- memos/_js/quarantine-commands.d.ts.map +1 -0
- memos/_js/quarantine-commands.js +42 -0
- memos/_js/quarantine-commands.js.map +1 -0
- memos/_js/quarantine.d.ts +120 -0
- memos/_js/quarantine.d.ts.map +1 -0
- memos/_js/quarantine.js +873 -0
- memos/_js/quarantine.js.map +1 -0
- memos/_js/redact.d.ts +12 -0
- memos/_js/redact.d.ts.map +1 -0
- memos/_js/redact.js +26 -0
- memos/_js/redact.js.map +1 -0
- memos/_js/repl.d.ts +57 -0
- memos/_js/repl.d.ts.map +1 -0
- memos/_js/repl.js +295 -0
- memos/_js/repl.js.map +1 -0
- memos/_js/rerank-local.d.ts +61 -0
- memos/_js/rerank-local.d.ts.map +1 -0
- memos/_js/rerank-local.js +210 -0
- memos/_js/rerank-local.js.map +1 -0
- memos/_js/retain-filter.d.ts +98 -0
- memos/_js/retain-filter.d.ts.map +1 -0
- memos/_js/retain-filter.js +232 -0
- memos/_js/retain-filter.js.map +1 -0
- memos/_js/retrieval.d.ts +265 -0
- memos/_js/retrieval.d.ts.map +1 -0
- memos/_js/retrieval.js +1018 -0
- memos/_js/retrieval.js.map +1 -0
- memos/_js/revert.d.ts +77 -0
- memos/_js/revert.d.ts.map +1 -0
- memos/_js/revert.js +252 -0
- memos/_js/revert.js.map +1 -0
- memos/_js/scope.d.ts +30 -0
- memos/_js/scope.d.ts.map +1 -0
- memos/_js/scope.js +71 -0
- memos/_js/scope.js.map +1 -0
- memos/_js/semantic-screen.d.ts +152 -0
- memos/_js/semantic-screen.d.ts.map +1 -0
- memos/_js/semantic-screen.js +290 -0
- memos/_js/semantic-screen.js.map +1 -0
- memos/_js/session-hooks.d.ts +127 -0
- memos/_js/session-hooks.d.ts.map +1 -0
- memos/_js/session-hooks.js +482 -0
- memos/_js/session-hooks.js.map +1 -0
- memos/_js/storage/sqlite.d.ts +427 -0
- memos/_js/storage/sqlite.d.ts.map +1 -0
- memos/_js/storage/sqlite.js +2428 -0
- memos/_js/storage/sqlite.js.map +1 -0
- memos/_js/sync.d.ts +213 -0
- memos/_js/sync.d.ts.map +1 -0
- memos/_js/sync.js +389 -0
- memos/_js/sync.js.map +1 -0
- memos/_js/tamper-log.d.ts +98 -0
- memos/_js/tamper-log.d.ts.map +1 -0
- memos/_js/tamper-log.js +327 -0
- memos/_js/tamper-log.js.map +1 -0
- memos/_js/temporal.d.ts +92 -0
- memos/_js/temporal.d.ts.map +1 -0
- memos/_js/temporal.js +536 -0
- memos/_js/temporal.js.map +1 -0
- memos/_js/time-travel.d.ts +38 -0
- memos/_js/time-travel.d.ts.map +1 -0
- memos/_js/time-travel.js +46 -0
- memos/_js/time-travel.js.map +1 -0
- memos/_js/timestamp-format.d.ts +18 -0
- memos/_js/timestamp-format.d.ts.map +1 -0
- memos/_js/timestamp-format.js +52 -0
- memos/_js/timestamp-format.js.map +1 -0
- memos/_js/triple-extraction.d.ts +31 -0
- memos/_js/triple-extraction.d.ts.map +1 -0
- memos/_js/triple-extraction.js +116 -0
- memos/_js/triple-extraction.js.map +1 -0
- memos/_js/types.d.ts +2474 -0
- memos/_js/types.d.ts.map +1 -0
- memos/_js/types.js +20 -0
- memos/_js/types.js.map +1 -0
- memos/_js/updater.d.ts +95 -0
- memos/_js/updater.d.ts.map +1 -0
- memos/_js/updater.js +268 -0
- memos/_js/updater.js.map +1 -0
- memos/_js/version.d.ts +17 -0
- memos/_js/version.d.ts.map +1 -0
- memos/_js/version.js +34 -0
- memos/_js/version.js.map +1 -0
- memos/_js/vision/clip-query-cache.d.ts +58 -0
- memos/_js/vision/clip-query-cache.d.ts.map +1 -0
- memos/_js/vision/clip-query-cache.js +79 -0
- memos/_js/vision/clip-query-cache.js.map +1 -0
- memos/_js/vision/clip.d.ts +113 -0
- memos/_js/vision/clip.d.ts.map +1 -0
- memos/_js/vision/clip.js +224 -0
- memos/_js/vision/clip.js.map +1 -0
- memos/_js/vision/fake-clip.d.ts +55 -0
- memos/_js/vision/fake-clip.d.ts.map +1 -0
- memos/_js/vision/fake-clip.js +122 -0
- memos/_js/vision/fake-clip.js.map +1 -0
- memos/_js/vision/index.d.ts +15 -0
- memos/_js/vision/index.d.ts.map +1 -0
- memos/_js/vision/index.js +13 -0
- memos/_js/vision/index.js.map +1 -0
- memos/_js/vision/store.d.ts +137 -0
- memos/_js/vision/store.d.ts.map +1 -0
- memos/_js/vision/store.js +383 -0
- memos/_js/vision/store.js.map +1 -0
- memos/adapters/__init__.py +0 -0
- memos/adapters/crewai.py +385 -0
- memos/adapters/langchain.py +301 -0
- memos/adapters/ollama.py +396 -0
- memos/server/__init__.py +0 -0
- memos/server/main.py +547 -0
- memos/server/routes.py +360 -0
memos/_js/graph.js
ADDED
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory graph engine for MemOS.
|
|
3
|
+
*
|
|
4
|
+
* Maintains an adjacency-list representation of the memory graph for
|
|
5
|
+
* fast traversal, clustering, and auto-linking. The graph mirrors
|
|
6
|
+
* what is persisted in the storage backend.
|
|
7
|
+
*
|
|
8
|
+
* @module @memos/graph
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Default per-node cap on edges created by `autoLink()`.
|
|
12
|
+
*
|
|
13
|
+
* Without a cap, a corpus of similar memories converges to a complete
|
|
14
|
+
* graph (K_N): every new node links to every existing one, so edge
|
|
15
|
+
* writes grow quadratically and dominate ingestion time. 16 links is
|
|
16
|
+
* enough to preserve local cluster structure for `findClusters()` /
|
|
17
|
+
* `injectContext()` while keeping bulk ingestion near-linear. Pass `0`
|
|
18
|
+
* to `autoLink()` to restore uncapped (legacy) behavior.
|
|
19
|
+
*/
|
|
20
|
+
export const DEFAULT_AUTO_LINK_CAP = 16;
|
|
21
|
+
/**
|
|
22
|
+
* Bag-of-words cosine similarity between two strings.
|
|
23
|
+
*
|
|
24
|
+
* This is intentionally lightweight — no external embedding model needed.
|
|
25
|
+
* For production use-cases requiring semantic similarity, supply your own
|
|
26
|
+
* embedding-based linker via the adapter interface.
|
|
27
|
+
*
|
|
28
|
+
* @param a — First text.
|
|
29
|
+
* @param b — Second text.
|
|
30
|
+
* @returns Cosine similarity in [0, 1].
|
|
31
|
+
*/
|
|
32
|
+
export function textSimilarity(a, b) {
|
|
33
|
+
const tokensA = bagOfWords(a);
|
|
34
|
+
const tokensB = bagOfWords(b);
|
|
35
|
+
if (tokensA.size === 0 || tokensB.size === 0)
|
|
36
|
+
return 0;
|
|
37
|
+
return tokenSetSimilarity(tokensA, tokensB);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Cosine similarity of two pre-tokenized bags (binary term frequency).
|
|
41
|
+
* Exported for reuse by GraphEngine.autoLink, which tokenizes the new node
|
|
42
|
+
* once and reuses cached token sets for existing nodes instead of
|
|
43
|
+
* re-tokenizing both sides on every comparison.
|
|
44
|
+
*/
|
|
45
|
+
export function tokenSetSimilarity(tokensA, tokensB) {
|
|
46
|
+
if (tokensA.size === 0 || tokensB.size === 0)
|
|
47
|
+
return 0;
|
|
48
|
+
let intersection = 0;
|
|
49
|
+
// Iterate the smaller set for fewer hash lookups.
|
|
50
|
+
const [small, large] = tokensA.size <= tokensB.size ? [tokensA, tokensB] : [tokensB, tokensA];
|
|
51
|
+
for (const token of small) {
|
|
52
|
+
if (large.has(token))
|
|
53
|
+
intersection += 1;
|
|
54
|
+
}
|
|
55
|
+
return intersection / Math.sqrt(tokensA.size * tokensB.size);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Tokenise text into a set of lowercased, de-stopped words.
|
|
59
|
+
*/
|
|
60
|
+
// Module-level: bagOfWords runs O(N) times per autoLink() call, so the
|
|
61
|
+
// ~100-word Set must not be re-allocated on every invocation.
|
|
62
|
+
const BAG_OF_WORDS_STOP_WORDS = new Set([
|
|
63
|
+
"a",
|
|
64
|
+
"an",
|
|
65
|
+
"the",
|
|
66
|
+
"is",
|
|
67
|
+
"are",
|
|
68
|
+
"was",
|
|
69
|
+
"were",
|
|
70
|
+
"be",
|
|
71
|
+
"been",
|
|
72
|
+
"being",
|
|
73
|
+
"have",
|
|
74
|
+
"has",
|
|
75
|
+
"had",
|
|
76
|
+
"do",
|
|
77
|
+
"does",
|
|
78
|
+
"did",
|
|
79
|
+
"will",
|
|
80
|
+
"would",
|
|
81
|
+
"shall",
|
|
82
|
+
"should",
|
|
83
|
+
"may",
|
|
84
|
+
"might",
|
|
85
|
+
"must",
|
|
86
|
+
"can",
|
|
87
|
+
"could",
|
|
88
|
+
"to",
|
|
89
|
+
"of",
|
|
90
|
+
"in",
|
|
91
|
+
"for",
|
|
92
|
+
"on",
|
|
93
|
+
"with",
|
|
94
|
+
"at",
|
|
95
|
+
"by",
|
|
96
|
+
"from",
|
|
97
|
+
"as",
|
|
98
|
+
"into",
|
|
99
|
+
"through",
|
|
100
|
+
"during",
|
|
101
|
+
"before",
|
|
102
|
+
"after",
|
|
103
|
+
"above",
|
|
104
|
+
"below",
|
|
105
|
+
"between",
|
|
106
|
+
"and",
|
|
107
|
+
"but",
|
|
108
|
+
"or",
|
|
109
|
+
"nor",
|
|
110
|
+
"not",
|
|
111
|
+
"so",
|
|
112
|
+
"yet",
|
|
113
|
+
"both",
|
|
114
|
+
"either",
|
|
115
|
+
"neither",
|
|
116
|
+
"each",
|
|
117
|
+
"every",
|
|
118
|
+
"all",
|
|
119
|
+
"any",
|
|
120
|
+
"few",
|
|
121
|
+
"more",
|
|
122
|
+
"most",
|
|
123
|
+
"other",
|
|
124
|
+
"some",
|
|
125
|
+
"such",
|
|
126
|
+
"no",
|
|
127
|
+
"only",
|
|
128
|
+
"own",
|
|
129
|
+
"same",
|
|
130
|
+
"than",
|
|
131
|
+
"too",
|
|
132
|
+
"very",
|
|
133
|
+
"just",
|
|
134
|
+
"because",
|
|
135
|
+
"about",
|
|
136
|
+
"up",
|
|
137
|
+
"out",
|
|
138
|
+
"it",
|
|
139
|
+
"its",
|
|
140
|
+
"this",
|
|
141
|
+
"that",
|
|
142
|
+
"these",
|
|
143
|
+
"those",
|
|
144
|
+
"i",
|
|
145
|
+
"me",
|
|
146
|
+
"my",
|
|
147
|
+
"we",
|
|
148
|
+
"our",
|
|
149
|
+
"you",
|
|
150
|
+
"your",
|
|
151
|
+
"he",
|
|
152
|
+
"him",
|
|
153
|
+
"his",
|
|
154
|
+
"she",
|
|
155
|
+
"her",
|
|
156
|
+
"they",
|
|
157
|
+
"them",
|
|
158
|
+
"their",
|
|
159
|
+
]);
|
|
160
|
+
function bagOfWords(text) {
|
|
161
|
+
return new Set(text
|
|
162
|
+
.toLowerCase()
|
|
163
|
+
.replace(/[^a-z0-9\s]/g, "")
|
|
164
|
+
.split(/\s+/)
|
|
165
|
+
.filter((w) => w.length > 1 && !BAG_OF_WORDS_STOP_WORDS.has(w)));
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Bitemporal validity predicate: an edge is valid at `timeMs` when its
|
|
169
|
+
* event-time interval covers it. NULL/undefined bounds are open-ended.
|
|
170
|
+
* (eqeqeq-safe explicit null checks — the lint config forbids `== null`.)
|
|
171
|
+
*/
|
|
172
|
+
function isEdgeValidAt(edge, timeMs) {
|
|
173
|
+
const fromOpen = edge.validFrom === undefined || edge.validFrom === null;
|
|
174
|
+
const toOpen = edge.validTo === undefined || edge.validTo === null;
|
|
175
|
+
return ((fromOpen || edge.validFrom <= timeMs) &&
|
|
176
|
+
(toOpen || edge.validTo > timeMs));
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Graph engine managing the in-memory representation of the memory graph.
|
|
180
|
+
*/
|
|
181
|
+
export class GraphEngine {
|
|
182
|
+
/** Adjacency list: nodeId → Set of edge IDs. */
|
|
183
|
+
adjacency = new Map();
|
|
184
|
+
/** Edge lookup: edgeId → MemoryEdge. */
|
|
185
|
+
edges = new Map();
|
|
186
|
+
/** Node lookup: nodeId → MemoryNode. */
|
|
187
|
+
nodes = new Map();
|
|
188
|
+
/**
|
|
189
|
+
* Lazily-computed bag-of-words token sets per node, for autoLink().
|
|
190
|
+
* Populated on first use and invalidated on update/remove — avoids
|
|
191
|
+
* re-tokenizing every existing node on every store().
|
|
192
|
+
*/
|
|
193
|
+
tokenCache = new Map();
|
|
194
|
+
/**
|
|
195
|
+
* Add a node to the graph.
|
|
196
|
+
*
|
|
197
|
+
* @param node — The memory node to add.
|
|
198
|
+
*/
|
|
199
|
+
addNode(node) {
|
|
200
|
+
this.nodes.set(node.id, node);
|
|
201
|
+
// Fresh content for this id — drop any cached token set.
|
|
202
|
+
this.tokenCache.delete(node.id);
|
|
203
|
+
if (!this.adjacency.has(node.id)) {
|
|
204
|
+
this.adjacency.set(node.id, new Set());
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Remove a node and all its connected edges from the graph.
|
|
209
|
+
*
|
|
210
|
+
* @param id — Node ID to remove.
|
|
211
|
+
* @returns `true` if the node existed.
|
|
212
|
+
*/
|
|
213
|
+
removeNode(id) {
|
|
214
|
+
if (!this.nodes.has(id))
|
|
215
|
+
return false;
|
|
216
|
+
// Remove connected edges
|
|
217
|
+
const edgeIds = this.adjacency.get(id);
|
|
218
|
+
if (edgeIds) {
|
|
219
|
+
for (const edgeId of [...edgeIds]) {
|
|
220
|
+
this.removeEdge(edgeId);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
this.nodes.delete(id);
|
|
224
|
+
this.adjacency.delete(id);
|
|
225
|
+
this.tokenCache.delete(id);
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Update a node in the graph.
|
|
230
|
+
*/
|
|
231
|
+
updateNode(node) {
|
|
232
|
+
this.nodes.set(node.id, node);
|
|
233
|
+
// Content may have changed — drop the cached token set.
|
|
234
|
+
this.tokenCache.delete(node.id);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Add an edge to the graph.
|
|
238
|
+
*
|
|
239
|
+
* @param input — Edge creation input. `validFrom`/`validTo` define the
|
|
240
|
+
* bitemporal event-time validity interval (`createdAt` stays the
|
|
241
|
+
* transaction/ingest time); omitted bounds are open-ended.
|
|
242
|
+
* @returns The created edge.
|
|
243
|
+
*/
|
|
244
|
+
addEdge(input) {
|
|
245
|
+
const edge = {
|
|
246
|
+
id: generateId(),
|
|
247
|
+
sourceId: input.sourceId,
|
|
248
|
+
targetId: input.targetId,
|
|
249
|
+
relation: input.relation ?? "relates_to",
|
|
250
|
+
weight: input.weight ?? 0.5,
|
|
251
|
+
metadata: input.metadata ?? {},
|
|
252
|
+
createdAt: Date.now(),
|
|
253
|
+
validFrom: input.validFrom ?? null,
|
|
254
|
+
validTo: input.validTo ?? null,
|
|
255
|
+
};
|
|
256
|
+
this.edges.set(edge.id, edge);
|
|
257
|
+
if (!this.adjacency.has(edge.sourceId)) {
|
|
258
|
+
this.adjacency.set(edge.sourceId, new Set());
|
|
259
|
+
}
|
|
260
|
+
this.adjacency.get(edge.sourceId).add(edge.id);
|
|
261
|
+
if (!this.adjacency.has(edge.targetId)) {
|
|
262
|
+
this.adjacency.set(edge.targetId, new Set());
|
|
263
|
+
}
|
|
264
|
+
this.adjacency.get(edge.targetId).add(edge.id);
|
|
265
|
+
return edge;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Remove an edge from the graph.
|
|
269
|
+
*/
|
|
270
|
+
removeEdge(id) {
|
|
271
|
+
const edge = this.edges.get(id);
|
|
272
|
+
if (!edge)
|
|
273
|
+
return false;
|
|
274
|
+
this.adjacency.get(edge.sourceId)?.delete(id);
|
|
275
|
+
this.adjacency.get(edge.targetId)?.delete(id);
|
|
276
|
+
this.edges.delete(id);
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Lazily-computed bag-of-words token set for a node, cached across
|
|
281
|
+
* autoLink() calls. The cache is invalidated on add/update/remove/clear.
|
|
282
|
+
*/
|
|
283
|
+
tokensFor(node) {
|
|
284
|
+
let tokens = this.tokenCache.get(node.id);
|
|
285
|
+
if (!tokens) {
|
|
286
|
+
tokens = bagOfWords(node.content);
|
|
287
|
+
this.tokenCache.set(node.id, tokens);
|
|
288
|
+
}
|
|
289
|
+
return tokens;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Get all edges connected to a node.
|
|
293
|
+
*/
|
|
294
|
+
getEdgesForNode(nodeId) {
|
|
295
|
+
const edgeIds = this.adjacency.get(nodeId);
|
|
296
|
+
if (!edgeIds)
|
|
297
|
+
return [];
|
|
298
|
+
const result = [];
|
|
299
|
+
for (const edgeId of edgeIds) {
|
|
300
|
+
const edge = this.edges.get(edgeId);
|
|
301
|
+
if (edge)
|
|
302
|
+
result.push(edge);
|
|
303
|
+
}
|
|
304
|
+
return result;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Get neighbours of a node (nodes connected by an edge).
|
|
308
|
+
*/
|
|
309
|
+
getNeighbours(nodeId) {
|
|
310
|
+
const edges = this.getEdgesForNode(nodeId);
|
|
311
|
+
const neighbourIds = new Set();
|
|
312
|
+
for (const edge of edges) {
|
|
313
|
+
if (edge.sourceId === nodeId)
|
|
314
|
+
neighbourIds.add(edge.targetId);
|
|
315
|
+
else
|
|
316
|
+
neighbourIds.add(edge.sourceId);
|
|
317
|
+
}
|
|
318
|
+
const result = [];
|
|
319
|
+
for (const id of neighbourIds) {
|
|
320
|
+
const node = this.nodes.get(id);
|
|
321
|
+
if (node)
|
|
322
|
+
result.push(node);
|
|
323
|
+
}
|
|
324
|
+
return result;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Attempt to auto-link a node to existing nodes based on text similarity.
|
|
328
|
+
*
|
|
329
|
+
* Cost control: linking is O(N) per store, and every accepted link is a
|
|
330
|
+
* persisted row. Without a per-node cap a repetitive corpus converges to
|
|
331
|
+
* a complete graph — K_N edges for N nodes (measured: 100 similar nodes
|
|
332
|
+
* → 4,950 edges, and 300 stores took 2.7s vs 0.1s with linking off).
|
|
333
|
+
* The cap keeps the most similar `maxLinksPerNode` edges and skips the
|
|
334
|
+
* long tail, which preserves cluster structure (`findClusters`,
|
|
335
|
+
* `injectContext`) while making ingestion cost linear-ish in practice.
|
|
336
|
+
*
|
|
337
|
+
* @param node — The node to link.
|
|
338
|
+
* @param threshold — Minimum similarity score to create an edge [0, 1].
|
|
339
|
+
* @param maxLinksPerNode — Hard cap on edges created per call.
|
|
340
|
+
* `0` disables the cap (legacy complete-graph behavior).
|
|
341
|
+
* @returns Array of created edges.
|
|
342
|
+
*/
|
|
343
|
+
autoLink(node, threshold, maxLinksPerNode = DEFAULT_AUTO_LINK_CAP) {
|
|
344
|
+
const created = [];
|
|
345
|
+
// Collect candidates first so the cap keeps the BEST links (highest
|
|
346
|
+
// similarity) rather than whichever happened to be iterated first.
|
|
347
|
+
const candidates = [];
|
|
348
|
+
// Tokenize the new node ONCE and reuse cached token sets for existing
|
|
349
|
+
// nodes: previously both sides were re-tokenized on every comparison
|
|
350
|
+
// (2 x N bagOfWords calls per store).
|
|
351
|
+
const tokensNew = this.tokensFor(node);
|
|
352
|
+
for (const [id, existing] of this.nodes) {
|
|
353
|
+
if (id === node.id)
|
|
354
|
+
continue;
|
|
355
|
+
const sim = tokenSetSimilarity(tokensNew, this.tokensFor(existing));
|
|
356
|
+
if (sim >= threshold) {
|
|
357
|
+
candidates.push({ id, sim });
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
// Cap AFTER collecting, keeping the strongest links.
|
|
361
|
+
const selected = maxLinksPerNode > 0 && candidates.length > maxLinksPerNode
|
|
362
|
+
? candidates.sort((a, b) => b.sim - a.sim).slice(0, maxLinksPerNode)
|
|
363
|
+
: candidates;
|
|
364
|
+
for (const { id, sim } of selected) {
|
|
365
|
+
const edge = this.addEdge({
|
|
366
|
+
sourceId: node.id,
|
|
367
|
+
targetId: id,
|
|
368
|
+
relation: "relates_to",
|
|
369
|
+
weight: sim,
|
|
370
|
+
});
|
|
371
|
+
created.push(edge);
|
|
372
|
+
}
|
|
373
|
+
return created;
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Find clusters of strongly connected nodes using a simple BFS approach.
|
|
377
|
+
*
|
|
378
|
+
* @param minClusterSize — Minimum number of nodes per cluster.
|
|
379
|
+
* @returns Array of clusters (each cluster is an array of node IDs).
|
|
380
|
+
*/
|
|
381
|
+
findClusters(minClusterSize = 2) {
|
|
382
|
+
const visited = new Set();
|
|
383
|
+
const clusters = [];
|
|
384
|
+
for (const nodeId of this.nodes.keys()) {
|
|
385
|
+
if (visited.has(nodeId))
|
|
386
|
+
continue;
|
|
387
|
+
const cluster = [];
|
|
388
|
+
const queue = [nodeId];
|
|
389
|
+
while (queue.length > 0) {
|
|
390
|
+
const current = queue.shift();
|
|
391
|
+
if (visited.has(current))
|
|
392
|
+
continue;
|
|
393
|
+
visited.add(current);
|
|
394
|
+
cluster.push(current);
|
|
395
|
+
const neighbours = this.getNeighbours(current);
|
|
396
|
+
for (const n of neighbours) {
|
|
397
|
+
if (!visited.has(n.id))
|
|
398
|
+
queue.push(n.id);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
if (cluster.length >= minClusterSize) {
|
|
402
|
+
clusters.push(cluster);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
return clusters;
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Get a node by ID.
|
|
409
|
+
*/
|
|
410
|
+
getNode(id) {
|
|
411
|
+
return this.nodes.get(id);
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Get all nodes.
|
|
415
|
+
*/
|
|
416
|
+
getAllNodes() {
|
|
417
|
+
return [...this.nodes.values()];
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Get all edges.
|
|
421
|
+
*/
|
|
422
|
+
getAllEdges() {
|
|
423
|
+
return [...this.edges.values()];
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Bitemporal as-of read: edges whose event-time validity interval covers
|
|
427
|
+
* `timeMs`. NULL bounds are open-ended. Superseded edges (whose
|
|
428
|
+
* `validTo` was stamped by invalidation) are excluded for timestamps
|
|
429
|
+
* at or after their `validTo`, but returned by as-of reads at earlier
|
|
430
|
+
* times — nothing is deleted.
|
|
431
|
+
*
|
|
432
|
+
* @param timeMs — The as-of timestamp (Unix ms).
|
|
433
|
+
*/
|
|
434
|
+
edgesValidAt(timeMs) {
|
|
435
|
+
return [...this.edges.values()].filter((edge) => isEdgeValidAt(edge, timeMs));
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Close (invalidate) the currently-valid edges incident to a node by
|
|
439
|
+
* stamping `validTo`. In-memory edges are mutated in place so the mirror
|
|
440
|
+
* stays consistent with storage; nothing is deleted (add-only).
|
|
441
|
+
*
|
|
442
|
+
* @param nodeId — Node whose incident edges to close.
|
|
443
|
+
* @param timeMs — The invalidation timestamp (Unix ms), usually `now`.
|
|
444
|
+
* @returns The edges that were closed.
|
|
445
|
+
*/
|
|
446
|
+
closeEdgesForNode(nodeId, timeMs) {
|
|
447
|
+
const closed = [];
|
|
448
|
+
for (const edge of this.getEdgesForNode(nodeId)) {
|
|
449
|
+
if (isEdgeValidAt(edge, timeMs)) {
|
|
450
|
+
edge.validTo = timeMs;
|
|
451
|
+
closed.push(edge);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
return closed;
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Node count.
|
|
458
|
+
*/
|
|
459
|
+
get size() {
|
|
460
|
+
return this.nodes.size;
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Clear the entire graph.
|
|
464
|
+
*/
|
|
465
|
+
clear() {
|
|
466
|
+
this.nodes.clear();
|
|
467
|
+
this.edges.clear();
|
|
468
|
+
this.adjacency.clear();
|
|
469
|
+
this.tokenCache.clear();
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Generate a UUID v4.
|
|
474
|
+
*/
|
|
475
|
+
export function generateId() {
|
|
476
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
477
|
+
const r = (Math.random() * 16) | 0;
|
|
478
|
+
const v = c === "x" ? r : (r & 0x3) | 0x8;
|
|
479
|
+
return v.toString(16);
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
//# sourceMappingURL=graph.js.map
|
memos/_js/graph.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.js","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"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"}
|
memos/_js/harness.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Harness attribution for MemOS — "one memory, every harness."
|
|
3
|
+
*
|
|
4
|
+
* Every memory records the agent harness (Claude Code, Cline, Codex,
|
|
5
|
+
* Gemini CLI, OpenClaw, …) that wrote it, stamped deterministically at
|
|
6
|
+
* write time. Detection is environment-based — pure, synchronous, no
|
|
7
|
+
* LLM anywhere — so a fresh process on the same DB file attributes
|
|
8
|
+
* identically to the process that wrote the memory.
|
|
9
|
+
*
|
|
10
|
+
* Detection rules, in priority order:
|
|
11
|
+
*
|
|
12
|
+
* 1. `MEMOS_HARNESS` — explicit override. Wins over everything; this is
|
|
13
|
+
* also the supported seam for tests and for deployments where the
|
|
14
|
+
* harness is known but leaves no env marker.
|
|
15
|
+
* 2. Known harness env markers (prefix match, first hit wins in the
|
|
16
|
+
* table order below).
|
|
17
|
+
* 3. `"unknown"` — unattributed (plain SDK use, legacy rows, tests).
|
|
18
|
+
*
|
|
19
|
+
* The tag is *attribution*, not isolation: it says which harness
|
|
20
|
+
* authored a memory version. Cross-harness reads default to `all`;
|
|
21
|
+
* `recall({ harness })` / `search({ harness })` scope to one harness.
|
|
22
|
+
* When harness B updates a memory written by harness A, the old version
|
|
23
|
+
* keeps its A tag and the replacement carries B — supersession is
|
|
24
|
+
* version-scoped, so the version ledger stays honest.
|
|
25
|
+
*
|
|
26
|
+
* @module @memos/harness
|
|
27
|
+
*/
|
|
28
|
+
/** Attribution value for memories written with no detectable harness. */
|
|
29
|
+
export declare const UNKNOWN_HARNESS = "unknown";
|
|
30
|
+
/** Environment variable that explicitly overrides harness detection. */
|
|
31
|
+
export declare const MEMOS_HARNESS_ENV = "MEMOS_HARNESS";
|
|
32
|
+
/**
|
|
33
|
+
* Known harness env markers. Order is priority: the first matching
|
|
34
|
+
* entry wins, so more specific harnesses must precede less specific
|
|
35
|
+
* ones. `match` is either an exact variable name or a prefix
|
|
36
|
+
* (trailing `_` means "prefix match").
|
|
37
|
+
*/
|
|
38
|
+
export declare const HARNESS_MARKERS: ReadonlyArray<{
|
|
39
|
+
/** Exact env var name or `PREFIX_` for a prefix match. */
|
|
40
|
+
match: string;
|
|
41
|
+
/** Normalized harness slug stamped on memories. */
|
|
42
|
+
harness: string;
|
|
43
|
+
}>;
|
|
44
|
+
/**
|
|
45
|
+
* Normalize a raw harness name to a stable slug: trimmed, lowercased,
|
|
46
|
+
* whitespace/underscores collapsed to `-`. Empty input normalizes to
|
|
47
|
+
* {@link UNKNOWN_HARNESS}.
|
|
48
|
+
*/
|
|
49
|
+
export declare function normalizeHarness(raw: string): string;
|
|
50
|
+
/**
|
|
51
|
+
* Deterministically detect the current harness from the environment.
|
|
52
|
+
*
|
|
53
|
+
* Pure function of its input — pass `process.env` in production, a
|
|
54
|
+
* stub record in tests. Scans each marker in priority order; the first
|
|
55
|
+
* env var that is set and non-empty wins. `MEMOS_HARNESS` always wins.
|
|
56
|
+
*
|
|
57
|
+
* @param env — Environment mapping. Defaults to `process.env`.
|
|
58
|
+
* @returns A harness slug (`"claude-code"`, `"cline"`, `"codex"`,
|
|
59
|
+
* `"gemini-cli"`, `"openclaw"`, a `MEMOS_HARNESS` slug, or
|
|
60
|
+
* `"unknown"`).
|
|
61
|
+
*/
|
|
62
|
+
export declare function detectHarness(env?: NodeJS.ProcessEnv | Record<string, string | undefined>): string;
|
|
63
|
+
//# sourceMappingURL=harness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harness.d.ts","sourceRoot":"","sources":["../src/harness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,yEAAyE;AACzE,eAAO,MAAM,eAAe,YAAY,CAAC;AAEzC,wEAAwE;AACxE,eAAO,MAAM,iBAAiB,kBAAkB,CAAC;AAEjD;;;;;GAKG;AACH,eAAO,MAAM,eAAe,EAAE,aAAa,CAAC;IAC1C,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;CACjB,CAOA,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAOpD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,GAAG,GAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACxE,MAAM,CAsBR"}
|
memos/_js/harness.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Harness attribution for MemOS — "one memory, every harness."
|
|
3
|
+
*
|
|
4
|
+
* Every memory records the agent harness (Claude Code, Cline, Codex,
|
|
5
|
+
* Gemini CLI, OpenClaw, …) that wrote it, stamped deterministically at
|
|
6
|
+
* write time. Detection is environment-based — pure, synchronous, no
|
|
7
|
+
* LLM anywhere — so a fresh process on the same DB file attributes
|
|
8
|
+
* identically to the process that wrote the memory.
|
|
9
|
+
*
|
|
10
|
+
* Detection rules, in priority order:
|
|
11
|
+
*
|
|
12
|
+
* 1. `MEMOS_HARNESS` — explicit override. Wins over everything; this is
|
|
13
|
+
* also the supported seam for tests and for deployments where the
|
|
14
|
+
* harness is known but leaves no env marker.
|
|
15
|
+
* 2. Known harness env markers (prefix match, first hit wins in the
|
|
16
|
+
* table order below).
|
|
17
|
+
* 3. `"unknown"` — unattributed (plain SDK use, legacy rows, tests).
|
|
18
|
+
*
|
|
19
|
+
* The tag is *attribution*, not isolation: it says which harness
|
|
20
|
+
* authored a memory version. Cross-harness reads default to `all`;
|
|
21
|
+
* `recall({ harness })` / `search({ harness })` scope to one harness.
|
|
22
|
+
* When harness B updates a memory written by harness A, the old version
|
|
23
|
+
* keeps its A tag and the replacement carries B — supersession is
|
|
24
|
+
* version-scoped, so the version ledger stays honest.
|
|
25
|
+
*
|
|
26
|
+
* @module @memos/harness
|
|
27
|
+
*/
|
|
28
|
+
/** Attribution value for memories written with no detectable harness. */
|
|
29
|
+
export const UNKNOWN_HARNESS = "unknown";
|
|
30
|
+
/** Environment variable that explicitly overrides harness detection. */
|
|
31
|
+
export const MEMOS_HARNESS_ENV = "MEMOS_HARNESS";
|
|
32
|
+
/**
|
|
33
|
+
* Known harness env markers. Order is priority: the first matching
|
|
34
|
+
* entry wins, so more specific harnesses must precede less specific
|
|
35
|
+
* ones. `match` is either an exact variable name or a prefix
|
|
36
|
+
* (trailing `_` means "prefix match").
|
|
37
|
+
*/
|
|
38
|
+
export const HARNESS_MARKERS = [
|
|
39
|
+
{ match: "CLAUDECODE", harness: "claude-code" },
|
|
40
|
+
{ match: "CLAUDE_CODE_", harness: "claude-code" },
|
|
41
|
+
{ match: "CLINE_", harness: "cline" },
|
|
42
|
+
{ match: "CODEX_", harness: "codex" },
|
|
43
|
+
{ match: "GEMINI_", harness: "gemini-cli" },
|
|
44
|
+
{ match: "OPENCLAW_", harness: "openclaw" },
|
|
45
|
+
];
|
|
46
|
+
/**
|
|
47
|
+
* Normalize a raw harness name to a stable slug: trimmed, lowercased,
|
|
48
|
+
* whitespace/underscores collapsed to `-`. Empty input normalizes to
|
|
49
|
+
* {@link UNKNOWN_HARNESS}.
|
|
50
|
+
*/
|
|
51
|
+
export function normalizeHarness(raw) {
|
|
52
|
+
const slug = raw
|
|
53
|
+
.trim()
|
|
54
|
+
.toLowerCase()
|
|
55
|
+
.replace(/[\s_]+/g, "-")
|
|
56
|
+
.replace(/[^a-z0-9-]/g, "");
|
|
57
|
+
return slug.length > 0 ? slug : UNKNOWN_HARNESS;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Deterministically detect the current harness from the environment.
|
|
61
|
+
*
|
|
62
|
+
* Pure function of its input — pass `process.env` in production, a
|
|
63
|
+
* stub record in tests. Scans each marker in priority order; the first
|
|
64
|
+
* env var that is set and non-empty wins. `MEMOS_HARNESS` always wins.
|
|
65
|
+
*
|
|
66
|
+
* @param env — Environment mapping. Defaults to `process.env`.
|
|
67
|
+
* @returns A harness slug (`"claude-code"`, `"cline"`, `"codex"`,
|
|
68
|
+
* `"gemini-cli"`, `"openclaw"`, a `MEMOS_HARNESS` slug, or
|
|
69
|
+
* `"unknown"`).
|
|
70
|
+
*/
|
|
71
|
+
export function detectHarness(env = process.env) {
|
|
72
|
+
const override = env[MEMOS_HARNESS_ENV];
|
|
73
|
+
if (override !== undefined && override.trim().length > 0) {
|
|
74
|
+
return normalizeHarness(override);
|
|
75
|
+
}
|
|
76
|
+
const names = Object.keys(env);
|
|
77
|
+
for (const marker of HARNESS_MARKERS) {
|
|
78
|
+
if (marker.match.endsWith("_")) {
|
|
79
|
+
// Prefix marker, e.g. CLAUDE_CODE_ matches CLAUDE_CODE_ENTRYPOINT.
|
|
80
|
+
const hit = names.some((name) => name.startsWith(marker.match) && (env[name] ?? "").trim().length > 0);
|
|
81
|
+
if (hit)
|
|
82
|
+
return marker.harness;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
const value = env[marker.match];
|
|
86
|
+
if (value !== undefined && value.trim().length > 0) {
|
|
87
|
+
return marker.harness;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return UNKNOWN_HARNESS;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=harness.js.map
|
memos/_js/harness.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harness.js","sourceRoot":"","sources":["../src/harness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,yEAAyE;AACzE,MAAM,CAAC,MAAM,eAAe,GAAG,SAAS,CAAC;AAEzC,wEAAwE;AACxE,MAAM,CAAC,MAAM,iBAAiB,GAAG,eAAe,CAAC;AAEjD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,eAAe,GAKvB;IACH,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,aAAa,EAAE;IAC/C,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,aAAa,EAAE;IACjD,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE;IACrC,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE;IACrC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE;IAC3C,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE;CAC5C,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,MAAM,IAAI,GAAG,GAAG;SACb,IAAI,EAAE;SACN,WAAW,EAAE;SACb,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;IAC9B,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC;AAClD,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,aAAa,CAC3B,GAAG,GAA2D,OAAO,CAAC,GAAG;IAEzE,MAAM,QAAQ,GAAG,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACxC,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzD,OAAO,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/B,KAAK,MAAM,MAAM,IAAI,eAAe,EAAE,CAAC;QACrC,IAAI,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/B,mEAAmE;YACnE,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CACpB,CAAC,IAAI,EAAE,EAAE,CACP,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CACvE,CAAC;YACF,IAAI,GAAG;gBAAE,OAAO,MAAM,CAAC,OAAO,CAAC;QACjC,CAAC;aAAM,CAAC;YACN,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAChC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACnD,OAAO,MAAM,CAAC,OAAO,CAAC;YACxB,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,eAAe,CAAC;AACzB,CAAC"}
|