jowork 0.2.4 → 0.3.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.
Files changed (38) hide show
  1. package/dist/{chunk-ROIINI33.js → chunk-4PIT2GZ4.js} +13 -1
  2. package/dist/{chunk-XLYRHKG6.js → chunk-54SD5GBF.js} +1 -1
  3. package/dist/chunk-63AMINQC.js +156 -0
  4. package/dist/{chunk-XAEGXSEO.js → chunk-74AHY7X6.js} +4 -0
  5. package/dist/{chunk-7U3SXINY.js → chunk-ATAUWJYD.js} +320 -50
  6. package/dist/chunk-DQW74UCN.js +671 -0
  7. package/dist/chunk-EYP6WMFF.js +153 -0
  8. package/dist/{chunk-JSTXMDXI.js → chunk-FCFZCZHR.js} +1 -1
  9. package/dist/chunk-FX6Z3QHV.js +34 -0
  10. package/dist/chunk-HENAABEL.js +419 -0
  11. package/dist/chunk-OXWWOKC7.js +201 -0
  12. package/dist/chunk-QGHJ45PL.js +661 -0
  13. package/dist/chunk-RO3KK5RC.js +132 -0
  14. package/dist/{chunk-JE6TOU7W.js → chunk-TFMF3EXE.js} +2 -7
  15. package/dist/{chunk-TN327MDF.js → chunk-VX662YLA.js} +3 -3
  16. package/dist/cli.js +338 -149
  17. package/dist/{config-AI6UIJJN.js → config-FH2XLN7A.js} +2 -2
  18. package/dist/content-reader-VPGTR2SF.js +10 -0
  19. package/dist/context-ZNI3WOB7.js +10 -0
  20. package/dist/{credential-store-ZRZCSRPC.js → credential-store-OS5ZY4OW.js} +2 -2
  21. package/dist/{feishu-A6YVFKEN.js → feishu-XW5T6ER2.js} +8 -3
  22. package/dist/{git-manager-N35XSG4Y.js → git-manager-RVWV2GSV.js} +2 -1
  23. package/dist/github-PQKAYTLO.js +11 -0
  24. package/dist/{paths-JXOMBYIT.js → paths-FFRET6F7.js} +7 -3
  25. package/dist/{server-5GVWN2NB.js → server-WEADPUST.js} +59 -66
  26. package/dist/{setup-IDQDPCEJ.js → setup-S2S2CHB2.js} +91 -32
  27. package/dist/sync-SRLFR5NA.js +21 -0
  28. package/dist/transport.js +6 -4
  29. package/package.json +1 -1
  30. package/src/dashboard/public/app.js +34 -8
  31. package/src/dashboard/public/style.css +14 -0
  32. package/dist/chunk-AIXKXEYS.js +0 -547
  33. package/dist/chunk-L5ZR7TSK.js +0 -82
  34. package/dist/chunk-LS2AJM5A.js +0 -163
  35. package/dist/chunk-QMOFQX7X.js +0 -612
  36. package/dist/chunk-YJWTKFWX.js +0 -451
  37. package/dist/github-SHWUFNYB.js +0 -10
  38. package/dist/sync-7V54N62M.js +0 -18
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  readConfig,
3
3
  writeConfig
4
- } from "./chunk-JSTXMDXI.js";
5
- import "./chunk-ROIINI33.js";
4
+ } from "./chunk-FCFZCZHR.js";
5
+ import "./chunk-4PIT2GZ4.js";
6
6
  import "./chunk-UJ4KEHGZ.js";
7
7
  export {
8
8
  readConfig,
@@ -0,0 +1,10 @@
1
+ import {
2
+ readObjectContent,
3
+ readObjectContents
4
+ } from "./chunk-FX6Z3QHV.js";
5
+ import "./chunk-4PIT2GZ4.js";
6
+ import "./chunk-UJ4KEHGZ.js";
7
+ export {
8
+ readObjectContent,
9
+ readObjectContents
10
+ };
@@ -0,0 +1,10 @@
1
+ import {
2
+ SyncContext,
3
+ contentHash
4
+ } from "./chunk-OXWWOKC7.js";
5
+ import "./chunk-TFMF3EXE.js";
6
+ import "./chunk-UJ4KEHGZ.js";
7
+ export {
8
+ SyncContext,
9
+ contentHash
10
+ };
@@ -3,8 +3,8 @@ import {
3
3
  listCredentials,
4
4
  loadCredential,
5
5
  saveCredential
6
- } from "./chunk-XLYRHKG6.js";
7
- import "./chunk-ROIINI33.js";
6
+ } from "./chunk-54SD5GBF.js";
7
+ import "./chunk-4PIT2GZ4.js";
8
8
  import "./chunk-UJ4KEHGZ.js";
