gnosys 5.15.3 → 5.17.0
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/README.md +1 -1
- package/dist/cli.js +6 -0
- package/dist/index.js +26 -3
- package/dist/lib/cleanup.js +2 -17
- package/dist/lib/paths.d.ts +1 -0
- package/dist/lib/paths.js +29 -0
- package/dist/lib/resolver.js +11 -1
- package/dist/lib/rulesGen.js +2 -2
- package/dist/lib/setupSyncProjectsCommand.js +36 -12
- package/dist/lib/staticSearch.d.ts +30 -0
- package/dist/lib/staticSearch.js +235 -6
- package/dist/lib/webBuildCommand.d.ts +3 -0
- package/dist/lib/webBuildCommand.js +61 -5
- package/dist/lib/webBuildIndexCommand.d.ts +3 -0
- package/dist/lib/webBuildIndexCommand.js +54 -3
- package/dist/lib/webIndex.d.ts +17 -0
- package/dist/lib/webIndex.js +127 -1
- package/dist/lib/webInitCommand.js +1 -0
- package/dist/lib/webStatusCommand.js +34 -0
- package/dist/lib/webVectors.d.ts +32 -0
- package/dist/lib/webVectors.js +255 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,7 +51,7 @@ That's the 60-second tour. **Everything else lives on [gnosys.ai](https://gnosys
|
|
|
51
51
|
- **Central brain** — one `~/.gnosys/gnosys.db` unifies every project (project / user / global scopes). Sub-10ms reads, SQLite as the sole source of truth.
|
|
52
52
|
- **Federated search** — tier-boosted hybrid (FTS5 keyword + semantic) search across scopes, with recency and reinforcement.
|
|
53
53
|
- **MCP server** — `gnosys serve` exposes 50+ memory tools to any MCP client. Sandbox-first runtime keeps context cost near zero.
|
|
54
|
-
- **Web Knowledge Base** — `gnosys web build` turns any site into a searchable index for serverless chatbots. Zero runtime deps.
|
|
54
|
+
- **Web Knowledge Base** — `gnosys web build` turns any site into a searchable index for serverless chatbots, with optional build-time vectors for serverless-safe hybrid semantic search. Zero runtime deps.
|
|
55
55
|
- **Dream Mode** — idle-time consolidation: confidence decay, summaries, relationship discovery. Never deletes — only suggests.
|
|
56
56
|
- **Multi-machine sync** — share your brain across machines; conflict detection with skip-and-flag resolution.
|
|
57
57
|
- **Obsidian export** — `gnosys export` regenerates a full vault with frontmatter, `[[wikilinks]]`, and graph data.
|
package/dist/cli.js
CHANGED
|
@@ -1788,6 +1788,9 @@ webCmd
|
|
|
1788
1788
|
.option("--input <dir>", "Override knowledge directory")
|
|
1789
1789
|
.option("--output <path>", "Override output file path")
|
|
1790
1790
|
.option("--no-stop-words", "Disable stop-word filtering")
|
|
1791
|
+
.option("--embeddings <provider>", "Also build gnosys-vectors.json (openai|voyage|local)")
|
|
1792
|
+
.option("--embed-model <id>", "Override the embedding model")
|
|
1793
|
+
.option("--no-expansions", "Skip LLM concept-expansion generation")
|
|
1791
1794
|
.option("--json", "Output index stats as JSON")
|
|
1792
1795
|
.action(async (opts) => {
|
|
1793
1796
|
const { runWebBuildIndexCommand } = await import("./lib/webBuildIndexCommand.js");
|
|
@@ -1801,6 +1804,9 @@ webCmd
|
|
|
1801
1804
|
.option("--no-llm", "Force structured mode (no LLM)")
|
|
1802
1805
|
.option("--concurrency <n>", "Parallel processing limit", "3")
|
|
1803
1806
|
.option("--dry-run", "Show what would change without writing files")
|
|
1807
|
+
.option("--embeddings <provider>", "Also build gnosys-vectors.json (openai|voyage|local)")
|
|
1808
|
+
.option("--embed-model <id>", "Override the embedding model")
|
|
1809
|
+
.option("--no-expansions", "Skip LLM concept-expansion generation")
|
|
1804
1810
|
.option("--json", "Output results as JSON")
|
|
1805
1811
|
.action(async (opts) => {
|
|
1806
1812
|
const { runWebBuildCommand } = await import("./lib/webBuildCommand.js");
|
package/dist/index.js
CHANGED
|
@@ -624,7 +624,7 @@ regTool("gnosys_list", "List memories across all stores, optionally filtered by
|
|
|
624
624
|
}
|
|
625
625
|
});
|
|
626
626
|
// ─── Tool: gnosys_add ────────────────────────────────────────────────────
|
|
627
|
-
regTool("gnosys_add", "
|
|
627
|
+
regTool("gnosys_add", "DO NOT USE if you are an LLM agent — call gnosys_add_structured instead (you structure the memory yourself; no redundant server-side LLM call). This freeform tool is REJECTED by default over MCP and only works when the operator sets GNOSYS_ALLOW_FREEFORM_ADD=1 for genuine non-agent callers (scripts, cron). Writes to the project store by default. Use store='personal' for cross-project knowledge, or store='global' to explicitly write to shared org knowledge.", {
|
|
628
628
|
input: z
|
|
629
629
|
.string()
|
|
630
630
|
.describe("Raw text input. Can be a decision, concept, fact, observation, or any knowledge."),
|
|
@@ -642,6 +642,29 @@ regTool("gnosys_add", "Add a new memory from raw text — the server's LLM struc
|
|
|
642
642
|
.describe("Epistemic trust level"),
|
|
643
643
|
projectRoot: projectRootParam,
|
|
644
644
|
}, async ({ input, store: targetStore, author, authority, projectRoot }) => {
|
|
645
|
+
// Hard gate (2026-07-04 decision): every MCP caller in practice is an
|
|
646
|
+
// LLM agent, and agents must use gnosys_add_structured — the freeform
|
|
647
|
+
// path burns a second server-side LLM call and silently fails without
|
|
648
|
+
// a provider key. Reject by default with a redirect the agent can act
|
|
649
|
+
// on immediately. Genuine non-agent MCP callers opt in via env.
|
|
650
|
+
if (process.env.GNOSYS_ALLOW_FREEFORM_ADD !== "1") {
|
|
651
|
+
return {
|
|
652
|
+
content: [
|
|
653
|
+
{
|
|
654
|
+
type: "text",
|
|
655
|
+
text: "gnosys_add is disabled for LLM agents. Call gnosys_add_structured instead — " +
|
|
656
|
+
"structure the memory yourself and pass: title (string), category " +
|
|
657
|
+
"(architecture|decisions|requirements|concepts|roadmap|landscape|open-questions), " +
|
|
658
|
+
"tags (object of string arrays, e.g. { domain: ['auth'], type: ['decision'] }), " +
|
|
659
|
+
"content (markdown body), relevance (space-separated keyword cloud for discovery), " +
|
|
660
|
+
"plus the same store/author/authority/projectRoot values you passed here. " +
|
|
661
|
+
"Retry now with gnosys_add_structured using the same input. " +
|
|
662
|
+
"(Non-agent scripts can re-enable this tool with GNOSYS_ALLOW_FREEFORM_ADD=1.)",
|
|
663
|
+
},
|
|
664
|
+
],
|
|
665
|
+
isError: true,
|
|
666
|
+
};
|
|
667
|
+
}
|
|
645
668
|
const ctx = await resolveToolContext(projectRoot);
|
|
646
669
|
const writeTarget = ctx.resolver.getWriteTarget(targetStore || undefined);
|
|
647
670
|
if (!writeTarget) {
|
|
@@ -972,7 +995,7 @@ regTool("gnosys_init", "Initialize Gnosys in a project directory. Creates .gnosy
|
|
|
972
995
|
content: [
|
|
973
996
|
{
|
|
974
997
|
type: "text",
|
|
975
|
-
text: `Gnosys store ${action} at ${storePath}\n\nProject Identity:\n- ID: ${identity.projectId}\n- Name: ${identity.projectName}\n- Directory: ${identity.workingDirectory}\n- Agent rules target: ${identity.agentRulesTarget || "none detected"}\n- Central DB: ${centralDb?.isAvailable() ? "registered ✓" : "not available"}\n\n${isResync ? "Identity re-synced." : "Created:\n- gnosys.json (project identity)\n- .config/ (internal config)\n- tags.json (tag registry)"}${hookInfo}\n\nThe store is ready. Use gnosys_discover to find existing memories or
|
|
998
|
+
text: `Gnosys store ${action} at ${storePath}\n\nProject Identity:\n- ID: ${identity.projectId}\n- Name: ${identity.projectName}\n- Directory: ${identity.workingDirectory}\n- Agent rules target: ${identity.agentRulesTarget || "none detected"}\n- Central DB: ${centralDb?.isAvailable() ? "registered ✓" : "not available"}\n\n${isResync ? "Identity re-synced." : "Created:\n- gnosys.json (project identity)\n- .config/ (internal config)\n- tags.json (tag registry)"}${hookInfo}\n\nThe store is ready. Use gnosys_discover to find existing memories or gnosys_add_structured to create new ones.`,
|
|
976
999
|
},
|
|
977
1000
|
],
|
|
978
1001
|
};
|
|
@@ -2216,7 +2239,7 @@ regTool("gnosys_stores", "Debug tool — lists all detected Gnosys stores across
|
|
|
2216
2239
|
// Usage hint
|
|
2217
2240
|
lines.push("USAGE:");
|
|
2218
2241
|
lines.push(" Pass projectRoot to any tool to target a specific project:");
|
|
2219
|
-
lines.push(' e.g.
|
|
2242
|
+
lines.push(' e.g. gnosys_add_structured({ projectRoot: "/path/to/my-project", ... })');
|
|
2220
2243
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
2221
2244
|
}
|
|
2222
2245
|
catch (err) {
|
package/dist/lib/cleanup.js
CHANGED
|
@@ -21,28 +21,13 @@
|
|
|
21
21
|
import fs from "fs/promises";
|
|
22
22
|
import fsSync from "fs";
|
|
23
23
|
import path from "path";
|
|
24
|
-
import os from "os";
|
|
25
24
|
import { createInterface } from "readline/promises";
|
|
26
25
|
import { stdin, stdout } from "process";
|
|
27
|
-
import { getProjectRegistryPath } from "./paths.js";
|
|
26
|
+
import { getProjectRegistryPath, isTempProjectPath } from "./paths.js";
|
|
28
27
|
import { safeQuestion } from "./setup/ui/safePrompt.js";
|
|
29
28
|
import { Header } from "./setup/ui/header.js";
|
|
30
29
|
import { Status } from "./setup/ui/status.js";
|
|
31
30
|
import { c, color, glyph } from "./setup/ui/tokens.js";
|
|
32
|
-
const TEMP_PREFIXES = [
|
|
33
|
-
"/tmp/",
|
|
34
|
-
"/private/tmp/",
|
|
35
|
-
"/var/folders/",
|
|
36
|
-
"/private/var/folders/",
|
|
37
|
-
];
|
|
38
|
-
function isTempPath(p) {
|
|
39
|
-
const resolved = path.resolve(p);
|
|
40
|
-
if (TEMP_PREFIXES.some((prefix) => resolved.startsWith(prefix)))
|
|
41
|
-
return true;
|
|
42
|
-
// Honor the system tmpdir too (covers $TMPDIR overrides on CI etc.).
|
|
43
|
-
const sysTmp = path.resolve(os.tmpdir()) + path.sep;
|
|
44
|
-
return resolved.startsWith(sysTmp);
|
|
45
|
-
}
|
|
46
31
|
function isAlive(p) {
|
|
47
32
|
try {
|
|
48
33
|
const stat = fsSync.statSync(path.join(p, ".gnosys"));
|
|
@@ -74,7 +59,7 @@ export async function classifyRegistryEntries() {
|
|
|
74
59
|
const dead = [];
|
|
75
60
|
const temp = [];
|
|
76
61
|
for (const e of entries) {
|
|
77
|
-
if (
|
|
62
|
+
if (isTempProjectPath(e)) {
|
|
78
63
|
temp.push(e);
|
|
79
64
|
}
|
|
80
65
|
else if (isAlive(e)) {
|
package/dist/lib/paths.d.ts
CHANGED
package/dist/lib/paths.js
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* reproduce the `path.join(os.homedir(), ".gnosys")` pattern inline.
|
|
24
24
|
*/
|
|
25
25
|
import path from "path";
|
|
26
|
+
import os from "os";
|
|
26
27
|
export function getGnosysHome() {
|
|
27
28
|
if (process.env.GNOSYS_HOME)
|
|
28
29
|
return process.env.GNOSYS_HOME;
|
|
@@ -45,6 +46,13 @@ export function getSandboxDir() {
|
|
|
45
46
|
function getConfigDir() {
|
|
46
47
|
if (process.env.GNOSYS_CONFIG_DIR)
|
|
47
48
|
return process.env.GNOSYS_CONFIG_DIR;
|
|
49
|
+
// GNOSYS_HOME redirects "everything gnosys-owned" (see header comment).
|
|
50
|
+
// Before this, tests that set GNOSYS_HOME still wrote the project
|
|
51
|
+
// registry into the user's REAL ~/.config/gnosys/projects.json — every
|
|
52
|
+
// test run leaked hundreds of /var/folders/... temp entries into it.
|
|
53
|
+
if (process.env.GNOSYS_HOME) {
|
|
54
|
+
return path.join(process.env.GNOSYS_HOME, "config");
|
|
55
|
+
}
|
|
48
56
|
const home = process.env.HOME || process.env.USERPROFILE || "/tmp";
|
|
49
57
|
return path.join(home, ".config", "gnosys");
|
|
50
58
|
}
|
|
@@ -65,3 +73,24 @@ export function getProjectRegistryPath() {
|
|
|
65
73
|
export function getMachineConfigPath() {
|
|
66
74
|
return path.join(getConfigDir(), "machine.json");
|
|
67
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* True when a project path lives under a system temp location (/tmp,
|
|
78
|
+
* /var/folders, or os.tmpdir()). Such paths are transient — test
|
|
79
|
+
* scaffolding, throwaway scratch dirs — and must never be treated as
|
|
80
|
+
* durable registered projects. Shared by cleanup, registration, and
|
|
81
|
+
* sync-projects so all three agree on what "temp" means.
|
|
82
|
+
*/
|
|
83
|
+
const TEMP_PATH_PREFIXES = [
|
|
84
|
+
"/tmp/",
|
|
85
|
+
"/private/tmp/",
|
|
86
|
+
"/var/folders/",
|
|
87
|
+
"/private/var/folders/",
|
|
88
|
+
];
|
|
89
|
+
export function isTempProjectPath(p) {
|
|
90
|
+
const resolved = path.resolve(p);
|
|
91
|
+
if (TEMP_PATH_PREFIXES.some((prefix) => resolved.startsWith(prefix))) {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
const sysTmp = path.resolve(os.tmpdir()) + path.sep;
|
|
95
|
+
return resolved.startsWith(sysTmp);
|
|
96
|
+
}
|
package/dist/lib/resolver.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import fs from "fs/promises";
|
|
11
11
|
import path from "path";
|
|
12
|
-
import { getProjectRegistryPath } from "./paths.js";
|
|
12
|
+
import { getProjectRegistryPath, isTempProjectPath } from "./paths.js";
|
|
13
13
|
import { GnosysStore } from "./store.js";
|
|
14
14
|
/**
|
|
15
15
|
* v5.9.1 (#98): read just the projectId from a project's gnosys.json
|
|
@@ -273,6 +273,16 @@ export class GnosysResolver {
|
|
|
273
273
|
*/
|
|
274
274
|
async registerProject(projectDir) {
|
|
275
275
|
const configPath = this.getRegistryPath();
|
|
276
|
+
// Never register temp-dir projects (/tmp, /var/folders, os.tmpdir())
|
|
277
|
+
// in the user's REAL registry — those are test scaffolding or scratch
|
|
278
|
+
// dirs that vanish, then linger as stale entries `gnosys setup
|
|
279
|
+
// sync-projects` counts forever. When GNOSYS_HOME / GNOSYS_CONFIG_DIR
|
|
280
|
+
// redirects the registry (tests, sandboxes), temp paths are allowed,
|
|
281
|
+
// since the whole registry is itself transient.
|
|
282
|
+
const registryIsIsolated = Boolean(process.env.GNOSYS_HOME) || Boolean(process.env.GNOSYS_CONFIG_DIR);
|
|
283
|
+
if (!registryIsIsolated && isTempProjectPath(projectDir)) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
276
286
|
let projects = [];
|
|
277
287
|
try {
|
|
278
288
|
const raw = await fs.readFile(configPath, "utf-8");
|
package/dist/lib/rulesGen.js
CHANGED
|
@@ -35,7 +35,7 @@ This project uses **Gnosys** for persistent memory via MCP. Gnosys uses a centra
|
|
|
35
35
|
|
|
36
36
|
### Write automatically
|
|
37
37
|
|
|
38
|
-
- **Always write with \`gnosys_add_structured\`** — you are an LLM, so structure the memory yourself (title, category, tags, content, relevance) and pass the explicit fields.
|
|
38
|
+
- **Always write with \`gnosys_add_structured\`** — you are an LLM, so structure the memory yourself (title, category, tags, content, relevance) and pass the explicit fields. NEVER call the freeform \`gnosys_add\`: the server **rejects it with an error** for MCP callers (it would run a second, redundant LLM call and depends on a provider key that can fail silently). \`gnosys_add_structured\` makes no server-side model call. (Freeform \`gnosys_add\` exists only for non-agent scripts/cron, which must set GNOSYS_ALLOW_FREEFORM_ADD=1.)
|
|
39
39
|
- When user says "remember", "memorize", "save this", "note this down", "don't forget" — call \`gnosys_add_structured\`
|
|
40
40
|
- When user states a decision or preference (even casually) — commit to \`decisions\` category
|
|
41
41
|
- When user provides a spec or plan — commit BEFORE starting work
|
|
@@ -48,7 +48,7 @@ This project uses **Gnosys** for persistent memory via MCP. Gnosys uses a centra
|
|
|
48
48
|
|--------|------|
|
|
49
49
|
| Find memories | \`gnosys_discover\` (metadata) → \`gnosys_read\` (content) |
|
|
50
50
|
| Search | \`gnosys_hybrid_search\` (best), \`gnosys_federated_search\` (cross-project), \`gnosys_search\` (keyword), \`gnosys_ask\` (Q&A) |
|
|
51
|
-
| Write | \`gnosys_add_structured\` (explicit fields — **always use this as an agent**; no server-side LLM call). \`gnosys_add\` (freeform) is for non-agent
|
|
51
|
+
| Write | \`gnosys_add_structured\` (explicit fields — **always use this as an agent**; no server-side LLM call). \`gnosys_add\` (freeform) is rejected for MCP callers — non-agent scripts only. |
|
|
52
52
|
| Update | \`gnosys_update\`, \`gnosys_reinforce\` (useful/not_relevant/outdated) |
|
|
53
53
|
| Browse | \`gnosys_list\`, \`gnosys_lens\` (filtered), \`gnosys_tags\`, \`gnosys_graph\` |
|
|
54
54
|
| Maintain | \`gnosys_maintain\`, \`gnosys_stale\`, \`gnosys_history\`, \`gnosys_dashboard\` |
|
|
@@ -22,7 +22,11 @@ export async function runSetupSyncProjectsCommand(opts) {
|
|
|
22
22
|
console.log("");
|
|
23
23
|
// 1. Read registered projects from file registry AND central DB
|
|
24
24
|
const home = process.env.HOME || process.env.USERPROFILE || "/tmp";
|
|
25
|
-
const
|
|
25
|
+
const { getProjectRegistryPath, isTempProjectPath } = await import("./paths.js");
|
|
26
|
+
// Registry lives at ~/.config/gnosys/projects.json (or under
|
|
27
|
+
// GNOSYS_HOME/GNOSYS_CONFIG_DIR when isolated) — always resolved via
|
|
28
|
+
// the shared helper, never hand-rolled from HOME.
|
|
29
|
+
const registryPath = getProjectRegistryPath();
|
|
26
30
|
let fileProjects = [];
|
|
27
31
|
try {
|
|
28
32
|
fileProjects = JSON.parse(await fs.readFile(registryPath, "utf-8"));
|
|
@@ -39,24 +43,46 @@ export async function runSetupSyncProjectsCommand(opts) {
|
|
|
39
43
|
const centralDb = GnosysDB.openCentral();
|
|
40
44
|
if (centralDb.isAvailable()) {
|
|
41
45
|
const allProjects = centralDb.getAllProjects();
|
|
42
|
-
|
|
43
|
-
|
|
46
|
+
// Purge temp-dir ghosts (leaked by test runs) from the central DB
|
|
47
|
+
// so they stop resurfacing in every future sync.
|
|
48
|
+
for (const p of allProjects) {
|
|
49
|
+
if (isTempProjectPath(p.working_directory)) {
|
|
50
|
+
try {
|
|
51
|
+
centralDb.deleteProject(p.id);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// non-critical
|
|
55
|
+
}
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
dbProjects.push(p.working_directory);
|
|
44
59
|
titleByDir.set(p.working_directory, p.name);
|
|
60
|
+
}
|
|
45
61
|
centralDb.close();
|
|
46
62
|
}
|
|
47
63
|
}
|
|
48
64
|
catch {
|
|
49
65
|
// non-critical
|
|
50
66
|
}
|
|
51
|
-
// Merge: deduplicate by resolved path
|
|
67
|
+
// Merge: deduplicate by resolved path. Temp-dir entries (/tmp,
|
|
68
|
+
// /var/folders — leaked by old versions' test runs) are dropped here,
|
|
69
|
+
// BEFORE the count and the registry write-back. Previously they were
|
|
70
|
+
// only skipped inside the upgrade loop, so "syncing N registered
|
|
71
|
+
// projects" reported hundreds of ghosts and the write-back on line
|
|
72
|
+
// below re-persisted them forever.
|
|
52
73
|
const seen = new Set();
|
|
53
74
|
const projects = [];
|
|
75
|
+
let droppedTemp = 0;
|
|
54
76
|
for (const p of [...fileProjects, ...dbProjects]) {
|
|
55
77
|
const resolved = path.resolve(p);
|
|
56
|
-
if (
|
|
57
|
-
|
|
58
|
-
|
|
78
|
+
if (seen.has(resolved))
|
|
79
|
+
continue;
|
|
80
|
+
seen.add(resolved);
|
|
81
|
+
if (isTempProjectPath(resolved)) {
|
|
82
|
+
droppedTemp++;
|
|
83
|
+
continue;
|
|
59
84
|
}
|
|
85
|
+
projects.push(resolved);
|
|
60
86
|
}
|
|
61
87
|
if (projects.length === 0) {
|
|
62
88
|
console.log(" no registered projects found");
|
|
@@ -79,10 +105,7 @@ export async function runSetupSyncProjectsCommand(opts) {
|
|
|
79
105
|
const skipped = [];
|
|
80
106
|
const failed = [];
|
|
81
107
|
for (const projectDir of projects) {
|
|
82
|
-
//
|
|
83
|
-
if (projectDir.startsWith("/tmp/") || projectDir.startsWith("/private/tmp/") || projectDir.startsWith("/var/folders/") || projectDir.startsWith("/private/var/folders/")) {
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
108
|
+
// Temp/test directories were already filtered out of `projects`.
|
|
86
109
|
const storePath = path.join(projectDir, ".gnosys");
|
|
87
110
|
try {
|
|
88
111
|
await fs.stat(storePath);
|
|
@@ -131,7 +154,8 @@ export async function runSetupSyncProjectsCommand(opts) {
|
|
|
131
154
|
}
|
|
132
155
|
// Stop the lead-in spinner now that the iteration is done. Resolved
|
|
133
156
|
// before any per-section output so the cursor is on a fresh line.
|
|
134
|
-
syncSpinner.ok(`synced ${projects.length} registered projects`, `${upgraded.length} upgraded · ${skipped.length} skipped · ${failed.length} failed`
|
|
157
|
+
syncSpinner.ok(`synced ${projects.length} registered projects`, `${upgraded.length} upgraded · ${skipped.length} skipped · ${failed.length} failed` +
|
|
158
|
+
(droppedTemp > 0 ? ` · ${droppedTemp} temp entries pruned` : ""));
|
|
135
159
|
// 3. Update global agent rules
|
|
136
160
|
try {
|
|
137
161
|
let centralDb = null;
|
|
@@ -13,6 +13,17 @@ export interface GnosysWebIndex {
|
|
|
13
13
|
documentCount: number;
|
|
14
14
|
documents: DocumentManifest[];
|
|
15
15
|
invertedIndex: Record<string, IndexEntry[]>;
|
|
16
|
+
expansions?: Record<string, string[]>;
|
|
17
|
+
}
|
|
18
|
+
export interface GnosysWebVectors {
|
|
19
|
+
version: number;
|
|
20
|
+
model: string;
|
|
21
|
+
dims: number;
|
|
22
|
+
quantization: "int8";
|
|
23
|
+
generated: string;
|
|
24
|
+
scale: number;
|
|
25
|
+
offset: number;
|
|
26
|
+
vectors: Record<string, number[]>;
|
|
16
27
|
}
|
|
17
28
|
export interface DocumentManifest {
|
|
18
29
|
id: string;
|
|
@@ -36,21 +47,40 @@ export interface SearchOptions {
|
|
|
36
47
|
category?: string;
|
|
37
48
|
tags?: string[];
|
|
38
49
|
boostRecent?: boolean;
|
|
50
|
+
queryVector?: number[];
|
|
51
|
+
vectors?: GnosysWebVectors;
|
|
52
|
+
expectedModel?: string;
|
|
53
|
+
expandQuery?: boolean;
|
|
39
54
|
}
|
|
40
55
|
export interface SearchResult {
|
|
41
56
|
document: DocumentManifest;
|
|
42
57
|
score: number;
|
|
43
58
|
matchedTokens: string[];
|
|
59
|
+
semanticScore?: number;
|
|
44
60
|
}
|
|
45
61
|
/**
|
|
46
62
|
* Load a pre-computed Gnosys web index from a file path or raw JSON string.
|
|
47
63
|
* Caches the result for repeated calls with the same source.
|
|
48
64
|
*/
|
|
49
65
|
export declare function loadIndex(pathOrJson: string): GnosysWebIndex;
|
|
66
|
+
/**
|
|
67
|
+
* Load pre-computed Gnosys web vectors from a file path or raw JSON string.
|
|
68
|
+
* Caches the result for repeated calls with the same source.
|
|
69
|
+
*/
|
|
70
|
+
export declare function loadVectors(pathOrJson: string): GnosysWebVectors;
|
|
50
71
|
/**
|
|
51
72
|
* Clear the cached index (useful for testing).
|
|
52
73
|
*/
|
|
53
74
|
export declare function clearIndexCache(): void;
|
|
75
|
+
/**
|
|
76
|
+
* Clear the cached vectors file (useful for testing).
|
|
77
|
+
*/
|
|
78
|
+
export declare function clearVectorsCache(): void;
|
|
79
|
+
/**
|
|
80
|
+
* Cosine similarity for equal-dimension vectors. Returns 0 for zero-magnitude
|
|
81
|
+
* vectors or dimension mismatches.
|
|
82
|
+
*/
|
|
83
|
+
export declare function cosineSimilarity(a: number[], b: number[]): number;
|
|
54
84
|
/**
|
|
55
85
|
* Search the pre-computed index and return ranked results.
|
|
56
86
|
*/
|