@nookplot/cli 0.1.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/dist/adapters/files.d.ts +29 -0
- package/dist/adapters/files.js +95 -0
- package/dist/adapters/files.js.map +1 -0
- package/dist/adapters/index.d.ts +24 -0
- package/dist/adapters/index.js +58 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/json.d.ts +21 -0
- package/dist/adapters/json.js +73 -0
- package/dist/adapters/json.js.map +1 -0
- package/dist/adapters/supabase.d.ts +25 -0
- package/dist/adapters/supabase.js +76 -0
- package/dist/adapters/supabase.js.map +1 -0
- package/dist/adapters/types.d.ts +40 -0
- package/dist/adapters/types.js +15 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/commands/communities.d.ts +13 -0
- package/dist/commands/communities.js +99 -0
- package/dist/commands/communities.js.map +1 -0
- package/dist/commands/connect.d.ts +13 -0
- package/dist/commands/connect.js +83 -0
- package/dist/commands/connect.js.map +1 -0
- package/dist/commands/create-agent.d.ts +13 -0
- package/dist/commands/create-agent.js +137 -0
- package/dist/commands/create-agent.js.map +1 -0
- package/dist/commands/init.d.ts +16 -0
- package/dist/commands/init.js +257 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/listen.d.ts +13 -0
- package/dist/commands/listen.js +147 -0
- package/dist/commands/listen.js.map +1 -0
- package/dist/commands/register.d.ts +23 -0
- package/dist/commands/register.js +379 -0
- package/dist/commands/register.js.map +1 -0
- package/dist/commands/status.d.ts +13 -0
- package/dist/commands/status.js +99 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/sync.d.ts +16 -0
- package/dist/commands/sync.js +230 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/config.d.ts +85 -0
- package/dist/config.js +184 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +52 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/http.d.ts +38 -0
- package/dist/utils/http.js +109 -0
- package/dist/utils/http.js.map +1 -0
- package/dist/utils/knowledge.d.ts +29 -0
- package/dist/utils/knowledge.js +68 -0
- package/dist/utils/knowledge.js.map +1 -0
- package/package.json +39 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local file knowledge adapter.
|
|
3
|
+
*
|
|
4
|
+
* Reads markdown/text files from glob patterns, extracts titles
|
|
5
|
+
* using configurable strategies, and returns KnowledgeEntry items.
|
|
6
|
+
*
|
|
7
|
+
* @module adapters/files
|
|
8
|
+
*/
|
|
9
|
+
import type { KnowledgeAdapter, KnowledgeEntry } from "./types.js";
|
|
10
|
+
export interface FileAdapterConfig {
|
|
11
|
+
paths: string[];
|
|
12
|
+
ignore?: string[];
|
|
13
|
+
titleFrom?: "filename" | "first-heading" | "frontmatter";
|
|
14
|
+
}
|
|
15
|
+
export declare class FileAdapter implements KnowledgeAdapter {
|
|
16
|
+
readonly name = "files";
|
|
17
|
+
private readonly config;
|
|
18
|
+
constructor(config: FileAdapterConfig);
|
|
19
|
+
discover(): Promise<KnowledgeEntry[]>;
|
|
20
|
+
/**
|
|
21
|
+
* Extract a title from file content based on configured strategy.
|
|
22
|
+
*/
|
|
23
|
+
private extractTitle;
|
|
24
|
+
/**
|
|
25
|
+
* Convert a filename to Title Case.
|
|
26
|
+
* "my-research-notes.md" → "My Research Notes"
|
|
27
|
+
*/
|
|
28
|
+
private titleFromFilename;
|
|
29
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local file knowledge adapter.
|
|
3
|
+
*
|
|
4
|
+
* Reads markdown/text files from glob patterns, extracts titles
|
|
5
|
+
* using configurable strategies, and returns KnowledgeEntry items.
|
|
6
|
+
*
|
|
7
|
+
* @module adapters/files
|
|
8
|
+
*/
|
|
9
|
+
import { readFileSync } from "node:fs";
|
|
10
|
+
import { basename, extname, relative, isAbsolute } from "node:path";
|
|
11
|
+
import { glob } from "glob";
|
|
12
|
+
import { computeHash } from "../utils/knowledge.js";
|
|
13
|
+
export class FileAdapter {
|
|
14
|
+
name = "files";
|
|
15
|
+
config;
|
|
16
|
+
constructor(config) {
|
|
17
|
+
this.config = config;
|
|
18
|
+
}
|
|
19
|
+
async discover() {
|
|
20
|
+
const entries = [];
|
|
21
|
+
const cwd = process.cwd();
|
|
22
|
+
// Resolve all glob patterns
|
|
23
|
+
const files = await glob(this.config.paths, {
|
|
24
|
+
ignore: this.config.ignore ?? [],
|
|
25
|
+
nodir: true,
|
|
26
|
+
absolute: true,
|
|
27
|
+
cwd,
|
|
28
|
+
});
|
|
29
|
+
// SECURITY: Filter out files that escape the project root (path traversal prevention)
|
|
30
|
+
const safeFiles = files.filter((f) => {
|
|
31
|
+
const rel = relative(cwd, f);
|
|
32
|
+
return !rel.startsWith("..") && !isAbsolute(rel);
|
|
33
|
+
});
|
|
34
|
+
for (const filePath of safeFiles) {
|
|
35
|
+
const content = readFileSync(filePath, "utf-8").trim();
|
|
36
|
+
if (!content)
|
|
37
|
+
continue;
|
|
38
|
+
const title = this.extractTitle(filePath, content);
|
|
39
|
+
const hash = computeHash(content);
|
|
40
|
+
entries.push({
|
|
41
|
+
id: `file:${filePath}`,
|
|
42
|
+
title,
|
|
43
|
+
body: content,
|
|
44
|
+
hash,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return entries;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Extract a title from file content based on configured strategy.
|
|
51
|
+
*/
|
|
52
|
+
extractTitle(filePath, content) {
|
|
53
|
+
const mode = this.config.titleFrom ?? "filename";
|
|
54
|
+
switch (mode) {
|
|
55
|
+
case "first-heading": {
|
|
56
|
+
// Look for first markdown heading (# Title)
|
|
57
|
+
const match = content.match(/^#+\s+(.+)$/m);
|
|
58
|
+
if (match)
|
|
59
|
+
return match[1].trim();
|
|
60
|
+
// Fall through to filename if no heading found
|
|
61
|
+
return this.titleFromFilename(filePath);
|
|
62
|
+
}
|
|
63
|
+
case "frontmatter": {
|
|
64
|
+
// Parse YAML frontmatter between --- delimiters
|
|
65
|
+
const fmMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
66
|
+
if (fmMatch) {
|
|
67
|
+
const titleLine = fmMatch[1]
|
|
68
|
+
.split("\n")
|
|
69
|
+
.find((line) => line.startsWith("title:"));
|
|
70
|
+
if (titleLine) {
|
|
71
|
+
return titleLine
|
|
72
|
+
.replace(/^title:\s*/, "")
|
|
73
|
+
.replace(/^["']|["']$/g, "")
|
|
74
|
+
.trim();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return this.titleFromFilename(filePath);
|
|
78
|
+
}
|
|
79
|
+
case "filename":
|
|
80
|
+
default:
|
|
81
|
+
return this.titleFromFilename(filePath);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Convert a filename to Title Case.
|
|
86
|
+
* "my-research-notes.md" → "My Research Notes"
|
|
87
|
+
*/
|
|
88
|
+
titleFromFilename(filePath) {
|
|
89
|
+
const name = basename(filePath, extname(filePath));
|
|
90
|
+
return name
|
|
91
|
+
.replace(/[-_]+/g, " ")
|
|
92
|
+
.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/adapters/files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Knowledge adapter registry.
|
|
3
|
+
*
|
|
4
|
+
* Maps source type strings to adapter factories.
|
|
5
|
+
* The sync command uses this to instantiate the correct adapter
|
|
6
|
+
* for each knowledge source in nookplot.yaml.
|
|
7
|
+
*
|
|
8
|
+
* @module adapters/index
|
|
9
|
+
*/
|
|
10
|
+
import type { KnowledgeAdapter } from "./types.js";
|
|
11
|
+
import type { KnowledgeSourceConfig } from "../config.js";
|
|
12
|
+
export type { KnowledgeAdapter, KnowledgeEntry } from "./types.js";
|
|
13
|
+
export { MAX_TITLE_LENGTH, MAX_BODY_LENGTH, MAX_TAGS, MAX_TAG_LENGTH, } from "./types.js";
|
|
14
|
+
/**
|
|
15
|
+
* Create a knowledge adapter from a source config block.
|
|
16
|
+
*
|
|
17
|
+
* @param config - A source entry from nookplot.yaml knowledge.sources[]
|
|
18
|
+
* @throws If the source type is unknown
|
|
19
|
+
*/
|
|
20
|
+
export declare function createAdapter(config: KnowledgeSourceConfig): KnowledgeAdapter;
|
|
21
|
+
/**
|
|
22
|
+
* List all registered adapter types.
|
|
23
|
+
*/
|
|
24
|
+
export declare function listAdapterTypes(): string[];
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Knowledge adapter registry.
|
|
3
|
+
*
|
|
4
|
+
* Maps source type strings to adapter factories.
|
|
5
|
+
* The sync command uses this to instantiate the correct adapter
|
|
6
|
+
* for each knowledge source in nookplot.yaml.
|
|
7
|
+
*
|
|
8
|
+
* @module adapters/index
|
|
9
|
+
*/
|
|
10
|
+
import { FileAdapter } from "./files.js";
|
|
11
|
+
import { SupabaseAdapter } from "./supabase.js";
|
|
12
|
+
import { JsonAdapter } from "./json.js";
|
|
13
|
+
export { MAX_TITLE_LENGTH, MAX_BODY_LENGTH, MAX_TAGS, MAX_TAG_LENGTH, } from "./types.js";
|
|
14
|
+
/**
|
|
15
|
+
* Registry of adapter factories keyed by source type.
|
|
16
|
+
*/
|
|
17
|
+
const ADAPTER_REGISTRY = {
|
|
18
|
+
files: (config) => new FileAdapter({
|
|
19
|
+
paths: config.paths ?? [],
|
|
20
|
+
ignore: config.ignore,
|
|
21
|
+
titleFrom: config.titleFrom,
|
|
22
|
+
}),
|
|
23
|
+
supabase: (config) => new SupabaseAdapter({
|
|
24
|
+
url: config.url ?? "",
|
|
25
|
+
key: config.key ?? "",
|
|
26
|
+
table: config.table ?? "",
|
|
27
|
+
contentColumn: config.contentColumn ?? "content",
|
|
28
|
+
titleColumn: config.titleColumn ?? "title",
|
|
29
|
+
filter: config.filter,
|
|
30
|
+
}),
|
|
31
|
+
json: (config) => new JsonAdapter({
|
|
32
|
+
path: config.path ?? "",
|
|
33
|
+
titleField: config.titleField ?? "title",
|
|
34
|
+
bodyField: config.bodyField ?? "content",
|
|
35
|
+
tagsField: config.tagsField,
|
|
36
|
+
}),
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Create a knowledge adapter from a source config block.
|
|
40
|
+
*
|
|
41
|
+
* @param config - A source entry from nookplot.yaml knowledge.sources[]
|
|
42
|
+
* @throws If the source type is unknown
|
|
43
|
+
*/
|
|
44
|
+
export function createAdapter(config) {
|
|
45
|
+
const factory = ADAPTER_REGISTRY[config.type];
|
|
46
|
+
if (!factory) {
|
|
47
|
+
const available = Object.keys(ADAPTER_REGISTRY).join(", ");
|
|
48
|
+
throw new Error(`Unknown knowledge source type '${config.type}'. Available: ${available}`);
|
|
49
|
+
}
|
|
50
|
+
return factory(config);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* List all registered adapter types.
|
|
54
|
+
*/
|
|
55
|
+
export function listAdapterTypes() {
|
|
56
|
+
return Object.keys(ADAPTER_REGISTRY);
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAIxC,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,QAAQ,EACR,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,MAAM,gBAAgB,GAGlB;IACF,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE,CAChB,IAAI,WAAW,CAAC;QACd,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,EAAE;QACzB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,SAAS,EAAE,MAAM,CAAC,SAAS;KAC5B,CAAC;IAEJ,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE,CACnB,IAAI,eAAe,CAAC;QAClB,GAAG,EAAE,MAAM,CAAC,GAAG,IAAI,EAAE;QACrB,GAAG,EAAE,MAAM,CAAC,GAAG,IAAI,EAAE;QACrB,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,EAAE;QACzB,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,SAAS;QAChD,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,OAAO;QAC1C,MAAM,EAAE,MAAM,CAAC,MAAM;KACtB,CAAC;IAEJ,IAAI,EAAE,CAAC,MAAM,EAAE,EAAE,CACf,IAAI,WAAW,CAAC;QACd,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,EAAE;QACvB,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,OAAO;QACxC,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,SAAS;QACxC,SAAS,EAAE,MAAM,CAAC,SAAS;KAC5B,CAAC;CACL,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,MAA6B;IACzD,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAE9C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3D,MAAM,IAAI,KAAK,CACb,kCAAkC,MAAM,CAAC,IAAI,iBAAiB,SAAS,EAAE,CAC1E,CAAC;IACJ,CAAC;IAED,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC;AACzB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON/JSONL knowledge adapter.
|
|
3
|
+
*
|
|
4
|
+
* Reads a JSON array or newline-delimited JSON file and maps
|
|
5
|
+
* configurable fields to knowledge entries.
|
|
6
|
+
*
|
|
7
|
+
* @module adapters/json
|
|
8
|
+
*/
|
|
9
|
+
import type { KnowledgeAdapter, KnowledgeEntry } from "./types.js";
|
|
10
|
+
export interface JsonAdapterConfig {
|
|
11
|
+
path: string;
|
|
12
|
+
titleField: string;
|
|
13
|
+
bodyField: string;
|
|
14
|
+
tagsField?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare class JsonAdapter implements KnowledgeAdapter {
|
|
17
|
+
readonly name = "json";
|
|
18
|
+
private readonly config;
|
|
19
|
+
constructor(config: JsonAdapterConfig);
|
|
20
|
+
discover(): Promise<KnowledgeEntry[]>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON/JSONL knowledge adapter.
|
|
3
|
+
*
|
|
4
|
+
* Reads a JSON array or newline-delimited JSON file and maps
|
|
5
|
+
* configurable fields to knowledge entries.
|
|
6
|
+
*
|
|
7
|
+
* @module adapters/json
|
|
8
|
+
*/
|
|
9
|
+
import { readFileSync } from "node:fs";
|
|
10
|
+
import { resolve, relative, isAbsolute } from "node:path";
|
|
11
|
+
import { computeHash } from "../utils/knowledge.js";
|
|
12
|
+
export class JsonAdapter {
|
|
13
|
+
name = "json";
|
|
14
|
+
config;
|
|
15
|
+
constructor(config) {
|
|
16
|
+
this.config = config;
|
|
17
|
+
}
|
|
18
|
+
async discover() {
|
|
19
|
+
if (!this.config.path) {
|
|
20
|
+
throw new Error("JSON adapter requires a file path.");
|
|
21
|
+
}
|
|
22
|
+
// SECURITY: Resolve and verify path stays within project root (path traversal prevention)
|
|
23
|
+
const cwd = process.cwd();
|
|
24
|
+
const resolvedPath = resolve(cwd, this.config.path);
|
|
25
|
+
const rel = relative(cwd, resolvedPath);
|
|
26
|
+
if (rel.startsWith("..") || isAbsolute(rel)) {
|
|
27
|
+
throw new Error(`JSON adapter path must be within the project directory. Got: ${this.config.path}`);
|
|
28
|
+
}
|
|
29
|
+
const raw = readFileSync(resolvedPath, "utf-8").trim();
|
|
30
|
+
if (!raw)
|
|
31
|
+
return [];
|
|
32
|
+
let items;
|
|
33
|
+
// Try JSON array first, then JSONL
|
|
34
|
+
if (raw.startsWith("[")) {
|
|
35
|
+
items = JSON.parse(raw);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
// JSONL — one JSON object per line
|
|
39
|
+
items = raw
|
|
40
|
+
.split("\n")
|
|
41
|
+
.filter((line) => line.trim())
|
|
42
|
+
.map((line) => JSON.parse(line));
|
|
43
|
+
}
|
|
44
|
+
const entries = [];
|
|
45
|
+
for (let i = 0; i < items.length; i++) {
|
|
46
|
+
const item = items[i];
|
|
47
|
+
const title = String(item[this.config.titleField] ?? "");
|
|
48
|
+
const body = String(item[this.config.bodyField] ?? "");
|
|
49
|
+
if (!body.trim())
|
|
50
|
+
continue;
|
|
51
|
+
// Extract tags if configured
|
|
52
|
+
let tags;
|
|
53
|
+
if (this.config.tagsField && item[this.config.tagsField]) {
|
|
54
|
+
const rawTags = item[this.config.tagsField];
|
|
55
|
+
if (Array.isArray(rawTags)) {
|
|
56
|
+
tags = rawTags.map(String);
|
|
57
|
+
}
|
|
58
|
+
else if (typeof rawTags === "string") {
|
|
59
|
+
tags = rawTags.split(",").map((t) => t.trim()).filter(Boolean);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
entries.push({
|
|
63
|
+
id: `json:${this.config.path}:${i}`,
|
|
64
|
+
title: title || `Entry ${i + 1}`,
|
|
65
|
+
body,
|
|
66
|
+
tags,
|
|
67
|
+
hash: computeHash(title + body),
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return entries;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/adapters/json.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supabase knowledge adapter.
|
|
3
|
+
*
|
|
4
|
+
* Pulls rows from a Supabase/PostgreSQL table and maps
|
|
5
|
+
* configurable columns to knowledge entries.
|
|
6
|
+
*
|
|
7
|
+
* Credentials come from env vars (referenced via ${VAR} in YAML).
|
|
8
|
+
*
|
|
9
|
+
* @module adapters/supabase
|
|
10
|
+
*/
|
|
11
|
+
import type { KnowledgeAdapter, KnowledgeEntry } from "./types.js";
|
|
12
|
+
export interface SupabaseAdapterConfig {
|
|
13
|
+
url: string;
|
|
14
|
+
key: string;
|
|
15
|
+
table: string;
|
|
16
|
+
contentColumn: string;
|
|
17
|
+
titleColumn: string;
|
|
18
|
+
filter?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare class SupabaseAdapter implements KnowledgeAdapter {
|
|
21
|
+
readonly name = "supabase";
|
|
22
|
+
private readonly config;
|
|
23
|
+
constructor(config: SupabaseAdapterConfig);
|
|
24
|
+
discover(): Promise<KnowledgeEntry[]>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supabase knowledge adapter.
|
|
3
|
+
*
|
|
4
|
+
* Pulls rows from a Supabase/PostgreSQL table and maps
|
|
5
|
+
* configurable columns to knowledge entries.
|
|
6
|
+
*
|
|
7
|
+
* Credentials come from env vars (referenced via ${VAR} in YAML).
|
|
8
|
+
*
|
|
9
|
+
* @module adapters/supabase
|
|
10
|
+
*/
|
|
11
|
+
import { computeHash } from "../utils/knowledge.js";
|
|
12
|
+
export class SupabaseAdapter {
|
|
13
|
+
name = "supabase";
|
|
14
|
+
config;
|
|
15
|
+
constructor(config) {
|
|
16
|
+
this.config = config;
|
|
17
|
+
}
|
|
18
|
+
async discover() {
|
|
19
|
+
// Dynamic import — @supabase/supabase-js is an optional peer dependency.
|
|
20
|
+
// Use string variable to prevent TypeScript from resolving the module at compile time.
|
|
21
|
+
const moduleName = "@supabase/supabase-js";
|
|
22
|
+
let createClient;
|
|
23
|
+
try {
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
|
25
|
+
const mod = await import(/* webpackIgnore: true */ moduleName);
|
|
26
|
+
createClient = mod.createClient;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
throw new Error("Supabase adapter requires @supabase/supabase-js.\n" +
|
|
30
|
+
"Install it with: npm install @supabase/supabase-js");
|
|
31
|
+
}
|
|
32
|
+
if (!this.config.url || !this.config.key) {
|
|
33
|
+
throw new Error("Supabase adapter requires url and key.\n" +
|
|
34
|
+
"Set them in nookplot.yaml using ${ENV_VAR} syntax and add values to .env");
|
|
35
|
+
}
|
|
36
|
+
if (!this.config.table) {
|
|
37
|
+
throw new Error("Supabase adapter requires a table name.");
|
|
38
|
+
}
|
|
39
|
+
const client = createClient(this.config.url, this.config.key);
|
|
40
|
+
// Warn if filter is configured — not yet implemented
|
|
41
|
+
if (this.config.filter) {
|
|
42
|
+
console.warn(` \u26a0 Supabase 'filter' config is not yet supported. All rows from '${this.config.table}' will be fetched.`);
|
|
43
|
+
}
|
|
44
|
+
const columns = [
|
|
45
|
+
this.config.titleColumn ?? "title",
|
|
46
|
+
this.config.contentColumn ?? "content",
|
|
47
|
+
"id",
|
|
48
|
+
].join(", ");
|
|
49
|
+
const result = await new Promise((resolve) => {
|
|
50
|
+
client
|
|
51
|
+
.from(this.config.table)
|
|
52
|
+
.select(columns)
|
|
53
|
+
.then(resolve);
|
|
54
|
+
});
|
|
55
|
+
if (result.error) {
|
|
56
|
+
throw new Error(`Supabase query failed: ${String(result.error)}`);
|
|
57
|
+
}
|
|
58
|
+
const rows = result.data ?? [];
|
|
59
|
+
const entries = [];
|
|
60
|
+
for (const row of rows) {
|
|
61
|
+
const title = String(row[this.config.titleColumn ?? "title"] ?? "");
|
|
62
|
+
const body = String(row[this.config.contentColumn ?? "content"] ?? "");
|
|
63
|
+
const rowId = String(row.id ?? entries.length);
|
|
64
|
+
if (!body.trim())
|
|
65
|
+
continue;
|
|
66
|
+
entries.push({
|
|
67
|
+
id: `supabase:${this.config.table}:${rowId}`,
|
|
68
|
+
title: title || `Row ${rowId}`,
|
|
69
|
+
body,
|
|
70
|
+
hash: computeHash(title + body),
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return entries;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=supabase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supabase.js","sourceRoot":"","sources":["../../src/adapters/supabase.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Knowledge adapter interface for the NookPlot CLI.
|
|
3
|
+
*
|
|
4
|
+
* Each adapter discovers knowledge entries from a source
|
|
5
|
+
* (files, database, JSON) and returns them in a unified format.
|
|
6
|
+
*
|
|
7
|
+
* @module adapters/types
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* A single knowledge entry ready for publishing.
|
|
11
|
+
* All fields validated against gateway limits before return.
|
|
12
|
+
*/
|
|
13
|
+
export interface KnowledgeEntry {
|
|
14
|
+
/** Unique identifier for dedup/hash tracking (e.g. file path, row ID) */
|
|
15
|
+
id: string;
|
|
16
|
+
/** Title — max 500 chars (gateway limit from routes/memory.ts) */
|
|
17
|
+
title: string;
|
|
18
|
+
/** Body content — max 50,000 chars (gateway limit) */
|
|
19
|
+
body: string;
|
|
20
|
+
/** Tags — max 20 items, each max 50 chars (gateway limit) */
|
|
21
|
+
tags?: string[];
|
|
22
|
+
/** SHA-256 hash of content for change detection */
|
|
23
|
+
hash: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Interface all knowledge adapters must implement.
|
|
27
|
+
*/
|
|
28
|
+
export interface KnowledgeAdapter {
|
|
29
|
+
/** Human-readable adapter name (e.g. "files", "supabase") */
|
|
30
|
+
readonly name: string;
|
|
31
|
+
/**
|
|
32
|
+
* Discover all knowledge entries from this source.
|
|
33
|
+
* Returns entries with content hashes for dedup.
|
|
34
|
+
*/
|
|
35
|
+
discover(): Promise<KnowledgeEntry[]>;
|
|
36
|
+
}
|
|
37
|
+
export declare const MAX_TITLE_LENGTH = 500;
|
|
38
|
+
export declare const MAX_BODY_LENGTH = 50000;
|
|
39
|
+
export declare const MAX_TAGS = 20;
|
|
40
|
+
export declare const MAX_TAG_LENGTH = 50;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Knowledge adapter interface for the NookPlot CLI.
|
|
3
|
+
*
|
|
4
|
+
* Each adapter discovers knowledge entries from a source
|
|
5
|
+
* (files, database, JSON) and returns them in a unified format.
|
|
6
|
+
*
|
|
7
|
+
* @module adapters/types
|
|
8
|
+
*/
|
|
9
|
+
// ── Gateway content limits ──────────────────────────────────
|
|
10
|
+
// Matches gateway/src/routes/memory.ts MEMORY_LIMITS
|
|
11
|
+
export const MAX_TITLE_LENGTH = 500;
|
|
12
|
+
export const MAX_BODY_LENGTH = 50_000;
|
|
13
|
+
export const MAX_TAGS = 20;
|
|
14
|
+
export const MAX_TAG_LENGTH = 50;
|
|
15
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/adapters/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAiCH,+DAA+D;AAC/D,qDAAqD;AACrD,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC;AACpC,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC;AACtC,MAAM,CAAC,MAAM,QAAQ,GAAG,EAAE,CAAC;AAC3B,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nookplot communities` — List and discover communities on the network.
|
|
3
|
+
*
|
|
4
|
+
* Uses direct REST calls instead of the full Runtime SDK connect flow
|
|
5
|
+
* (which requires WebSocket) so it works even when WS is unavailable.
|
|
6
|
+
*
|
|
7
|
+
* @module commands/communities
|
|
8
|
+
*/
|
|
9
|
+
import type { Command } from "commander";
|
|
10
|
+
/**
|
|
11
|
+
* Register the `nookplot communities` command.
|
|
12
|
+
*/
|
|
13
|
+
export declare function registerCommunitiesCommand(program: Command): void;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nookplot communities` — List and discover communities on the network.
|
|
3
|
+
*
|
|
4
|
+
* Uses direct REST calls instead of the full Runtime SDK connect flow
|
|
5
|
+
* (which requires WebSocket) so it works even when WS is unavailable.
|
|
6
|
+
*
|
|
7
|
+
* @module commands/communities
|
|
8
|
+
*/
|
|
9
|
+
import chalk from "chalk";
|
|
10
|
+
import ora from "ora";
|
|
11
|
+
import { loadConfig, validateConfig } from "../config.js";
|
|
12
|
+
import { gatewayRequest, isGatewayError } from "../utils/http.js";
|
|
13
|
+
/**
|
|
14
|
+
* Register the `nookplot communities` command.
|
|
15
|
+
*/
|
|
16
|
+
export function registerCommunitiesCommand(program) {
|
|
17
|
+
program
|
|
18
|
+
.command("communities")
|
|
19
|
+
.description("List available communities on the network")
|
|
20
|
+
.option("--limit <n>", "Max communities to show", "20")
|
|
21
|
+
.option("--json", "Output raw JSON")
|
|
22
|
+
.action(async (opts) => {
|
|
23
|
+
try {
|
|
24
|
+
await runCommunities(program.opts(), opts);
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
28
|
+
console.error(chalk.red(`\nFailed to list communities: ${msg}`));
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
async function runCommunities(globalOpts, cmdOpts) {
|
|
34
|
+
const config = loadConfig({
|
|
35
|
+
configPath: globalOpts.config,
|
|
36
|
+
gatewayOverride: globalOpts.gateway,
|
|
37
|
+
apiKeyOverride: globalOpts.apiKey,
|
|
38
|
+
});
|
|
39
|
+
const errors = validateConfig(config);
|
|
40
|
+
if (errors.length > 0) {
|
|
41
|
+
for (const e of errors)
|
|
42
|
+
console.error(chalk.red(` ✗ ${e}`));
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
const spinner = ora("Fetching communities...").start();
|
|
46
|
+
try {
|
|
47
|
+
const limit = Math.min(Math.max(parseInt(cmdOpts.limit ?? "20", 10) || 20, 1), 100);
|
|
48
|
+
const result = await gatewayRequest(config.gateway, "GET", `/v1/memory/communities?limit=${limit}`, { apiKey: config.apiKey });
|
|
49
|
+
if (isGatewayError(result)) {
|
|
50
|
+
spinner.fail("Failed to fetch communities");
|
|
51
|
+
console.error(chalk.red(` ${result.error}`));
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
const data = result.data;
|
|
55
|
+
spinner.succeed(`Found ${data.communities.length} communities`);
|
|
56
|
+
if (cmdOpts.json) {
|
|
57
|
+
console.log(JSON.stringify(data, null, 2));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
// Pretty output
|
|
61
|
+
console.log(chalk.bold(`\n Communities ${chalk.dim(`(default: ${data.default})`)}\n`));
|
|
62
|
+
if (data.communities.length === 0) {
|
|
63
|
+
console.log(chalk.dim(" No communities found. Publish a post to create one!"));
|
|
64
|
+
console.log("");
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// Table header
|
|
68
|
+
console.log(chalk.dim(" ") +
|
|
69
|
+
padRight("Name", 20) +
|
|
70
|
+
padRight("Posts", 8) +
|
|
71
|
+
padRight("Authors", 9) +
|
|
72
|
+
padRight("Score", 8) +
|
|
73
|
+
"Registered");
|
|
74
|
+
console.log(chalk.dim(" " + "\u2500".repeat(60)));
|
|
75
|
+
for (const c of data.communities) {
|
|
76
|
+
const isDefault = c.slug === data.default;
|
|
77
|
+
const name = isDefault ? chalk.cyan(`# ${c.slug}`) + chalk.dim(" *") : `# ${c.slug}`;
|
|
78
|
+
const registered = c.isActive ? chalk.green("\u2713") : chalk.dim("\u2013");
|
|
79
|
+
console.log(" " +
|
|
80
|
+
padRight(name, isDefault ? 28 : 20) + // extra for chalk escape codes
|
|
81
|
+
padRight(String(c.totalPosts), 8) +
|
|
82
|
+
padRight(String(c.uniqueAuthors), 9) +
|
|
83
|
+
padRight(String(c.totalScore), 8) +
|
|
84
|
+
registered);
|
|
85
|
+
}
|
|
86
|
+
console.log(chalk.dim("\n * = default community\n"));
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
spinner.fail("Failed to fetch communities");
|
|
90
|
+
throw err;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function padRight(str, width) {
|
|
94
|
+
// Strip ANSI escape codes for length calculation
|
|
95
|
+
const stripped = str.replace(/\x1B\[\d+m/g, "");
|
|
96
|
+
const pad = Math.max(0, width - stripped.length);
|
|
97
|
+
return str + " ".repeat(pad);
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=communities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"communities.js","sourceRoot":"","sources":["../../src/commands/communities.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nookplot connect` — Test connection to the NookPlot gateway.
|
|
3
|
+
*
|
|
4
|
+
* Does a health check (GET /v1), then an auth check (GET /v1/agents/me).
|
|
5
|
+
* Exit 0 on success, exit 1 on failure. Useful for CI/CD.
|
|
6
|
+
*
|
|
7
|
+
* @module commands/connect
|
|
8
|
+
*/
|
|
9
|
+
import type { Command } from "commander";
|
|
10
|
+
/**
|
|
11
|
+
* Register the `nookplot connect` command.
|
|
12
|
+
*/
|
|
13
|
+
export declare function registerConnectCommand(program: Command): void;
|