9
9
  export {
10
10
  deleteCredential,
@@ -1,13 +1,17 @@
1
1
  import {
2
- contentHash,
3
2
  getFeishuToken,
4
3
  syncFeishu,
5
4
  syncFeishuApprovals,
6
5
  syncFeishuDocs,
6
+ syncFeishuLinks,
7
7
  syncFeishuMeetings
8
- } from "./chunk-QMOFQX7X.js";
9
- import "./chunk-JE6TOU7W.js";
8
+ } from "./chunk-DQW74UCN.js";
9
+ import "./chunk-RO3KK5RC.js";
10
10
  import "./chunk-MYDK7MWB.js";
11
+ import {
12
+ contentHash
13
+ } from "./chunk-OXWWOKC7.js";
14
+ import "./chunk-TFMF3EXE.js";
11
15
  import "./chunk-UJ4KEHGZ.js";
12
16
  export {
13
17
  contentHash,
@@ -15,5 +19,6 @@ export {
15
19
  syncFeishu,
16
20
  syncFeishuApprovals,
17
21
  syncFeishuDocs,
22
+ syncFeishuLinks,
18
23
  syncFeishuMeetings
19
24
  };
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  GitManager
3
- } from "./chunk-L5ZR7TSK.js";
3
+ } from "./chunk-EYP6WMFF.js";
4
+ import "./chunk-4PIT2GZ4.js";
4
5
  import "./chunk-MYDK7MWB.js";
5
6
  import "./chunk-UJ4KEHGZ.js";
6
7
  export {
@@ -0,0 +1,11 @@
1
+ import {
2
+ syncGitHub
3
+ } from "./chunk-63AMINQC.js";
4
+ import "./chunk-EYP6WMFF.js";
5
+ import "./chunk-4PIT2GZ4.js";
6
+ import "./chunk-RO3KK5RC.js";
7
+ import "./chunk-MYDK7MWB.js";
8
+ import "./chunk-UJ4KEHGZ.js";
9
+ export {
10
+ syncGitHub
11
+ };
@@ -1,19 +1,23 @@
1
1
  import {
2
+ bareReposDir,
2
3
  configPath,
3
4
  credentialsDir,
4
5
  dataDir,
5
6
  dbPath,
6
7
  fileRepoDir,
7
8
  joworkDir,
8
- logsDir
9
- } from "./chunk-ROIINI33.js";
9
+ logsDir,
10
+ pluginsDir
11
+ } from "./chunk-4PIT2GZ4.js";
10
12
  import "./chunk-UJ4KEHGZ.js";
11
13
  export {
14
+ bareReposDir,
12
15
  configPath,
13
16
  credentialsDir,
14
17
  dataDir,
15
18
  dbPath,
16
19
  fileRepoDir,
17
20
  joworkDir,
18
- logsDir
21
+ logsDir,
22
+ pluginsDir
19
23
  };
@@ -2,38 +2,44 @@ import {
2
2
  linkAllUnprocessed,
3
3
  syncGitLab,
4
4
  syncLinear
5
- } from "./chunk-YJWTKFWX.js";
5
+ } from "./chunk-HENAABEL.js";
6
+ import {
7
+ syncGitHub
8
+ } from "./chunk-63AMINQC.js";
9
+ import "./chunk-EYP6WMFF.js";
6
10
  import {
7
11
  DbManager
8
- } from "./chunk-XAEGXSEO.js";
12
+ } from "./chunk-74AHY7X6.js";
9
13
  import {
10
14
  GoalManager
11
- } from "./chunk-TN327MDF.js";
15
+ } from "./chunk-VX662YLA.js";
12
16
  import {
13
17
  listCredentials,
14
18
  loadCredential
15
- } from "./chunk-XLYRHKG6.js";
19
+ } from "./chunk-54SD5GBF.js";
20
+ import "./chunk-FX6Z3QHV.js";
16
21
  import {
17
22
  dbPath,
18
23
  joworkDir
19
- } from "./chunk-ROIINI33.js";
20
- import {
21
- syncGitHub
22
- } from "./chunk-LS2AJM5A.js";
24
+ } from "./chunk-4PIT2GZ4.js";
23
25
  import {
24
- contentHash,
25
26
  syncFeishu,
26
27
  syncFeishuApprovals,
27
28
  syncFeishuDocs,
28
29
  syncFeishuMeetings
29
- } from "./chunk-QMOFQX7X.js";
30
- import {
31
- createId
32
- } from "./chunk-JE6TOU7W.js";
30
+ } from "./chunk-DQW74UCN.js";
31
+ import "./chunk-RO3KK5RC.js";
33
32
  import {
34
33
  logError,
35
34
  logInfo
36
35
  } from "./chunk-MYDK7MWB.js";
