ahok-skill 1.3.1
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/.prettierrc +8 -0
- package/Dockerfile +59 -0
- package/RAW_SKILL.md +219 -0
- package/README.md +277 -0
- package/SKILL.md +58 -0
- package/bin/opm.js +268 -0
- package/data/openmemory.sqlite +0 -0
- package/data/openmemory.sqlite-shm +0 -0
- package/data/openmemory.sqlite-wal +0 -0
- package/dist/ai/graph.js +293 -0
- package/dist/ai/mcp.js +397 -0
- package/dist/cli.js +78 -0
- package/dist/core/cfg.js +87 -0
- package/dist/core/db.js +636 -0
- package/dist/core/memory.js +116 -0
- package/dist/core/migrate.js +227 -0
- package/dist/core/models.js +105 -0
- package/dist/core/telemetry.js +57 -0
- package/dist/core/types.js +2 -0
- package/dist/core/vector/postgres.js +52 -0
- package/dist/core/vector/valkey.js +246 -0
- package/dist/core/vector_store.js +2 -0
- package/dist/index.js +44 -0
- package/dist/memory/decay.js +301 -0
- package/dist/memory/embed.js +675 -0
- package/dist/memory/hsg.js +959 -0
- package/dist/memory/reflect.js +131 -0
- package/dist/memory/user_summary.js +99 -0
- package/dist/migrate.js +9 -0
- package/dist/ops/compress.js +255 -0
- package/dist/ops/dynamics.js +189 -0
- package/dist/ops/extract.js +333 -0
- package/dist/ops/ingest.js +214 -0
- package/dist/server/index.js +109 -0
- package/dist/server/middleware/auth.js +137 -0
- package/dist/server/routes/auth.js +186 -0
- package/dist/server/routes/compression.js +108 -0
- package/dist/server/routes/dashboard.js +399 -0
- package/dist/server/routes/docs.js +241 -0
- package/dist/server/routes/dynamics.js +312 -0
- package/dist/server/routes/ide.js +280 -0
- package/dist/server/routes/index.js +33 -0
- package/dist/server/routes/keys.js +132 -0
- package/dist/server/routes/langgraph.js +61 -0
- package/dist/server/routes/memory.js +213 -0
- package/dist/server/routes/sources.js +140 -0
- package/dist/server/routes/system.js +63 -0
- package/dist/server/routes/temporal.js +293 -0
- package/dist/server/routes/users.js +101 -0
- package/dist/server/routes/vercel.js +57 -0
- package/dist/server/server.js +211 -0
- package/dist/server.js +3 -0
- package/dist/sources/base.js +223 -0
- package/dist/sources/github.js +171 -0
- package/dist/sources/google_drive.js +166 -0
- package/dist/sources/google_sheets.js +112 -0
- package/dist/sources/google_slides.js +139 -0
- package/dist/sources/index.js +34 -0
- package/dist/sources/notion.js +165 -0
- package/dist/sources/onedrive.js +143 -0
- package/dist/sources/web_crawler.js +166 -0
- package/dist/temporal_graph/index.js +20 -0
- package/dist/temporal_graph/query.js +240 -0
- package/dist/temporal_graph/store.js +116 -0
- package/dist/temporal_graph/timeline.js +241 -0
- package/dist/temporal_graph/types.js +2 -0
- package/dist/utils/chunking.js +60 -0
- package/dist/utils/index.js +31 -0
- package/dist/utils/keyword.js +94 -0
- package/dist/utils/text.js +120 -0
- package/nodemon.json +7 -0
- package/package.json +50 -0
- package/references/api_reference.md +66 -0
- package/references/examples.md +45 -0
- package/src/ai/graph.ts +363 -0
- package/src/ai/mcp.ts +494 -0
- package/src/cli.ts +94 -0
- package/src/core/cfg.ts +110 -0
- package/src/core/db.ts +1052 -0
- package/src/core/memory.ts +99 -0
- package/src/core/migrate.ts +302 -0
- package/src/core/models.ts +107 -0
- package/src/core/telemetry.ts +47 -0
- package/src/core/types.ts +130 -0
- package/src/core/vector/postgres.ts +61 -0
- package/src/core/vector/valkey.ts +261 -0
- package/src/core/vector_store.ts +9 -0
- package/src/index.ts +5 -0
- package/src/memory/decay.ts +427 -0
- package/src/memory/embed.ts +707 -0
- package/src/memory/hsg.ts +1245 -0
- package/src/memory/reflect.ts +158 -0
- package/src/memory/user_summary.ts +110 -0
- package/src/migrate.ts +8 -0
- package/src/ops/compress.ts +296 -0
- package/src/ops/dynamics.ts +272 -0
- package/src/ops/extract.ts +360 -0
- package/src/ops/ingest.ts +286 -0
- package/src/server/index.ts +159 -0
- package/src/server/middleware/auth.ts +156 -0
- package/src/server/routes/auth.ts +223 -0
- package/src/server/routes/compression.ts +106 -0
- package/src/server/routes/dashboard.ts +420 -0
- package/src/server/routes/docs.ts +380 -0
- package/src/server/routes/dynamics.ts +516 -0
- package/src/server/routes/ide.ts +283 -0
- package/src/server/routes/index.ts +32 -0
- package/src/server/routes/keys.ts +131 -0
- package/src/server/routes/langgraph.ts +71 -0
- package/src/server/routes/memory.ts +440 -0
- package/src/server/routes/sources.ts +111 -0
- package/src/server/routes/system.ts +68 -0
- package/src/server/routes/temporal.ts +335 -0
- package/src/server/routes/users.ts +111 -0
- package/src/server/routes/vercel.ts +55 -0
- package/src/server/server.js +215 -0
- package/src/server.ts +1 -0
- package/src/sources/base.ts +257 -0
- package/src/sources/github.ts +156 -0
- package/src/sources/google_drive.ts +144 -0
- package/src/sources/google_sheets.ts +85 -0
- package/src/sources/google_slides.ts +115 -0
- package/src/sources/index.ts +19 -0
- package/src/sources/notion.ts +148 -0
- package/src/sources/onedrive.ts +131 -0
- package/src/sources/web_crawler.ts +161 -0
- package/src/temporal_graph/index.ts +4 -0
- package/src/temporal_graph/query.ts +299 -0
- package/src/temporal_graph/store.ts +156 -0
- package/src/temporal_graph/timeline.ts +319 -0
- package/src/temporal_graph/types.ts +41 -0
- package/src/utils/chunking.ts +66 -0
- package/src/utils/index.ts +25 -0
- package/src/utils/keyword.ts +137 -0
- package/src/utils/text.ts +115 -0
- package/tests/test_api_workspace_management.ts +413 -0
- package/tests/test_bulk_delete.ts +267 -0
- package/tests/test_omnibus.ts +166 -0
- package/tests/test_workspace_management.ts +278 -0
- package/tests/verify.ts +104 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* base source class for openmemory data sources - production grade
|
|
4
|
+
*
|
|
5
|
+
* features:
|
|
6
|
+
* - custom exception hierarchy
|
|
7
|
+
* - logging
|
|
8
|
+
* - retry logic with exponential backoff
|
|
9
|
+
* - rate limiting
|
|
10
|
+
*/
|
|
11
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
14
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
15
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
16
|
+
}
|
|
17
|
+
Object.defineProperty(o, k2, desc);
|
|
18
|
+
}) : (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
o[k2] = m[k];
|
|
21
|
+
}));
|
|
22
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
23
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
24
|
+
}) : function(o, v) {
|
|
25
|
+
o["default"] = v;
|
|
26
|
+
});
|
|
27
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
28
|
+
var ownKeys = function(o) {
|
|
29
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
30
|
+
var ar = [];
|
|
31
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
32
|
+
return ar;
|
|
33
|
+
};
|
|
34
|
+
return ownKeys(o);
|
|
35
|
+
};
|
|
36
|
+
return function (mod) {
|
|
37
|
+
if (mod && mod.__esModule) return mod;
|
|
38
|
+
var result = {};
|
|
39
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
40
|
+
__setModuleDefault(result, mod);
|
|
41
|
+
return result;
|
|
42
|
+
};
|
|
43
|
+
})();
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.base_source = exports.rate_limiter = exports.source_fetch_error = exports.source_rate_limit_error = exports.source_config_error = exports.source_auth_error = exports.source_error = void 0;
|
|
46
|
+
exports.with_retry = with_retry;
|
|
47
|
+
// -- exceptions --
|
|
48
|
+
class source_error extends Error {
|
|
49
|
+
source;
|
|
50
|
+
cause;
|
|
51
|
+
constructor(msg, source, cause) {
|
|
52
|
+
super(source ? `[${source}] ${msg}` : msg);
|
|
53
|
+
this.name = 'source_error';
|
|
54
|
+
this.source = source;
|
|
55
|
+
this.cause = cause;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.source_error = source_error;
|
|
59
|
+
class source_auth_error extends source_error {
|
|
60
|
+
constructor(msg, source, cause) {
|
|
61
|
+
super(msg, source, cause);
|
|
62
|
+
this.name = 'source_auth_error';
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
exports.source_auth_error = source_auth_error;
|
|
66
|
+
class source_config_error extends source_error {
|
|
67
|
+
constructor(msg, source, cause) {
|
|
68
|
+
super(msg, source, cause);
|
|
69
|
+
this.name = 'source_config_error';
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
exports.source_config_error = source_config_error;
|
|
73
|
+
class source_rate_limit_error extends source_error {
|
|
74
|
+
retry_after;
|
|
75
|
+
constructor(msg, retry_after, source) {
|
|
76
|
+
super(msg, source);
|
|
77
|
+
this.name = 'source_rate_limit_error';
|
|
78
|
+
this.retry_after = retry_after;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.source_rate_limit_error = source_rate_limit_error;
|
|
82
|
+
class source_fetch_error extends source_error {
|
|
83
|
+
constructor(msg, source, cause) {
|
|
84
|
+
super(msg, source, cause);
|
|
85
|
+
this.name = 'source_fetch_error';
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
exports.source_fetch_error = source_fetch_error;
|
|
89
|
+
// -- rate limiter --
|
|
90
|
+
class rate_limiter {
|
|
91
|
+
rps;
|
|
92
|
+
tokens;
|
|
93
|
+
last_update;
|
|
94
|
+
constructor(requests_per_second = 10) {
|
|
95
|
+
this.rps = requests_per_second;
|
|
96
|
+
this.tokens = requests_per_second;
|
|
97
|
+
this.last_update = Date.now();
|
|
98
|
+
}
|
|
99
|
+
async acquire() {
|
|
100
|
+
const now = Date.now();
|
|
101
|
+
const elapsed = (now - this.last_update) / 1000;
|
|
102
|
+
this.tokens = Math.min(this.rps, this.tokens + elapsed * this.rps);
|
|
103
|
+
this.last_update = now;
|
|
104
|
+
if (this.tokens < 1) {
|
|
105
|
+
const wait_time = ((1 - this.tokens) / this.rps) * 1000;
|
|
106
|
+
await new Promise(r => setTimeout(r, wait_time));
|
|
107
|
+
this.tokens = 0;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
this.tokens -= 1;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
exports.rate_limiter = rate_limiter;
|
|
115
|
+
// -- retry helper --
|
|
116
|
+
async function with_retry(fn, max_attempts = 3, base_delay = 1000, max_delay = 60000) {
|
|
117
|
+
let last_err = null;
|
|
118
|
+
for (let attempt = 0; attempt < max_attempts; attempt++) {
|
|
119
|
+
try {
|
|
120
|
+
return await fn();
|
|
121
|
+
}
|
|
122
|
+
catch (e) {
|
|
123
|
+
last_err = e;
|
|
124
|
+
if (e instanceof source_auth_error) {
|
|
125
|
+
throw e; // don't retry auth errors
|
|
126
|
+
}
|
|
127
|
+
if (attempt < max_attempts - 1) {
|
|
128
|
+
const delay = e instanceof source_rate_limit_error && e.retry_after
|
|
129
|
+
? e.retry_after * 1000
|
|
130
|
+
: Math.min(base_delay * Math.pow(2, attempt), max_delay);
|
|
131
|
+
console.warn(`[retry] attempt ${attempt + 1}/${max_attempts} failed: ${e.message}, retrying in ${delay}ms`);
|
|
132
|
+
await new Promise(r => setTimeout(r, delay));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
throw last_err;
|
|
137
|
+
}
|
|
138
|
+
// -- base source --
|
|
139
|
+
class base_source {
|
|
140
|
+
name = 'base';
|
|
141
|
+
user_id;
|
|
142
|
+
_connected = false;
|
|
143
|
+
_max_retries;
|
|
144
|
+
_rate_limiter;
|
|
145
|
+
constructor(user_id, config) {
|
|
146
|
+
this.user_id = user_id || 'anonymous';
|
|
147
|
+
this._max_retries = config?.max_retries || 3;
|
|
148
|
+
this._rate_limiter = new rate_limiter(config?.requests_per_second || 10);
|
|
149
|
+
}
|
|
150
|
+
get connected() {
|
|
151
|
+
return this._connected;
|
|
152
|
+
}
|
|
153
|
+
async connect(creds) {
|
|
154
|
+
console.log(`[${this.name}] connecting...`);
|
|
155
|
+
try {
|
|
156
|
+
const result = await this._connect(creds || {});
|
|
157
|
+
this._connected = result;
|
|
158
|
+
if (result) {
|
|
159
|
+
console.log(`[${this.name}] connected`);
|
|
160
|
+
}
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
catch (e) {
|
|
164
|
+
console.error(`[${this.name}] connection failed: ${e.message}`);
|
|
165
|
+
throw new source_auth_error(e.message, this.name, e);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
async disconnect() {
|
|
169
|
+
this._connected = false;
|
|
170
|
+
console.log(`[${this.name}] disconnected`);
|
|
171
|
+
}
|
|
172
|
+
async list_items(filters) {
|
|
173
|
+
if (!this._connected) {
|
|
174
|
+
await this.connect();
|
|
175
|
+
}
|
|
176
|
+
await this._rate_limiter.acquire();
|
|
177
|
+
try {
|
|
178
|
+
const items = await with_retry(() => this._list_items(filters || {}), this._max_retries);
|
|
179
|
+
console.log(`[${this.name}] found ${items.length} items`);
|
|
180
|
+
return items;
|
|
181
|
+
}
|
|
182
|
+
catch (e) {
|
|
183
|
+
throw new source_fetch_error(e.message, this.name, e);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
async fetch_item(item_id) {
|
|
187
|
+
if (!this._connected) {
|
|
188
|
+
await this.connect();
|
|
189
|
+
}
|
|
190
|
+
await this._rate_limiter.acquire();
|
|
191
|
+
try {
|
|
192
|
+
return await with_retry(() => this._fetch_item(item_id), this._max_retries);
|
|
193
|
+
}
|
|
194
|
+
catch (e) {
|
|
195
|
+
throw new source_fetch_error(e.message, this.name, e);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
async ingest_all(filters) {
|
|
199
|
+
const { ingestDocument } = await Promise.resolve().then(() => __importStar(require('../ops/ingest')));
|
|
200
|
+
const items = await this.list_items(filters);
|
|
201
|
+
const ids = [];
|
|
202
|
+
const errors = [];
|
|
203
|
+
console.log(`[${this.name}] ingesting ${items.length} items...`);
|
|
204
|
+
for (let i = 0; i < items.length; i++) {
|
|
205
|
+
const item = items[i];
|
|
206
|
+
try {
|
|
207
|
+
const content = await this.fetch_item(item.id);
|
|
208
|
+
const result = await ingestDocument(content.type || 'text', content.data || content.text || '', { source: this.name, ...content.meta }, undefined, this.user_id);
|
|
209
|
+
ids.push(result.root_memory_id);
|
|
210
|
+
}
|
|
211
|
+
catch (e) {
|
|
212
|
+
console.warn(`[${this.name}] failed to ingest ${item.id}: ${e.message}`);
|
|
213
|
+
errors.push({ id: item.id, error: e.message });
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
console.log(`[${this.name}] ingested ${ids.length} items, ${errors.length} errors`);
|
|
217
|
+
return ids;
|
|
218
|
+
}
|
|
219
|
+
_get_env(key, default_val) {
|
|
220
|
+
return process.env[key] || default_val;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
exports.base_source = base_source;
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* github source for openmemory - production grade
|
|
4
|
+
* requires: @octokit/rest
|
|
5
|
+
* env vars: GITHUB_TOKEN
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.github_source = void 0;
|
|
42
|
+
const base_1 = require("./base");
|
|
43
|
+
class github_source extends base_1.base_source {
|
|
44
|
+
name = 'github';
|
|
45
|
+
octokit = null;
|
|
46
|
+
async _connect(creds) {
|
|
47
|
+
let Octokit;
|
|
48
|
+
try {
|
|
49
|
+
Octokit = await Promise.resolve().then(() => __importStar(require('@octokit/rest'))).then(m => m.Octokit);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
throw new base_1.source_config_error('missing deps: npm install @octokit/rest', this.name);
|
|
53
|
+
}
|
|
54
|
+
const token = creds.token || process.env.GITHUB_TOKEN;
|
|
55
|
+
if (!token) {
|
|
56
|
+
throw new base_1.source_config_error('no credentials: set GITHUB_TOKEN', this.name);
|
|
57
|
+
}
|
|
58
|
+
this.octokit = new Octokit({ auth: token });
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
async _list_items(filters) {
|
|
62
|
+
if (!filters.repo) {
|
|
63
|
+
throw new base_1.source_config_error('repo is required (format: owner/repo)', this.name);
|
|
64
|
+
}
|
|
65
|
+
const [owner, repo] = filters.repo.split('/');
|
|
66
|
+
const path = filters.path?.replace(/^\//, '') || '';
|
|
67
|
+
const include_issues = filters.include_issues || false;
|
|
68
|
+
const results = [];
|
|
69
|
+
// list files
|
|
70
|
+
try {
|
|
71
|
+
const resp = await this.octokit.repos.getContent({ owner, repo, path });
|
|
72
|
+
const contents = Array.isArray(resp.data) ? resp.data : [resp.data];
|
|
73
|
+
for (const content of contents) {
|
|
74
|
+
results.push({
|
|
75
|
+
id: `${filters.repo}:${content.path}`,
|
|
76
|
+
name: content.name,
|
|
77
|
+
type: content.type === 'dir' ? 'dir' : content.encoding || 'file',
|
|
78
|
+
path: content.path,
|
|
79
|
+
size: content.size || 0,
|
|
80
|
+
sha: content.sha
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
console.warn(`[github] failed to list ${path}: ${e.message}`);
|
|
86
|
+
}
|
|
87
|
+
// list issues if requested
|
|
88
|
+
if (include_issues) {
|
|
89
|
+
try {
|
|
90
|
+
const resp = await this.octokit.issues.listForRepo({ owner, repo, state: 'all', per_page: 50 });
|
|
91
|
+
for (const issue of resp.data) {
|
|
92
|
+
results.push({
|
|
93
|
+
id: `${filters.repo}:issue:${issue.number}`,
|
|
94
|
+
name: issue.title,
|
|
95
|
+
type: 'issue',
|
|
96
|
+
number: issue.number,
|
|
97
|
+
state: issue.state,
|
|
98
|
+
labels: issue.labels.map((l) => l.name)
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch (e) {
|
|
103
|
+
console.warn(`[github] failed to list issues: ${e.message}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return results;
|
|
107
|
+
}
|
|
108
|
+
async _fetch_item(item_id) {
|
|
109
|
+
const parts = item_id.split(':');
|
|
110
|
+
const repo_full = parts[0];
|
|
111
|
+
const [owner, repo] = repo_full.split('/');
|
|
112
|
+
// issue
|
|
113
|
+
if (parts.length >= 3 && parts[1] === 'issue') {
|
|
114
|
+
const issue_num = parseInt(parts[2]);
|
|
115
|
+
const issue = await this.octokit.issues.get({ owner, repo, issue_number: issue_num });
|
|
116
|
+
const comments = await this.octokit.issues.listComments({ owner, repo, issue_number: issue_num });
|
|
117
|
+
const text_parts = [
|
|
118
|
+
`# ${issue.data.title}`,
|
|
119
|
+
`**State:** ${issue.data.state}`,
|
|
120
|
+
`**Labels:** ${issue.data.labels.map((l) => l.name).join(', ')}`,
|
|
121
|
+
'',
|
|
122
|
+
issue.data.body || ''
|
|
123
|
+
];
|
|
124
|
+
for (const comment of comments.data) {
|
|
125
|
+
text_parts.push(`\n---\n**${comment.user?.login}:** ${comment.body}`);
|
|
126
|
+
}
|
|
127
|
+
const text = text_parts.join('\n');
|
|
128
|
+
return {
|
|
129
|
+
id: item_id,
|
|
130
|
+
name: issue.data.title,
|
|
131
|
+
type: 'issue',
|
|
132
|
+
text,
|
|
133
|
+
data: text,
|
|
134
|
+
meta: { source: 'github', repo: repo_full, issue_number: issue_num, state: issue.data.state }
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
// file
|
|
138
|
+
const path = parts.slice(1).join(':');
|
|
139
|
+
const resp = await this.octokit.repos.getContent({ owner, repo, path });
|
|
140
|
+
if (Array.isArray(resp.data)) {
|
|
141
|
+
const text = resp.data.map((c) => `- ${c.path}`).join('\n');
|
|
142
|
+
return {
|
|
143
|
+
id: item_id,
|
|
144
|
+
name: path || repo_full,
|
|
145
|
+
type: 'directory',
|
|
146
|
+
text,
|
|
147
|
+
data: text,
|
|
148
|
+
meta: { source: 'github', repo: repo_full, path }
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
const content = resp.data;
|
|
152
|
+
let text = '';
|
|
153
|
+
let data = '';
|
|
154
|
+
if (content.content) {
|
|
155
|
+
data = Buffer.from(content.content, 'base64');
|
|
156
|
+
try {
|
|
157
|
+
text = data.toString('utf-8');
|
|
158
|
+
}
|
|
159
|
+
catch { }
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
id: item_id,
|
|
163
|
+
name: content.name,
|
|
164
|
+
type: content.encoding || 'file',
|
|
165
|
+
text,
|
|
166
|
+
data,
|
|
167
|
+
meta: { source: 'github', repo: repo_full, path: content.path, sha: content.sha, size: content.size }
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
exports.github_source = github_source;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* google drive source for openmemory - production grade
|
|
4
|
+
* requires: googleapis
|
|
5
|
+
* env vars: GOOGLE_SERVICE_ACCOUNT_FILE or GOOGLE_CREDENTIALS_JSON
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.google_drive_source = void 0;
|
|
42
|
+
const base_1 = require("./base");
|
|
43
|
+
class google_drive_source extends base_1.base_source {
|
|
44
|
+
name = 'google_drive';
|
|
45
|
+
service = null;
|
|
46
|
+
auth = null;
|
|
47
|
+
async _connect(creds) {
|
|
48
|
+
let google;
|
|
49
|
+
try {
|
|
50
|
+
google = await Promise.resolve().then(() => __importStar(require('googleapis'))).then(m => m.google);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
throw new base_1.source_config_error('missing deps: npm install googleapis', this.name);
|
|
54
|
+
}
|
|
55
|
+
const scopes = ['https://www.googleapis.com/auth/drive.readonly'];
|
|
56
|
+
if (creds.credentials_json) {
|
|
57
|
+
this.auth = new google.auth.GoogleAuth({
|
|
58
|
+
credentials: creds.credentials_json,
|
|
59
|
+
scopes
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
else if (creds.service_account_file) {
|
|
63
|
+
this.auth = new google.auth.GoogleAuth({
|
|
64
|
+
keyFile: creds.service_account_file,
|
|
65
|
+
scopes
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
else if (process.env.GOOGLE_CREDENTIALS_JSON) {
|
|
69
|
+
this.auth = new google.auth.GoogleAuth({
|
|
70
|
+
credentials: JSON.parse(process.env.GOOGLE_CREDENTIALS_JSON),
|
|
71
|
+
scopes
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
else if (process.env.GOOGLE_SERVICE_ACCOUNT_FILE) {
|
|
75
|
+
this.auth = new google.auth.GoogleAuth({
|
|
76
|
+
keyFile: process.env.GOOGLE_SERVICE_ACCOUNT_FILE,
|
|
77
|
+
scopes
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
throw new base_1.source_config_error('no credentials: set GOOGLE_SERVICE_ACCOUNT_FILE or GOOGLE_CREDENTIALS_JSON', this.name);
|
|
82
|
+
}
|
|
83
|
+
this.service = google.drive({ version: 'v3', auth: this.auth });
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
async _list_items(filters) {
|
|
87
|
+
const q_parts = ['trashed=false'];
|
|
88
|
+
if (filters.folder_id) {
|
|
89
|
+
q_parts.push(`'${filters.folder_id}' in parents`);
|
|
90
|
+
}
|
|
91
|
+
if (filters.mime_types?.length) {
|
|
92
|
+
const mime_q = filters.mime_types.map((m) => `mimeType='${m}'`).join(' or ');
|
|
93
|
+
q_parts.push(`(${mime_q})`);
|
|
94
|
+
}
|
|
95
|
+
const query = q_parts.join(' and ');
|
|
96
|
+
const results = [];
|
|
97
|
+
let page_token;
|
|
98
|
+
do {
|
|
99
|
+
const resp = await this.service.files.list({
|
|
100
|
+
q: query,
|
|
101
|
+
spaces: 'drive',
|
|
102
|
+
fields: 'nextPageToken, files(id, name, mimeType, modifiedTime, size)',
|
|
103
|
+
pageToken: page_token,
|
|
104
|
+
pageSize: 100
|
|
105
|
+
});
|
|
106
|
+
for (const f of resp.data.files || []) {
|
|
107
|
+
results.push({
|
|
108
|
+
id: f.id,
|
|
109
|
+
name: f.name,
|
|
110
|
+
type: f.mimeType,
|
|
111
|
+
modified: f.modifiedTime,
|
|
112
|
+
size: f.size
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
page_token = resp.data.nextPageToken;
|
|
116
|
+
} while (page_token);
|
|
117
|
+
return results;
|
|
118
|
+
}
|
|
119
|
+
async _fetch_item(item_id) {
|
|
120
|
+
const meta = await this.service.files.get({
|
|
121
|
+
fileId: item_id,
|
|
122
|
+
fields: 'id,name,mimeType'
|
|
123
|
+
});
|
|
124
|
+
const mime = meta.data.mimeType;
|
|
125
|
+
let text = '';
|
|
126
|
+
let data = '';
|
|
127
|
+
// google docs -> export as text
|
|
128
|
+
if (mime === 'application/vnd.google-apps.document') {
|
|
129
|
+
const resp = await this.service.files.export({ fileId: item_id, mimeType: 'text/plain' });
|
|
130
|
+
text = resp.data;
|
|
131
|
+
data = text;
|
|
132
|
+
}
|
|
133
|
+
// google sheets -> export as csv
|
|
134
|
+
else if (mime === 'application/vnd.google-apps.spreadsheet') {
|
|
135
|
+
const resp = await this.service.files.export({ fileId: item_id, mimeType: 'text/csv' });
|
|
136
|
+
text = resp.data;
|
|
137
|
+
data = text;
|
|
138
|
+
}
|
|
139
|
+
// google slides -> export as plain text
|
|
140
|
+
else if (mime === 'application/vnd.google-apps.presentation') {
|
|
141
|
+
const resp = await this.service.files.export({ fileId: item_id, mimeType: 'text/plain' });
|
|
142
|
+
text = resp.data;
|
|
143
|
+
data = text;
|
|
144
|
+
}
|
|
145
|
+
// other files -> download raw
|
|
146
|
+
else {
|
|
147
|
+
const resp = await this.service.files.get({ fileId: item_id, alt: 'media' }, { responseType: 'arraybuffer' });
|
|
148
|
+
data = Buffer.from(resp.data);
|
|
149
|
+
try {
|
|
150
|
+
text = data.toString('utf-8');
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
text = '';
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
id: item_id,
|
|
158
|
+
name: meta.data.name,
|
|
159
|
+
type: mime,
|
|
160
|
+
text,
|
|
161
|
+
data,
|
|
162
|
+
meta: { source: 'google_drive', file_id: item_id, mime_type: mime }
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
exports.google_drive_source = google_drive_source;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* google sheets source for openmemory - production grade
|
|
4
|
+
* requires: googleapis
|
|
5
|
+
* env vars: GOOGLE_SERVICE_ACCOUNT_FILE or GOOGLE_CREDENTIALS_JSON
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.google_sheets_source = void 0;
|
|
42
|
+
const base_1 = require("./base");
|
|
43
|
+
class google_sheets_source extends base_1.base_source {
|
|
44
|
+
name = 'google_sheets';
|
|
45
|
+
service = null;
|
|
46
|
+
auth = null;
|
|
47
|
+
async _connect(creds) {
|
|
48
|
+
let google;
|
|
49
|
+
try {
|
|
50
|
+
google = await Promise.resolve().then(() => __importStar(require('googleapis'))).then(m => m.google);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
throw new base_1.source_config_error('missing deps: npm install googleapis', this.name);
|
|
54
|
+
}
|
|
55
|
+
const scopes = ['https://www.googleapis.com/auth/spreadsheets.readonly'];
|
|
56
|
+
if (creds.credentials_json) {
|
|
57
|
+
this.auth = new google.auth.GoogleAuth({ credentials: creds.credentials_json, scopes });
|
|
58
|
+
}
|
|
59
|
+
else if (creds.service_account_file) {
|
|
60
|
+
this.auth = new google.auth.GoogleAuth({ keyFile: creds.service_account_file, scopes });
|
|
61
|
+
}
|
|
62
|
+
else if (process.env.GOOGLE_CREDENTIALS_JSON) {
|
|
63
|
+
this.auth = new google.auth.GoogleAuth({ credentials: JSON.parse(process.env.GOOGLE_CREDENTIALS_JSON), scopes });
|
|
64
|
+
}
|
|
65
|
+
else if (process.env.GOOGLE_SERVICE_ACCOUNT_FILE) {
|
|
66
|
+
this.auth = new google.auth.GoogleAuth({ keyFile: process.env.GOOGLE_SERVICE_ACCOUNT_FILE, scopes });
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
throw new base_1.source_config_error('no credentials: set GOOGLE_SERVICE_ACCOUNT_FILE or GOOGLE_CREDENTIALS_JSON', this.name);
|
|
70
|
+
}
|
|
71
|
+
this.service = google.sheets({ version: 'v4', auth: this.auth });
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
async _list_items(filters) {
|
|
75
|
+
if (!filters.spreadsheet_id) {
|
|
76
|
+
throw new base_1.source_config_error('spreadsheet_id is required', this.name);
|
|
77
|
+
}
|
|
78
|
+
const meta = await this.service.spreadsheets.get({ spreadsheetId: filters.spreadsheet_id });
|
|
79
|
+
return (meta.data.sheets || []).map((sheet, i) => ({
|
|
80
|
+
id: `${filters.spreadsheet_id}!${sheet.properties?.title || 'Sheet1'}`,
|
|
81
|
+
name: sheet.properties?.title || 'Sheet1',
|
|
82
|
+
type: 'sheet',
|
|
83
|
+
index: i,
|
|
84
|
+
spreadsheet_id: filters.spreadsheet_id
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
async _fetch_item(item_id) {
|
|
88
|
+
const [spreadsheet_id, sheet_range] = item_id.includes('!')
|
|
89
|
+
? item_id.split('!', 2)
|
|
90
|
+
: [item_id, 'A:ZZ'];
|
|
91
|
+
const result = await this.service.spreadsheets.values.get({
|
|
92
|
+
spreadsheetId: spreadsheet_id,
|
|
93
|
+
range: sheet_range
|
|
94
|
+
});
|
|
95
|
+
const values = result.data.values || [];
|
|
96
|
+
// convert to markdown table
|
|
97
|
+
const lines = values.map((row, i) => {
|
|
98
|
+
const line = row.map(String).join(' | ');
|
|
99
|
+
return i === 0 ? `${line}\n${row.map(() => '---').join(' | ')}` : line;
|
|
100
|
+
});
|
|
101
|
+
const text = lines.join('\n');
|
|
102
|
+
return {
|
|
103
|
+
id: item_id,
|
|
104
|
+
name: sheet_range,
|
|
105
|
+
type: 'spreadsheet',
|
|
106
|
+
text,
|
|
107
|
+
data: text,
|
|
108
|
+
meta: { source: 'google_sheets', spreadsheet_id, range: sheet_range, row_count: values.length }
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
exports.google_sheets_source = google_sheets_source;
|