@anokye-labs/kbexplorer-engine 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/LICENSE +21 -0
- package/README.md +77 -0
- package/dist/build-manifest-BT0sY84J.d.ts +239 -0
- package/dist/build-manifest-BkgZUL0E.d.cts +239 -0
- package/dist/chunk-ASLGNOYV.js +220 -0
- package/dist/chunk-BA526FDQ.js +16 -0
- package/dist/chunk-DJ2DBEEK.js +424 -0
- package/dist/chunk-FJ4GTN4U.js +973 -0
- package/dist/chunk-HXAS3BSD.js +187 -0
- package/dist/chunk-IWEURXYH.js +273 -0
- package/dist/chunk-JNQVSNLC.js +55 -0
- package/dist/chunk-MW4BLXVK.js +72 -0
- package/dist/chunk-NOGBKE7C.js +351 -0
- package/dist/chunk-XVI6CBSX.js +412 -0
- package/dist/chunk-YTMIERYM.js +67 -0
- package/dist/github-api-source-KV5HZARH.js +4 -0
- package/dist/index.cjs +6218 -0
- package/dist/index.d.cts +1396 -0
- package/dist/index.d.ts +1396 -0
- package/dist/index.js +2892 -0
- package/dist/node-wasm-VSXBOCPD.js +9 -0
- package/dist/plugin-loader-K4VU6ODV.js +2 -0
- package/dist/repo-data-0JvFdLGv.d.cts +461 -0
- package/dist/repo-data-0JvFdLGv.d.ts +461 -0
- package/dist/sources.cjs +1191 -0
- package/dist/sources.d.cts +194 -0
- package/dist/sources.d.ts +194 -0
- package/dist/sources.js +357 -0
- package/dist/sqlite-graph-store-NH2NHL2B.js +2 -0
- package/dist/sqlite-runtime-CysPjjzX.d.cts +96 -0
- package/dist/sqlite-runtime-CysPjjzX.d.ts +96 -0
- package/dist/store-orchestrator-337XWIXO.js +5 -0
- package/dist/store.cjs +1112 -0
- package/dist/store.d.cts +37 -0
- package/dist/store.d.ts +37 -0
- package/dist/store.js +7 -0
- package/package.json +70 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import { collectNodemapData, resolveStructuredContentPath, hasExplicitStructuredContentPath } from './chunk-XVI6CBSX.js';
|
|
2
|
+
import { loadConfig, fetchFile, fetchIssues, fetchReleases, fetchBranches, fetchRepoMetadata, fetchTree, fetchPullRequests, fetchFiles, fetchCommits } from './chunk-FJ4GTN4U.js';
|
|
3
|
+
import { STAGING_AREA_REL } from '@anokye-labs/kbexplorer-core';
|
|
4
|
+
|
|
5
|
+
function isStructuralPath(path) {
|
|
6
|
+
return path.startsWith(".github/") || /(^|\/)CODEOWNERS$/.test(path);
|
|
7
|
+
}
|
|
8
|
+
var MAX_STRUCTURAL_FILE_SIZE = 256 * 1024;
|
|
9
|
+
async function fetchStructuredNodeMap(source, env, cache) {
|
|
10
|
+
for (const name of ["structured-node-map.yaml", "structured-node-map.yml"]) {
|
|
11
|
+
try {
|
|
12
|
+
return await fetchFile(source, name, env, cache);
|
|
13
|
+
} catch {
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
async function fetchNodemapRaw(source, env, cache) {
|
|
19
|
+
for (const name of ["nodemap.yaml", "nodemap.yml"]) {
|
|
20
|
+
try {
|
|
21
|
+
return await fetchFile(source, name, env, cache);
|
|
22
|
+
} catch {
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
var GitHubApiSource = class {
|
|
28
|
+
id = "github-api";
|
|
29
|
+
name = "GitHub API";
|
|
30
|
+
/** Advisory universe; authoritative affordances live on each retrieval. */
|
|
31
|
+
possibleAffordances = ["read", "write", "stage", "comment", "close", "merge"];
|
|
32
|
+
fetchPromise = null;
|
|
33
|
+
source;
|
|
34
|
+
preset;
|
|
35
|
+
env;
|
|
36
|
+
cache;
|
|
37
|
+
constructor(source, preset = "standard", env, cache) {
|
|
38
|
+
this.source = source;
|
|
39
|
+
this.preset = preset;
|
|
40
|
+
this.env = env;
|
|
41
|
+
this.cache = cache;
|
|
42
|
+
}
|
|
43
|
+
/** The locator of this repo's staging area (git index). */
|
|
44
|
+
get stagingHref() {
|
|
45
|
+
return `git://${this.source.repo}/.git/index`;
|
|
46
|
+
}
|
|
47
|
+
/** Fetch (memoized) so `resolveConfig` + `getRepoData` share one round-trip. */
|
|
48
|
+
fetch() {
|
|
49
|
+
if (!this.fetchPromise) this.fetchPromise = this.fetchGitHubData();
|
|
50
|
+
return this.fetchPromise;
|
|
51
|
+
}
|
|
52
|
+
/** Resolve the config without re-fetching. */
|
|
53
|
+
async resolveConfig() {
|
|
54
|
+
return (await this.fetch()).config;
|
|
55
|
+
}
|
|
56
|
+
async resolveThemeFileRaw() {
|
|
57
|
+
return (await this.fetch()).themeFileRaw;
|
|
58
|
+
}
|
|
59
|
+
async getRepoData() {
|
|
60
|
+
const data = await this.fetch();
|
|
61
|
+
return {
|
|
62
|
+
repo: this.source.repo,
|
|
63
|
+
tree: data.tree,
|
|
64
|
+
authoredContent: data.authoredContent,
|
|
65
|
+
nodemapRaw: data.nodemapRaw,
|
|
66
|
+
// `nodemapFiles`/`nodemapDirs` are omitted (rather than assigned empty
|
|
67
|
+
// objects) when there's nothing to report — this package enables
|
|
68
|
+
// exactOptionalPropertyTypes, and the loader/manifest convention is to
|
|
69
|
+
// leave optional fields unset rather than emit noisy `{}`.
|
|
70
|
+
...Object.keys(data.nodemapFiles).length > 0 ? { nodemapFiles: data.nodemapFiles } : {},
|
|
71
|
+
...Object.keys(data.nodemapDirs).length > 0 ? { nodemapDirs: data.nodemapDirs } : {},
|
|
72
|
+
listFiles: async () => [],
|
|
73
|
+
issues: data.issues,
|
|
74
|
+
// Reproduce the former remote shaping: no head_branch (so WorkProvider
|
|
75
|
+
// emits no branch connections), user/assignees retained for people.
|
|
76
|
+
// (user/assignees are set conditionally because this package's config
|
|
77
|
+
// enables exactOptionalPropertyTypes — an explicit `undefined` value is
|
|
78
|
+
// not assignable to the optional target fields.)
|
|
79
|
+
pullRequests: data.pullRequests.map((pr) => {
|
|
80
|
+
const mapped = {
|
|
81
|
+
number: pr.number,
|
|
82
|
+
title: pr.title,
|
|
83
|
+
body: pr.body ?? "",
|
|
84
|
+
state: pr.state,
|
|
85
|
+
labels: pr.labels.map((l) => ({ name: l.name, color: l.color ?? "" })),
|
|
86
|
+
html_url: pr.html_url,
|
|
87
|
+
created_at: pr.created_at,
|
|
88
|
+
updated_at: pr.updated_at
|
|
89
|
+
};
|
|
90
|
+
if (pr.user) mapped.user = pr.user;
|
|
91
|
+
if (pr.assignees) mapped.assignees = pr.assignees;
|
|
92
|
+
return mapped;
|
|
93
|
+
}),
|
|
94
|
+
commits: data.commits,
|
|
95
|
+
branches: data.branches,
|
|
96
|
+
repoMetadata: data.repoMetadata,
|
|
97
|
+
releases: data.releases,
|
|
98
|
+
structuralFiles: data.structuralFiles,
|
|
99
|
+
structuredNodeMapRaw: data.structuredNodeMapRaw,
|
|
100
|
+
contentModel: data.contentModel ?? null,
|
|
101
|
+
readme: data.readme,
|
|
102
|
+
themeFileRaw: data.themeFileRaw
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
// ── Formal resource surface (Git ≠ GitHub, per-retrieval affordances) ─────
|
|
106
|
+
async retrieve(query) {
|
|
107
|
+
const data = await this.fetch();
|
|
108
|
+
const kind = query.kind;
|
|
109
|
+
const worktree = query.worktree === true;
|
|
110
|
+
const staged = query.staged === true;
|
|
111
|
+
const out = [];
|
|
112
|
+
if (kind === "staging-area") {
|
|
113
|
+
out.push(this.stagingAreaResource());
|
|
114
|
+
return out;
|
|
115
|
+
}
|
|
116
|
+
if (!kind || kind === "file" || kind === "tree") {
|
|
117
|
+
for (const item of data.tree) {
|
|
118
|
+
if (kind === "file" && item.type !== "blob") continue;
|
|
119
|
+
if (kind === "tree" && item.type !== "tree") continue;
|
|
120
|
+
out.push(this.gitFileResource(item, { worktree, staged }));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (!kind || kind === "commit") {
|
|
124
|
+
for (const c of data.commits) out.push(this.commitResource(c));
|
|
125
|
+
}
|
|
126
|
+
if (!kind || kind === "issue") {
|
|
127
|
+
for (const issue of data.issues) out.push(this.issueResource(issue));
|
|
128
|
+
}
|
|
129
|
+
if (!kind || kind === "pull-request") {
|
|
130
|
+
for (const pr of data.pullRequests) out.push(this.pullRequestResource(pr));
|
|
131
|
+
}
|
|
132
|
+
if (!kind || kind === "release") {
|
|
133
|
+
for (const r of data.releases) out.push(this.releaseResource(r));
|
|
134
|
+
}
|
|
135
|
+
return out;
|
|
136
|
+
}
|
|
137
|
+
async get(href) {
|
|
138
|
+
if (href === this.stagingHref) return this.stagingAreaResource();
|
|
139
|
+
const all = await this.retrieve({});
|
|
140
|
+
return all.find((r) => r.href === href);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* A git file/tree resource. Affordances are situational:
|
|
144
|
+
* - plain read → `['read']`
|
|
145
|
+
* - writable worktree → `['read','write','stage']`
|
|
146
|
+
* - staged → `['read','write','stage']` PLUS a `staging-area` link.
|
|
147
|
+
*/
|
|
148
|
+
gitFileResource(item, ctx) {
|
|
149
|
+
const href = `git://${this.source.repo}/${item.path}`;
|
|
150
|
+
const affordances = ctx.worktree || ctx.staged ? ["read", "write", "stage"] : ["read"];
|
|
151
|
+
const links = [{ rel: "self", href }];
|
|
152
|
+
if (ctx.staged) {
|
|
153
|
+
links.push({ rel: STAGING_AREA_REL, href: this.stagingHref });
|
|
154
|
+
}
|
|
155
|
+
return { href, kind: item.type === "tree" ? "tree" : "file", affordances, links, body: { path: item.path } };
|
|
156
|
+
}
|
|
157
|
+
stagingAreaResource() {
|
|
158
|
+
return {
|
|
159
|
+
href: this.stagingHref,
|
|
160
|
+
kind: "staging-area",
|
|
161
|
+
affordances: ["read", "stage"],
|
|
162
|
+
links: [{ rel: "self", href: this.stagingHref }],
|
|
163
|
+
body: { repo: this.source.repo }
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
commitResource(c) {
|
|
167
|
+
const href = `git://${this.source.repo}/commit/${c.sha}`;
|
|
168
|
+
return {
|
|
169
|
+
href,
|
|
170
|
+
kind: "commit",
|
|
171
|
+
affordances: ["read"],
|
|
172
|
+
links: [{ rel: "self", href }],
|
|
173
|
+
body: { sha: c.sha, message: c.commit.message }
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
issueResource(issue) {
|
|
177
|
+
const href = `github://${this.source.repo}/issues/${issue.number}`;
|
|
178
|
+
return {
|
|
179
|
+
href,
|
|
180
|
+
kind: "issue",
|
|
181
|
+
affordances: ["read", "comment", "close"],
|
|
182
|
+
links: [{ rel: "self", href }],
|
|
183
|
+
body: { number: issue.number, title: issue.title, state: issue.state }
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
pullRequestResource(pr) {
|
|
187
|
+
const href = `github://${this.source.repo}/pull/${pr.number}`;
|
|
188
|
+
return {
|
|
189
|
+
href,
|
|
190
|
+
kind: "pull-request",
|
|
191
|
+
affordances: ["read", "comment", "close", "merge"],
|
|
192
|
+
links: [{ rel: "self", href }],
|
|
193
|
+
body: { number: pr.number, title: pr.title, state: pr.state }
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
releaseResource(r) {
|
|
197
|
+
const href = `github://${this.source.repo}/releases/${r.tag_name}`;
|
|
198
|
+
return {
|
|
199
|
+
href,
|
|
200
|
+
kind: "release",
|
|
201
|
+
affordances: ["read"],
|
|
202
|
+
links: [{ rel: "self", href }],
|
|
203
|
+
body: { tag: r.tag_name }
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
// ── Data path (moved verbatim from the former remote loader) ──────────────
|
|
207
|
+
async fetchGitHubData() {
|
|
208
|
+
const source = this.source;
|
|
209
|
+
const preset = this.preset;
|
|
210
|
+
const env = this.env;
|
|
211
|
+
const cache = this.cache;
|
|
212
|
+
const config = await loadConfig(source, env, cache);
|
|
213
|
+
const themeFilePromise = config.theme?.themesFile ? fetchFile(source, config.theme.themesFile, env, cache).catch(() => null) : Promise.resolve(null);
|
|
214
|
+
const [issues, readme, releases, themeFileRaw, branches, repoMetadata, nodemapRaw] = await Promise.all([
|
|
215
|
+
fetchIssues(source, env, cache).catch(() => []),
|
|
216
|
+
fetchFile(source, "README.md", env, cache).catch(() => null),
|
|
217
|
+
fetchReleases(source, 30, env, cache).catch(() => []),
|
|
218
|
+
themeFilePromise,
|
|
219
|
+
fetchBranches(source, env, cache).catch(() => []),
|
|
220
|
+
fetchRepoMetadata(source, env, cache).catch(() => null),
|
|
221
|
+
fetchNodemapRaw(source, env, cache)
|
|
222
|
+
]);
|
|
223
|
+
let tree = [];
|
|
224
|
+
let pullRequests = [];
|
|
225
|
+
let commits = [];
|
|
226
|
+
const authoredContent = {};
|
|
227
|
+
const structuralFiles = {};
|
|
228
|
+
let structuredNodeMapRaw = null;
|
|
229
|
+
let contentModel = null;
|
|
230
|
+
let nodemapFiles = {};
|
|
231
|
+
let nodemapDirs = {};
|
|
232
|
+
if (preset === "standard" || preset === "full") {
|
|
233
|
+
const [treeResult, prResult] = await Promise.all([
|
|
234
|
+
fetchTree(source, void 0, env, cache).catch(() => []),
|
|
235
|
+
fetchPullRequests(source, env, cache).catch(() => [])
|
|
236
|
+
]);
|
|
237
|
+
tree = treeResult;
|
|
238
|
+
pullRequests = prResult;
|
|
239
|
+
if (config.source.path) {
|
|
240
|
+
try {
|
|
241
|
+
const contentTree = await fetchTree(source, config.source.path, env, cache);
|
|
242
|
+
const mdFiles = contentTree.filter((item) => item.type === "blob" && item.path.endsWith(".md")).map((item) => item.path);
|
|
243
|
+
const files = await fetchFiles(source, mdFiles, env, cache);
|
|
244
|
+
for (const [path, content] of files) {
|
|
245
|
+
authoredContent[path] = content;
|
|
246
|
+
}
|
|
247
|
+
} catch {
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
contentModel = await this.fetchContentModel(config);
|
|
251
|
+
try {
|
|
252
|
+
const structuralPaths = tree.filter(
|
|
253
|
+
(item) => item.type === "blob" && isStructuralPath(item.path) && !(typeof item.size === "number" && item.size > MAX_STRUCTURAL_FILE_SIZE)
|
|
254
|
+
).map((item) => item.path);
|
|
255
|
+
if (structuralPaths.length > 0) {
|
|
256
|
+
const files = await fetchFiles(source, structuralPaths, env, cache);
|
|
257
|
+
for (const [path, content] of files) {
|
|
258
|
+
if (content.length > MAX_STRUCTURAL_FILE_SIZE) continue;
|
|
259
|
+
structuralFiles[path] = content;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
structuredNodeMapRaw = await fetchStructuredNodeMap(source, env, cache);
|
|
263
|
+
} catch {
|
|
264
|
+
}
|
|
265
|
+
if (nodemapRaw !== null) {
|
|
266
|
+
try {
|
|
267
|
+
const collected = await collectNodemapData(
|
|
268
|
+
nodemapRaw,
|
|
269
|
+
tree,
|
|
270
|
+
(path) => fetchFile(source, path, env, cache).catch(() => null),
|
|
271
|
+
(dir) => this.listNodemapDirFromTree(tree, dir)
|
|
272
|
+
);
|
|
273
|
+
nodemapFiles = collected.nodemapFiles;
|
|
274
|
+
nodemapDirs = collected.nodemapDirs;
|
|
275
|
+
} catch {
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (preset === "full") {
|
|
280
|
+
commits = await fetchCommits(source, 50, env, cache).catch(() => []);
|
|
281
|
+
}
|
|
282
|
+
return {
|
|
283
|
+
issues,
|
|
284
|
+
pullRequests,
|
|
285
|
+
tree,
|
|
286
|
+
readme,
|
|
287
|
+
commits,
|
|
288
|
+
releases,
|
|
289
|
+
branches,
|
|
290
|
+
repoMetadata,
|
|
291
|
+
authoredContent,
|
|
292
|
+
structuralFiles,
|
|
293
|
+
structuredNodeMapRaw,
|
|
294
|
+
contentModel,
|
|
295
|
+
config,
|
|
296
|
+
themeFileRaw: themeFileRaw ?? null,
|
|
297
|
+
nodemapRaw,
|
|
298
|
+
nodemapFiles,
|
|
299
|
+
nodemapDirs
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Direct children of `dir` in an already-fetched git tree — a nodemap
|
|
304
|
+
* `directory:` entry's listing derived with no extra API call. Skips
|
|
305
|
+
* dotfile-named children, mirroring the local source's `listNodemapDir`.
|
|
306
|
+
*/
|
|
307
|
+
listNodemapDirFromTree(tree, dir) {
|
|
308
|
+
const prefix = `${dir}/`;
|
|
309
|
+
const out = tree.filter((item) => {
|
|
310
|
+
if (!item.path.startsWith(prefix)) return false;
|
|
311
|
+
const rest = item.path.slice(prefix.length);
|
|
312
|
+
if (rest === "" || rest.includes("/")) return false;
|
|
313
|
+
return !rest.startsWith(".");
|
|
314
|
+
});
|
|
315
|
+
return Promise.resolve(out);
|
|
316
|
+
}
|
|
317
|
+
async fetchContentModel(config) {
|
|
318
|
+
const env = this.env;
|
|
319
|
+
const cache = this.cache;
|
|
320
|
+
const root = resolveStructuredContentPath(config, env);
|
|
321
|
+
const explicitPath = hasExplicitStructuredContentPath(config, env);
|
|
322
|
+
try {
|
|
323
|
+
const contentModelTree = await fetchTree(this.source, root, env, cache);
|
|
324
|
+
const paths = contentModelTree.filter((item) => item.type === "blob").map((item) => item.path).filter((path) => !path.slice(root.length + 1).split("/").some((segment) => segment.startsWith(".")));
|
|
325
|
+
if (paths.length === 0) {
|
|
326
|
+
if (explicitPath) {
|
|
327
|
+
console.warn(`[github-api-source] No structured content files found at configured path ${root}`);
|
|
328
|
+
}
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
const files = await fetchFiles(this.source, paths, env, cache);
|
|
332
|
+
const sourceFiles = {};
|
|
333
|
+
for (const [path, content] of files) {
|
|
334
|
+
const relativePath = path.startsWith(`${root}/`) ? path.slice(root.length + 1) : path;
|
|
335
|
+
sourceFiles[relativePath] = content;
|
|
336
|
+
}
|
|
337
|
+
if (Object.keys(sourceFiles).length === 0) {
|
|
338
|
+
if (explicitPath) {
|
|
339
|
+
console.warn(`[github-api-source] Structured content path ${root} was listed but no files could be fetched`);
|
|
340
|
+
}
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
return { root, files: sourceFiles };
|
|
344
|
+
} catch (error) {
|
|
345
|
+
console.warn(`[github-api-source] Failed to fetch structured content from ${root}:`, error);
|
|
346
|
+
return null;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
export { GitHubApiSource };
|