@tomingtoming/kioq 0.8.1 → 0.8.3

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.
@@ -38,6 +38,8 @@ export class GitHubStorage {
38
38
  fetchFn;
39
39
  execFileAsyncFn;
40
40
  setupValidated = false;
41
+ lastFetchMs = 0;
42
+ static FETCH_INTERVAL_MS = 10_000;
41
43
  constructor(githubConfig, rootPath, deps = {}) {
42
44
  this.githubConfig = githubConfig;
43
45
  this.rootPath = rootPath;
@@ -48,17 +50,21 @@ export class GitHubStorage {
48
50
  this.fetchFn = deps.fetchFn ?? fetch;
49
51
  this.execFileAsyncFn = deps.execFileAsyncFn ?? execFileAsync;
50
52
  }
51
- // --- Reads: delegate to local clone ---
52
- stat(relativePath) {
53
+ // --- Reads: delegate to local clone (with auto-refresh) ---
54
+ async stat(relativePath) {
55
+ await this.refreshIfStale();
53
56
  return this.local.stat(relativePath);
54
57
  }
55
- readFile(relativePath) {
58
+ async readFile(relativePath) {
59
+ await this.refreshIfStale();
56
60
  return this.local.readFile(relativePath);
57
61
  }
58
- readdir(relativePath) {
62
+ async readdir(relativePath) {
63
+ await this.refreshIfStale();
59
64
  return this.local.readdir(relativePath);
60
65
  }
61
- listMarkdownFiles() {
66
+ async listMarkdownFiles() {
67
+ await this.refreshIfStale();
62
68
  return this.local.listMarkdownFiles();
63
69
  }
64
70
  // --- Writes: GitHub Git Data API ---
@@ -116,7 +122,7 @@ export class GitHubStorage {
116
122
  catch {
117
123
  // .git not found — auto-clone below
118
124
  }
119
- const cloneUrl = `https://github.com/${this.githubConfig.owner}/${this.githubConfig.repo}.git`;
125
+ const cloneUrl = `https://x-access-token:${this.githubConfig.token}@github.com/${this.githubConfig.owner}/${this.githubConfig.repo}.git`;
120
126
  try {
121
127
  await fs.mkdir(path.dirname(this.rootPath), { recursive: true });
122
128
  await this.execFileAsyncFn("git", ["clone", "--branch", this.branch, "--single-branch", cloneUrl, this.rootPath], { timeout: 120_000 });
@@ -352,6 +358,7 @@ export class GitHubStorage {
352
358
  cwd: this.rootPath,
353
359
  timeout: 30_000,
354
360
  });
361
+ this.lastFetchMs = Date.now();
355
362
  }
356
363
  catch (error) {
357
364
  throw new Error(`${context}: ${this.normalizeExecError(error)}`);
@@ -365,6 +372,25 @@ export class GitHubStorage {
365
372
  // best-effort only
366
373
  }
367
374
  }
375
+ async refreshIfStale() {
376
+ const now = Date.now();
377
+ if (now - this.lastFetchMs < GitHubStorage.FETCH_INTERVAL_MS) {
378
+ return;
379
+ }
380
+ try {
381
+ const { stdout: localRef } = await this.execFileAsyncFn("git", ["rev-parse", `refs/heads/${this.branch}`], { cwd: this.rootPath, timeout: 5_000 });
382
+ await this.execFileAsyncFn("git", ["fetch", "--no-tags", "origin", this.branch], { cwd: this.rootPath, timeout: 15_000 });
383
+ const { stdout: remoteRef } = await this.execFileAsyncFn("git", ["rev-parse", `refs/remotes/origin/${this.branch}`], { cwd: this.rootPath, timeout: 5_000 });
384
+ this.lastFetchMs = Date.now();
385
+ if (localRef.trim() !== remoteRef.trim()) {
386
+ await this.pullLocal("git pull --ff-only failed during auto-refresh");
387
+ }
388
+ }
389
+ catch {
390
+ // best-effort: if fetch fails, proceed with stale data
391
+ this.lastFetchMs = Date.now();
392
+ }
393
+ }
368
394
  isRetryableBatchError(error) {
369
395
  return (error instanceof GitHubApiError && error.retryable)
370
396
  || this.isTransientNetworkError(error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomingtoming/kioq",
3
- "version": "0.8.1",
3
+ "version": "0.8.3",
4
4
  "description": "Japanese-first local markdown MCP server",
5
5
  "type": "module",
6
6
  "bin": {