@gobi-ai/cli 0.6.3 → 0.6.6

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.
@@ -1,5 +1,6 @@
1
- import { existsSync, readFileSync } from "fs";
1
+ import { existsSync, readFileSync, appendFileSync } from "fs";
2
2
  import { join, extname } from "path";
3
+ import ignore from "ignore";
3
4
  import { WEBDRIVE_BASE_URL } from "./constants.js";
4
5
  export function extractWikiLinks(content) {
5
6
  const seen = new Set();
@@ -13,7 +14,31 @@ export function extractWikiLinks(content) {
13
14
  }
14
15
  return results;
15
16
  }
16
- export async function uploadAttachments(vaultSlug, links, token) {
17
+ function readSyncfilesPatterns(gobiDir) {
18
+ const syncfilesPath = join(gobiDir, "syncfiles");
19
+ if (!existsSync(syncfilesPath))
20
+ return [];
21
+ return readFileSync(syncfilesPath, "utf-8")
22
+ .split("\n")
23
+ .map((l) => l.trim())
24
+ .filter((l) => l.length > 0 && !l.startsWith("#"));
25
+ }
26
+ function isPathCovered(filePath, patterns) {
27
+ if (patterns.length === 0)
28
+ return false;
29
+ return ignore().add(patterns).ignores(filePath.replace(/\\/g, "/"));
30
+ }
31
+ function addToLocalSyncfiles(gobiDir, filePath) {
32
+ const patterns = readSyncfilesPatterns(gobiDir);
33
+ if (isPathCovered(filePath, patterns))
34
+ return;
35
+ const syncfilesPath = join(gobiDir, "syncfiles");
36
+ appendFileSync(syncfilesPath, `\n${filePath}`);
37
+ console.log(`Added to syncfiles: ${filePath}`);
38
+ }
39
+ export async function uploadAttachments(vaultSlug, links, token, options) {
40
+ const addToSyncfiles = options?.addToSyncfiles ?? false;
41
+ const gobiDir = join(process.cwd(), ".gobi");
17
42
  for (const link of links) {
18
43
  let localPath = join(process.cwd(), link);
19
44
  if (!existsSync(localPath)) {
@@ -28,7 +53,8 @@ export async function uploadAttachments(vaultSlug, links, token) {
28
53
  const filePath = extname(link) ? link : link + ".md";
29
54
  console.log(`Uploading [[${link}]]...`);
30
55
  const content = readFileSync(localPath);
31
- const url = `${WEBDRIVE_BASE_URL}/api/v1/vaults/${vaultSlug}/files/${filePath}`;
56
+ const queryString = addToSyncfiles ? "?add_to_syncfiles=true" : "";
57
+ const url = `${WEBDRIVE_BASE_URL}/api/v1/vaults/${vaultSlug}/files/${filePath}${queryString}`;
32
58
  const res = await fetch(url, {
33
59
  method: "PUT",
34
60
  headers: {
@@ -41,5 +67,8 @@ export async function uploadAttachments(vaultSlug, links, token) {
41
67
  throw new Error(`Failed to upload [[${link}]]: HTTP ${res.status}: ${(await res.text()) || "(no body)"}`);
42
68
  }
43
69
  console.log(`Uploaded [[${link}]]`);
70
+ if (addToSyncfiles) {
71
+ addToLocalSyncfiles(gobiDir, filePath);
72
+ }
44
73
  }
45
74
  }
@@ -74,7 +74,7 @@ export function registerBrainCommand(program) {
74
74
  }
75
75
  if (opts.mode != null)
76
76
  body.mode = opts.mode;
77
- const resp = (await apiPost(`/session/targeted`, body));
77
+ const resp = (await apiPost(`/chat/targeted`, body));
78
78
  const data = unwrapResp(resp);
79
79
  if (isJsonMode(brain)) {
80
80
  jsonOut(data);
@@ -198,7 +198,7 @@ export function registerBrainCommand(program) {
198
198
  if (opts.autoAttachments) {
199
199
  const token = await getValidToken();
200
200
  const links = extractWikiLinks(opts.content);
201
- await uploadAttachments(vaultSlug, links, token);
201
+ await uploadAttachments(vaultSlug, links, token, { addToSyncfiles: true });
202
202
  }
203
203
  const resp = (await apiPost(`/brain-updates/vault/${vaultSlug}`, {
204
204
  title: opts.title,
@@ -16,7 +16,7 @@ export function registerSessionsCommand(program) {
16
16
  };
17
17
  if (opts.cursor)
18
18
  params.cursor = opts.cursor;
19
- const resp = (await apiGet(`/session/${sessionId}`, params));
19
+ const resp = (await apiGet(`/chat/${sessionId}`, params));
20
20
  const data = unwrapResp(resp);
21
21
  if (isJsonMode(sessions)) {
22
22
  jsonOut(data);
@@ -56,7 +56,7 @@ export function registerSessionsCommand(program) {
56
56
  const query = { limit: parseInt(opts.limit, 10) };
57
57
  if (opts.cursor)
58
58
  query.cursor = opts.cursor;
59
- const resp = (await apiGet(`/session/my-sessions`, query));
59
+ const resp = (await apiGet(`/chat/my-sessions`, query));
60
60
  const items = (resp.data || []);
61
61
  const pagination = (resp.pagination || {});
62
62
  if (isJsonMode(sessions)) {
@@ -115,7 +115,7 @@ export function registerSessionsCommand(program) {
115
115
  else {
116
116
  body.content = opts.content;
117
117
  }
118
- const resp = (await apiPost(`/session/${sessionId}/reply`, body));
118
+ const resp = (await apiPost(`/chat/${sessionId}/reply`, body));
119
119
  const msg = unwrapResp(resp);
120
120
  if (isJsonMode(sessions)) {
121
121
  jsonOut(msg);
@@ -154,7 +154,7 @@ export function registerSpaceCommand(program) {
154
154
  const vaultSlug = resolveVaultSlug(opts);
155
155
  const token = await getValidToken();
156
156
  const links = extractWikiLinks(content);
157
- await uploadAttachments(vaultSlug, links, token);
157
+ await uploadAttachments(vaultSlug, links, token, { addToSyncfiles: true });
158
158
  }
159
159
  const spaceSlug = resolveSpaceSlug(space);
160
160
  const resp = (await apiPost(`/spaces/${spaceSlug}/threads`, {
@@ -148,6 +148,15 @@ export function readSyncfiles(gobiDir) {
148
148
  const contentHash = createHash("md5").update(content).digest("hex");
149
149
  return { patterns, contentHash };
150
150
  }
151
+ export function readPrivatefiles(gobiDir) {
152
+ const path = join(gobiDir, "privatefiles");
153
+ if (!existsSync(path))
154
+ return [];
155
+ return readFileSync(path, "utf-8")
156
+ .split("\n")
157
+ .map((l) => l.trim())
158
+ .filter((l) => l.length > 0 && !l.startsWith("#"));
159
+ }
151
160
  export function buildWhitelistMatcher(patterns) {
152
161
  if (patterns.length === 0)
153
162
  return () => false;
@@ -273,6 +282,21 @@ async function webdriveSync(baseUrl, vaultSlug, body, token) {
273
282
  }
274
283
  return (await res.json());
275
284
  }
285
+ async function webdrivePrivatefiles(baseUrl, vaultSlug, patterns, token) {
286
+ const url = `${baseUrl}/api/v1/vaults/${vaultSlug}/privatefiles`;
287
+ const res = await fetch(url, {
288
+ method: "POST",
289
+ headers: {
290
+ Authorization: `Bearer ${token}`,
291
+ "Content-Type": "application/json",
292
+ },
293
+ body: JSON.stringify({ patterns }),
294
+ });
295
+ if (!res.ok) {
296
+ throw new Error(`Privatefiles request failed: HTTP ${res.status}: ${await res.text()}`);
297
+ }
298
+ return (await res.json());
299
+ }
276
300
  // ─── Conflict Resolution ──────────────────────────────────────────────────────
277
301
  function formatDate(ms) {
278
302
  return new Date(ms).toLocaleString();
@@ -346,6 +370,20 @@ export async function runSync(opts) {
346
370
  console.log("Full sync: ignoring cursor and hash cache.");
347
371
  }
348
372
  const token = opts.authToken ?? (await getValidToken());
373
+ // Sync privatefiles with server
374
+ if (!opts.dryRun) {
375
+ try {
376
+ const localPrivatePatterns = readPrivatefiles(gobiDir);
377
+ const privateresp = await webdrivePrivatefiles(baseUrl, vaultSlug, localPrivatePatterns, token);
378
+ if (!opts.uploadOnly && privateresp.patterns.length > 0) {
379
+ await writeFile(join(gobiDir, "privatefiles"), privateresp.patterns.join("\n") + "\n");
380
+ }
381
+ }
382
+ catch (err) {
383
+ if (!jsonMode)
384
+ console.error(`Warning: Failed to sync privatefiles: ${err.message}`);
385
+ }
386
+ }
349
387
  // Read syncfiles whitelist
350
388
  const { patterns: currPatterns, contentHash: currSyncfilesHash } = readSyncfiles(gobiDir);
351
389
  if (currPatterns.length === 0 && !jsonMode) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobi-ai/cli",
3
- "version": "0.6.3",
3
+ "version": "0.6.6",
4
4
  "description": "CLI client for the Gobi collaborative knowledge platform",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -44,6 +44,7 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "better-sqlite3": "^12.8.0",
47
+ "chokidar": "^5.0.0",
47
48
  "commander": "^12.1.0",
48
49
  "ignore": "^7.0.5",
49
50
  "inquirer": "^12.3.0",
@@ -10,12 +10,12 @@ description: >-
10
10
  allowed-tools: Bash(gobi:*)
11
11
  metadata:
12
12
  author: gobi-ai
13
- version: "0.6.3"
13
+ version: "0.6.5"
14
14
  ---
15
15
 
16
16
  # gobi-cli
17
17
 
18
- A CLI client for the Gobi collaborative knowledge platform (v0.6.3).
18
+ A CLI client for the Gobi collaborative knowledge platform (v0.6.5).
19
19
 
20
20
  ## Prerequisites
21
21