36
+ import {
37
+ SyncContext,
38
+ contentHash
39
+ } from "./chunk-OXWWOKC7.js";
40
+ import {
41
+ createId
42
+ } from "./chunk-TFMF3EXE.js";
37
43
  import {
38
44
  __require
39
45
  } from "./chunk-UJ4KEHGZ.js";
@@ -184,10 +190,6 @@ function indexDirectory(sqlite, dirPath, opts = {}) {
184
190
  INSERT OR IGNORE INTO objects (id, source, source_type, uri, title, summary, tags, content_hash, last_synced_at, created_at)
185
191
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
186
192
  `);
187
- const insertBody = sqlite.prepare(`
188
- INSERT OR IGNORE INTO object_bodies (object_id, content, content_type, fetched_at)
189
- VALUES (?, ?, ?, ?)
190
- `);
191
193
  const insertFts = sqlite.prepare(`
192
194
  INSERT INTO objects_fts(rowid, title, summary, tags, source, source_type, body_excerpt)
193
195
  VALUES (?, ?, ?, ?, ?, ?, ?)
@@ -212,7 +214,6 @@ function indexDirectory(sqlite, dirPath, opts = {}) {
212
214
  const tags = JSON.stringify(["local", "file", ext.replace(".", "")].filter(Boolean));
213
215
  const sourceType = detectFileType(ext);
214
216
  insertObj.run(id, "local", sourceType, uri, fileName, summary, tags, hash, now, now);
215
- insertBody.run(id, content, mimeForExt(ext), now);
216
217
  try {
217
218
  const rowid = getRowid.get(id);
218
219
  if (rowid) {
@@ -279,25 +280,6 @@ function detectFileType(ext) {
279
280
  };
280
281
  return map[ext.toLowerCase()] ?? "file";
281
282
  }
282
- function mimeForExt(ext) {
283
- const map = {
284
- ".ts": "text/typescript",
285
- ".js": "text/javascript",
286
- ".json": "application/json",
287
- ".md": "text/markdown",
288
- ".html": "text/html",
289
- ".css": "text/css",
290
- ".py": "text/x-python",
291
- ".go": "text/x-go",
292
- ".yaml": "text/yaml",
293
- ".yml": "text/yaml",
294
- ".toml": "text/toml",
295
- ".xml": "text/xml",
296
- ".sql": "text/x-sql",
297
- ".sh": "text/x-shellscript"
298
- };
299
- return map[ext.toLowerCase()] ?? "text/plain";
300
- }
301
283
 
302
284
  // src/dashboard/server.ts
303
285
  var DEFAULT_PORT = 18801;
@@ -490,28 +472,11 @@ async function startDashboard(opts = {}) {
490
472
  };
491
473
  return map[ext.toLowerCase()] ?? "file";
492
474
  };
493
- const mimeForExt2 = (ext) => {
494
- const map = {
495
- ".ts": "text/typescript",
496
- ".js": "text/javascript",
497
- ".json": "application/json",
498
- ".md": "text/markdown",
499
- ".html": "text/html",
500
- ".css": "text/css",
501
- ".py": "text/x-python",
502
- ".go": "text/x-go"
503
- };
504
- return map[ext.toLowerCase()] ?? "text/plain";
505
- };
506
475
  const checkExists = sqlite.prepare("SELECT id FROM objects WHERE uri = ?");
507
476
  const insertObj = sqlite.prepare(`
508
477
  INSERT OR IGNORE INTO objects (id, source, source_type, uri, title, summary, tags, content_hash, last_synced_at, created_at)
509
478
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
510
479
  `);
511
- const insertBody = sqlite.prepare(`
512
- INSERT OR IGNORE INTO object_bodies (object_id, content, content_type, fetched_at)
513
- VALUES (?, ?, ?, ?)
514
- `);
515
480
  const insertFts = sqlite.prepare(`
516
481
  INSERT INTO objects_fts(rowid, title, summary, tags, source, source_type, body_excerpt)
517
482
  VALUES (?, ?, ?, ?, ?, ?, ?)
@@ -546,7 +511,6 @@ async function startDashboard(opts = {}) {
546
511
  const tags = JSON.stringify(["local", "upload", ext.replace(".", "")].filter(Boolean));
547
512
  const sourceType = detectFileType2(ext);
548
513
  insertObj.run(id, "local", sourceType, uri, fileName, summary, tags, hash, now, now);
549
- insertBody.run(id, file.content, mimeForExt2(ext), now);
550
514
  try {
551
515
  const rowid = getRowid.get(id);
552
516
  if (rowid) {
@@ -604,30 +568,41 @@ async function startDashboard(opts = {}) {
604
568
  try {
605
569
  let result = {};
606
570
  switch (source) {
607
- case "feishu":
608
- result = await syncFeishu(sqlite, cred.data, logger);
571
+ case "feishu": {
572
+ const feishuCtx = new SyncContext(sqlite, logger);
573
+ result = await syncFeishu(feishuCtx, cred.data, logger);
609
574
  try {
610
- await syncFeishuMeetings(sqlite, cred.data, logger);
575
+ await syncFeishuMeetings(feishuCtx, cred.data, logger);
611
576
  } catch {
612
577
  }
613
578
  try {
614
- await syncFeishuDocs(sqlite, cred.data, logger);
579
+ await syncFeishuDocs(feishuCtx, cred.data, logger);
615
580
  } catch {
616
581
  }
617
582
  try {
618
- await syncFeishuApprovals(sqlite, cred.data, logger);
583
+ await syncFeishuApprovals(feishuCtx, cred.data, logger);
619
584
  } catch {
620
585
  }
621
586
  break;
622
- case "github":
623
- result = await syncGitHub(sqlite, cred.data, logger);
587
+ }
588
+ case "github": {
589
+ const { SyncContext: SyncContext2 } = await import("./context-ZNI3WOB7.js");
590
+ const ghCtx = new SyncContext2(sqlite, logger);
591
+ result = await syncGitHub(ghCtx, cred.data, logger);
624
592
  break;
625
- case "gitlab":
626
- result = await syncGitLab(sqlite, cred.data, logger);
593
+ }
594
+ case "gitlab": {
595
+ const { SyncContext: GlCtx } = await import("./context-ZNI3WOB7.js");
596
+ const glCtx = new GlCtx(sqlite, logger);
597
+ result = await syncGitLab(glCtx, cred.data, logger);
627
598
  break;
628
- case "linear":
629
- result = await syncLinear(sqlite, cred.data, logger);
599
+ }
600
+ case "linear": {
601
+ const { SyncContext: LnCtx } = await import("./context-ZNI3WOB7.js");
602
+ const lnCtx = new LnCtx(sqlite, logger);
603
+ result = await syncLinear(lnCtx, cred.data, logger);
630
604
  break;
605
+ }
631
606
  default:
632
607
  return c.json({ error: `Unknown source: ${source}` }, 400);
633
608
  }
@@ -713,9 +688,26 @@ async function startDashboard(opts = {}) {
713
688
  });
714
689
  wss.on("connection", (ws) => {
715
690
  clients.add(ws);
691
+ ws.isAlive = true;
692
+ ws.on("pong", () => {
693
+ ws.isAlive = true;
694
+ });
716
695
  ws.on("close", () => clients.delete(ws));
717
696
  ws.on("error", () => clients.delete(ws));
718
697
  });
698
+ const heartbeatTimer = setInterval(() => {
699
+ for (const client of clients) {
700
+ if (client.isAlive === false) {
701
+ clients.delete(client);
702
+ client.terminate();
703
+ continue;
704
+ }
705
+ client.isAlive = false;
706
+ if (client.readyState === WebSocket.OPEN) {
707
+ client.ping();
708
+ }
709
+ }
710
+ }, 25e3);
719
711
  let lastState = getDbState(sqlite);
720
712
  const pollInterval = setInterval(() => {
721
713
  try {
@@ -737,6 +729,7 @@ async function startDashboard(opts = {}) {
737
729
  port,
738
730
  close: () => {
739
731
  clearInterval(pollInterval);
732
+ clearInterval(heartbeatTimer);
740
733
  for (const client of clients) {
741
734
  try {
742
735
  client.close();
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  DbManager
3
- } from "./chunk-XAEGXSEO.js";
3
+ } from "./chunk-74AHY7X6.js";
4
4
  import {
5
5
  readConfig,
6
6
  writeConfig
7
- } from "./chunk-JSTXMDXI.js";
7
+ } from "./chunk-FCFZCZHR.js";
8
8
  import {
9
9
  listCredentials,
10
10
  saveCredential
11
- } from "./chunk-XLYRHKG6.js";
11
+ } from "./chunk-54SD5GBF.js";
12
12
  import {
13
13
  dbPath
14
- } from "./chunk-ROIINI33.js";
14
+ } from "./chunk-4PIT2GZ4.js";
15
15
  import "./chunk-MYDK7MWB.js";
16
16
  import "./chunk-UJ4KEHGZ.js";
17
17
 
@@ -109,6 +109,18 @@ async function runSetupWizard() {
109
109
  feishu: !!(process.env["FEISHU_APP_ID"] && process.env["FEISHU_APP_SECRET"]),
110
110
  github: !!process.env["GITHUB_PERSONAL_ACCESS_TOKEN"]
111
111
  };
112
+ const COMING_SOON_SOURCES = /* @__PURE__ */ new Set([
113
+ "notion",
114
+ "jira",
115
+ "confluence",
116
+ "google-calendar",
117
+ "sentry",
118
+ "figma",
119
+ "discord",
120
+ "trello",
121
+ "asana"
122
+ ]);
123
+ const comingSoonSuffix = zh ? "\uFF08\u5373\u5C06\u63A8\u51FA\uFF09" : " (coming soon)";
112
124
  const { selectedSources } = await inquirer.prompt([{
113
125
  type: "checkbox",
114
126
  name: "selectedSources",
@@ -149,44 +161,50 @@ async function runSetupWizard() {
149
161
  value: "firebase"
150
162
  },
151
163
  {
152
- name: zh ? "Notion\uFF08\u6587\u6863\u3001\u6570\u636E\u5E93\u3001\u77E5\u8BC6\u5E93\uFF09" : "Notion (docs, databases, wikis)",
164
+ name: (zh ? "Notion\uFF08\u6587\u6863\u3001\u6570\u636E\u5E93\u3001\u77E5\u8BC6\u5E93\uFF09" : "Notion (docs, databases, wikis)") + comingSoonSuffix,
153
165
  value: "notion"
154
166
  },
155
167
  {
156
- name: zh ? "Jira\uFF08\u4EFB\u52A1\u8FFD\u8E2A\uFF09" : "Jira (issue tracking)",
168
+ name: (zh ? "Jira\uFF08\u4EFB\u52A1\u8FFD\u8E2A\uFF09" : "Jira (issue tracking)") + comingSoonSuffix,
157
169
  value: "jira"
158
170
  },
159
171
  {
160
- name: zh ? "Confluence\uFF08\u4F01\u4E1A\u6587\u6863\uFF09" : "Confluence (enterprise wiki)",
172
+ name: (zh ? "Confluence\uFF08\u4F01\u4E1A\u6587\u6863\uFF09" : "Confluence (enterprise wiki)") + comingSoonSuffix,
161
173
  value: "confluence"
162
174
  },
163
175
  {
164
- name: zh ? "Google Calendar\uFF08\u65E5\u5386\u3001\u4F1A\u8BAE\uFF09" : "Google Calendar (events, meetings)",
176
+ name: (zh ? "Google Calendar\uFF08\u65E5\u5386\u3001\u4F1A\u8BAE\uFF09" : "Google Calendar (events, meetings)") + comingSoonSuffix,
165
177
  value: "google-calendar"
166
178
  },
167
179
  {
168
- name: zh ? "Sentry\uFF08\u9519\u8BEF\u76D1\u63A7\u3001\u5D29\u6E83\u8FFD\u8E2A\uFF09" : "Sentry (error tracking, crashes)",
180
+ name: (zh ? "Sentry\uFF08\u9519\u8BEF\u76D1\u63A7\u3001\u5D29\u6E83\u8FFD\u8E2A\uFF09" : "Sentry (error tracking, crashes)") + comingSoonSuffix,
169
181
  value: "sentry"
170
182
  },
171
183
  {
172
- name: zh ? "Figma\uFF08\u8BBE\u8BA1\u6587\u4EF6\uFF09" : "Figma (design files)",
184
+ name: (zh ? "Figma\uFF08\u8BBE\u8BA1\u6587\u4EF6\uFF09" : "Figma (design files)") + comingSoonSuffix,
173
185
  value: "figma"
174
186
  },
175
187
  {
176
- name: zh ? "Discord\uFF08\u793E\u533A\u6D88\u606F\uFF09" : "Discord (community messages)",
188
+ name: (zh ? "Discord\uFF08\u793E\u533A\u6D88\u606F\uFF09" : "Discord (community messages)") + comingSoonSuffix,
177
189
  value: "discord"
178
190
  },
179
191
  {
180
- name: zh ? "Trello\uFF08\u770B\u677F\u3001\u4EFB\u52A1\u7BA1\u7406\uFF09" : "Trello (kanban boards)",
192
+ name: (zh ? "Trello\uFF08\u770B\u677F\u3001\u4EFB\u52A1\u7BA1\u7406\uFF09" : "Trello (kanban boards)") + comingSoonSuffix,
181
193
  value: "trello"
182
194
  },
183
195
  {
184
- name: zh ? "Asana\uFF08\u9879\u76EE\u7BA1\u7406\uFF09" : "Asana (project management)",
196
+ name: (zh ? "Asana\uFF08\u9879\u76EE\u7BA1\u7406\uFF09" : "Asana (project management)") + comingSoonSuffix,
185
197
  value: "asana"
186
198
  }
187
199
  ]
188
200
  }]);
189
201
  for (const key of selectedSources) {
202
+ if (COMING_SOON_SOURCES.has(key)) {
203
+ console.log(zh ? `
204
+ ${key}: \u5373\u5C06\u63A8\u51FA\uFF01\u5173\u6CE8 github.com/FluxVita/jowork \u83B7\u53D6\u66F4\u65B0\u3002` : `
205
+ ${key}: Coming soon! Follow github.com/FluxVita/jowork for updates.`);
206
+ continue;
207
+ }
190
208
  await connectSource(key, inquirer);
191
209
  }
192
210
  const connectedSources = listCredentials();
@@ -194,7 +212,7 @@ async function runSetupWizard() {
194
212
  console.log("");
195
213
  console.log(zh ? ` \u6B63\u5728\u540C\u6B65 ${connectedSources.length} \u4E2A\u6570\u636E\u6E90...` : ` Syncing ${connectedSources.length} source${connectedSources.length > 1 ? "s" : ""}...`);
196
214
  console.log("");
197
- const { runSync } = await import("./sync-7V54N62M.js");
215
+ const { runSync } = await import("./sync-SRLFR5NA.js");
198
216
  try {
199
217
  await runSync(connectedSources);
200
218
  } catch {
@@ -242,7 +260,15 @@ async function registerEngine(engine) {
242
260
  cursor: "Cursor",
243
261
  openclaw: "OpenClaw"
244
262
  };
245
- const mcpEntry = { command: "jowork", args: ["serve"] };
263
+ let mcpCommand = "jowork";
264
+ let mcpArgs = ["serve"];
265
+ try {
266
+ execSync("which jowork", { stdio: "ignore" });
267
+ } catch {
268
+ mcpCommand = "npx";
269
+ mcpArgs = ["-y", "jowork@latest", "serve"];
270
+ }
271
+ const mcpEntry = { command: mcpCommand, args: mcpArgs };
246
272
  switch (engine) {
247
273
  case "claude-code": {
248
274
  const p = join(HOME, ".claude.json");
@@ -266,7 +292,12 @@ async function registerEngine(engine) {
266
292
  const p = join(dir, "config.toml");
267
293
  let c = existsSync(p) ? readFileSync(p, "utf-8") : "";
268
294
  if (!c.includes("[mcp_servers.jowork]")) {
269
- c += '\n[mcp_servers.jowork]\ncommand = "jowork"\nargs = ["serve"]\n';
295
+ const argsToml = mcpArgs.map((a) => `"${a}"`).join(", ");
296
+ c += `
297
+ [mcp_servers.jowork]
298
+ command = "${mcpCommand}"
299
+ args = [${argsToml}]
300
+ `;
270
301
  writeFileSync(p, c);
271
302
  }
272
303
  break;
@@ -547,13 +578,18 @@ async function connectSource(source, inquirer) {
547
578
  break;
548
579
  }
549
580
  case "telegram": {
550
- console.log(zh ? " \u9700\u8981 Bot Token \u548C Chat ID\n \u521B\u5EFA\u65B9\u5F0F\uFF1A\u5728 Telegram \u4E2D\u641C\u7D22 @BotFather \u2192 /newbot" : " Requires Bot Token and Chat ID\n Create: search @BotFather in Telegram \u2192 /newbot");
551
- console.log("");
552
- const tgAnswers = await inquirer.prompt([
553
- { type: "input", name: "botToken", message: zh ? "Telegram Bot Token (123456:ABC-xxx):" : "Telegram Bot Token (123456:ABC-xxx):" },
554
- { type: "input", name: "chatId", message: zh ? "Telegram Chat ID:" : "Telegram Chat ID:" }
555
- ]);
556
- if (tgAnswers.botToken) {
581
+ let done = false;
582
+ while (!done) {
583
+ console.log(zh ? " \u9700\u8981 Bot Token \u548C Chat ID\n \u521B\u5EFA\u65B9\u5F0F\uFF1A\u5728 Telegram \u4E2D\u641C\u7D22 @BotFather \u2192 /newbot" : " Requires Bot Token and Chat ID\n Create: search @BotFather in Telegram \u2192 /newbot");
584
+ console.log("");
585
+ const tgAnswers = await inquirer.prompt([
586
+ { type: "input", name: "botToken", message: zh ? "Telegram Bot Token (123456:ABC-xxx):" : "Telegram Bot Token (123456:ABC-xxx):" },
587
+ { type: "input", name: "chatId", message: zh ? "Telegram Chat ID:" : "Telegram Chat ID:" }
588
+ ]);
589
+ if (!tgAnswers.botToken) {
590
+ done = true;
591
+ break;
592
+ }
557
593
  console.log(zh ? " \u9A8C\u8BC1\u4E2D..." : " Verifying...");
558
594
  try {
559
595
  const res = await fetch(`https://api.telegram.org/bot${tgAnswers.botToken}/getMe`);
@@ -561,25 +597,48 @@ async function connectSource(source, inquirer) {
561
597
  if (data.ok) {
562
598
  saveCredential("telegram", { type: "telegram", data: { botToken: tgAnswers.botToken, chatId: tgAnswers.chatId ?? "" }, createdAt: Date.now(), updatedAt: Date.now() });
563
599
  console.log(zh ? ` \u2713 Telegram \u5DF2\u8FDE\u63A5\uFF08Bot: @${data.result?.username}\uFF09` : ` \u2713 Telegram connected (Bot: @${data.result?.username})`);
600
+ done = true;
564
601
  } else {
565
602
  console.log(zh ? " \u2717 Telegram Bot Token \u65E0\u6548" : " \u2717 Invalid Telegram Bot Token");
603
+ if (!await askRetryOrSkip()) done = true;
566
604
  }
567
605
  } catch {
568
606
  console.log(zh ? " \u2717 \u65E0\u6CD5\u8FDE\u63A5 Telegram API" : " \u2717 Cannot reach Telegram API");
607
+ if (!await askRetryOrSkip()) done = true;
569
608
  }
570
609
  }
571
610
  break;
572
611
  }
573
612
  case "firebase": {
574
- console.log(zh ? " \u9700\u8981 Google Analytics API Key \u548C Property ID\n \u83B7\u53D6\u65B9\u5F0F\uFF1AGoogle Cloud Console \u2192 APIs & Services \u2192 Credentials" : " Requires Google Analytics API Key and Property ID\n Get it: Google Cloud Console \u2192 APIs & Services \u2192 Credentials");
575
- console.log("");
576
- const fbAnswers = await inquirer.prompt([
577
- { type: "input", name: "apiKey", message: zh ? "Firebase/GA4 API Key:" : "Firebase/GA4 API Key:" },
578
- { type: "input", name: "propertyId", message: zh ? "GA4 Property ID (\u6570\u5B57):" : "GA4 Property ID (numbers):" }
579
- ]);
580
- if (fbAnswers.apiKey && fbAnswers.propertyId) {
581
- saveCredential("firebase", { type: "firebase", data: { apiKey: fbAnswers.apiKey, projectId: fbAnswers.propertyId, propertyId: fbAnswers.propertyId }, createdAt: Date.now(), updatedAt: Date.now() });
582
- console.log(zh ? " \u2713 Firebase \u5DF2\u8FDE\u63A5" : " \u2713 Firebase connected");
613
+ let done = false;
614
+ while (!done) {
615
+ console.log(zh ? " \u9700\u8981 Google Analytics API Key \u548C Property ID\n \u83B7\u53D6\u65B9\u5F0F\uFF1AGoogle Cloud Console \u2192 APIs & Services \u2192 Credentials" : " Requires Google Analytics API Key and Property ID\n Get it: Google Cloud Console \u2192 APIs & Services \u2192 Credentials");
616
+ console.log("");
617
+ const fbAnswers = await inquirer.prompt([
618
+ { type: "input", name: "apiKey", message: zh ? "Firebase/GA4 API Key:" : "Firebase/GA4 API Key:" },
619
+ { type: "input", name: "propertyId", message: zh ? "GA4 Property ID (\u6570\u5B57):" : "GA4 Property ID (numbers):" }
620
+ ]);
621
+ if (!fbAnswers.apiKey || !fbAnswers.propertyId) {
622
+ done = true;
623
+ break;
624
+ }
625
+ console.log(zh ? " \u9A8C\u8BC1\u4E2D..." : " Verifying...");
626
+ try {
627
+ const res = await fetch(
628
+ `https://analyticsdata.googleapis.com/v1beta/properties/${fbAnswers.propertyId}/metadata?key=${fbAnswers.apiKey}`
629
+ );
630
+ if (res.ok) {
631
+ saveCredential("firebase", { type: "firebase", data: { apiKey: fbAnswers.apiKey, projectId: fbAnswers.propertyId, propertyId: fbAnswers.propertyId }, createdAt: Date.now(), updatedAt: Date.now() });
632
+ console.log(zh ? " \u2713 Firebase \u5DF2\u8FDE\u63A5\uFF08\u9A8C\u8BC1\u901A\u8FC7\uFF09" : " \u2713 Firebase connected (verified)");
633
+ done = true;
634
+ } else {
635
+ console.log(zh ? " \u2717 Firebase/GA4 \u51ED\u8BC1\u65E0\u6548" : " \u2717 Invalid Firebase/GA4 credentials");
636
+ if (!await askRetryOrSkip()) done = true;
637
+ }
638
+ } catch {
639
+ console.log(zh ? " \u2717 \u65E0\u6CD5\u8FDE\u63A5 Google Analytics API" : " \u2717 Cannot reach Google Analytics API");
640
+ if (!await askRetryOrSkip()) done = true;
641
+ }
583
642
  }
584
643
  break;
585
644
  }
@@ -0,0 +1,21 @@
1
+ import {
2
+ runSync,
3
+ syncCommand
4
+ } from "./chunk-QGHJ45PL.js";
5
+ import "./chunk-HENAABEL.js";
6
+ import "./chunk-63AMINQC.js";
7
+ import "./chunk-EYP6WMFF.js";
8
+ import "./chunk-74AHY7X6.js";
9
+ import "./chunk-54SD5GBF.js";
10
+ import "./chunk-FX6Z3QHV.js";
11
+ import "./chunk-4PIT2GZ4.js";
12
+ import "./chunk-DQW74UCN.js";
13
+ import "./chunk-RO3KK5RC.js";
14
+ import "./chunk-MYDK7MWB.js";
15
+ import "./chunk-OXWWOKC7.js";
16
+ import "./chunk-TFMF3EXE.js";
17
+ import "./chunk-UJ4KEHGZ.js";
18
+ export {
19
+ runSync,
20
+ syncCommand
21
+ };
package/dist/transport.js CHANGED
@@ -1,12 +1,14 @@
1
1
  import {
2
2
  createJoWorkMcpServer
3
- } from "./chunk-7U3SXINY.js";
4
- import "./chunk-TN327MDF.js";
3
+ } from "./chunk-ATAUWJYD.js";
4
+ import "./chunk-VX662YLA.js";
5
+ import "./chunk-54SD5GBF.js";
6
+ import "./chunk-FX6Z3QHV.js";
5
7
  import {
6
8
  dbPath
7
- } from "./chunk-ROIINI33.js";
8
- import "./chunk-JE6TOU7W.js";
9
+ } from "./chunk-4PIT2GZ4.js";
9
10
  import "./chunk-MYDK7MWB.js";
11
+ import "./chunk-TFMF3EXE.js";
10
12
  import "./chunk-UJ4KEHGZ.js";
11
13
 
12
14
  // src/mcp/transport.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jowork",
3
- "version": "0.2.4",
3
+ "version": "0.3.0",
4
4
  "description": "AI Agent Infrastructure — let AI agents truly understand your work. Connect data sources, give agents awareness and goals. Local-first, one command.",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0",