@claudeink/mcp-server 2.1.0 → 2.2.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.
Files changed (3) hide show
  1. package/dist/cli.js +462 -327
  2. package/dist/index.js +417 -284
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -28848,179 +28848,6 @@ var init_state = __esm({
28848
28848
  }
28849
28849
  });
28850
28850
 
28851
- // src/lib/logger.ts
28852
- import { appendFile, mkdir as mkdir2 } from "fs/promises";
28853
- import { join as join2 } from "path";
28854
- function setLogLevel(level) {
28855
- currentLevel = level;
28856
- }
28857
- async function log(level, scope, message) {
28858
- if (LEVELS[level] > LEVELS[currentLevel]) return;
28859
- const dir = join2(getClaudeinkDir(), "logs");
28860
- await mkdir2(dir, { recursive: true });
28861
- const date3 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
28862
- const line = `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${scope} | ${message}
28863
- `;
28864
- await appendFile(join2(dir, `mcp-${date3}.log`), line);
28865
- console.error(`[ClaudeInk] ${line.trim()}`);
28866
- }
28867
- var currentLevel, LEVELS;
28868
- var init_logger = __esm({
28869
- "src/lib/logger.ts"() {
28870
- "use strict";
28871
- init_state();
28872
- currentLevel = "INFO";
28873
- LEVELS = { ERROR: 0, WARN: 1, INFO: 2, DEBUG: 3 };
28874
- }
28875
- });
28876
-
28877
- // src/tools/sync.ts
28878
- async function sync2(input) {
28879
- if (input.workDir) setWorkDir(input.workDir);
28880
- const creds = await getCredentials();
28881
- if (!creds?.token) {
28882
- return { success: false, message: "\u672A\u6FC0\u6D3B\uFF0C\u8BF7\u5148\u4F7F\u7528 workflow.init \u6FC0\u6D3B License" };
28883
- }
28884
- return doPull(creds.token);
28885
- }
28886
- async function doPull(token) {
28887
- const config2 = await getConfig();
28888
- try {
28889
- const res = await fetch(`${config2.apiBaseUrl}/api/sync/pull`, {
28890
- headers: { Authorization: `Bearer ${token}` }
28891
- });
28892
- if (!res.ok) {
28893
- if (res.status === 404) {
28894
- return { success: true, message: "\u4E91\u7AEF\u65E0\u6570\u636E" };
28895
- }
28896
- await log("ERROR", "ink.sync", `pull failed: HTTP ${res.status}`);
28897
- return { success: false, message: `\u62C9\u53D6\u5931\u8D25: HTTP ${res.status}` };
28898
- }
28899
- await updateLastSyncAt();
28900
- await log("INFO", "ink.sync", "pull completed");
28901
- return {
28902
- success: true,
28903
- message: "\u2705 \u540C\u6B65\u5B8C\u6210"
28904
- };
28905
- } catch (err) {
28906
- return { success: false, message: `\u540C\u6B65\u5931\u8D25: ${err instanceof Error ? err.message : err}` };
28907
- }
28908
- }
28909
- async function syncPull(input) {
28910
- if (input.workDir) setWorkDir(input.workDir);
28911
- const creds = await getCredentials();
28912
- if (!creds?.token) {
28913
- return { success: false, message: "\u672A\u6FC0\u6D3B" };
28914
- }
28915
- return doPull(creds.token);
28916
- }
28917
- var syncSchema;
28918
- var init_sync = __esm({
28919
- "src/tools/sync.ts"() {
28920
- "use strict";
28921
- init_zod();
28922
- init_state();
28923
- init_logger();
28924
- syncSchema = external_exports.object({
28925
- workDir: external_exports.string().optional().describe("\u5DE5\u4F5C\u76EE\u5F55\uFF08\u9ED8\u8BA4\u4F7F\u7528\u914D\u7F6E\u4E2D\u7684 workflowDir\uFF09")
28926
- });
28927
- }
28928
- });
28929
-
28930
- // src/tools/workflow.ts
28931
- import { mkdir as mkdir3, access, unlink } from "fs/promises";
28932
- import { join as join3 } from "path";
28933
- async function workflowInit(input) {
28934
- const cwd = input.workDir;
28935
- const results = [];
28936
- try {
28937
- setWorkDir(cwd);
28938
- const claudeinkDir = join3(cwd, ".claudeink");
28939
- await mkdir3(join3(claudeinkDir, "knowledge"), { recursive: true });
28940
- results.push("\u2705 \u77E5\u8BC6\u5E93\u76EE\u5F55\u5DF2\u521B\u5EFA");
28941
- const state = await readState();
28942
- state.config.workflowDir = cwd;
28943
- const oldCredsPath = join3(claudeinkDir, "credentials.json");
28944
- try {
28945
- await access(oldCredsPath);
28946
- await unlink(oldCredsPath);
28947
- results.push("\u{1F9F9} \u5DF2\u6E05\u7406\u65E7\u7248 credentials.json");
28948
- } catch {
28949
- }
28950
- let activated = false;
28951
- if (input.licenseKey) {
28952
- try {
28953
- const res = await fetch(`${DEFAULT_API_BASE_URL}/api/auth/activate`, {
28954
- method: "POST",
28955
- headers: { "Content-Type": "application/json" },
28956
- body: JSON.stringify({ key: input.licenseKey })
28957
- });
28958
- const data = await res.json();
28959
- if (data.userId) {
28960
- state.credentials = {
28961
- licenseKey: input.licenseKey,
28962
- token: data.token,
28963
- userId: data.userId,
28964
- plan: data.plan,
28965
- expiresAt: data.expiresAt
28966
- };
28967
- results.push(`\u2705 License \u6FC0\u6D3B\u6210\u529F\uFF08\u5957\u9910: ${data.plan}\uFF09`);
28968
- activated = true;
28969
- } else {
28970
- results.push(`\u26A0\uFE0F License \u6FC0\u6D3B\u5931\u8D25: ${JSON.stringify(data)}`);
28971
- }
28972
- } catch (err) {
28973
- results.push(`\u26A0\uFE0F \u6FC0\u6D3B\u7F51\u7EDC\u9519\u8BEF: ${err instanceof Error ? err.message : err}`);
28974
- }
28975
- }
28976
- await writeState(state);
28977
- results.push("\u2705 state.json");
28978
- if (state.credentials?.token) {
28979
- try {
28980
- const pullResult = await syncPull({ workDir: cwd });
28981
- if (pullResult.success) {
28982
- results.push("\u2705 \u5DF2\u4ECE\u4E91\u7AEF\u540C\u6B65\u6570\u636E");
28983
- } else {
28984
- results.push("\u2139\uFE0F \u4E91\u7AEF\u65E0\u5DF2\u6709\u6570\u636E");
28985
- }
28986
- } catch {
28987
- results.push("\u2139\uFE0F \u4E91\u7AEF\u540C\u6B65\u8DF3\u8FC7");
28988
- }
28989
- }
28990
- return {
28991
- success: true,
28992
- message: [
28993
- "\u{1F389} ClaudeInk \u77E5\u8BC6\u5E93\u521D\u59CB\u5316\u5B8C\u6210\uFF01",
28994
- "",
28995
- ...results,
28996
- "",
28997
- "\u{1F3AF} \u4E0B\u4E00\u6B65\uFF1A",
28998
- "1. \u5728\u5BF9\u8BDD\u4E2D\u8BF4\u300C\u5E2E\u6211\u5B58\u4E00\u4E0B\u300D\u4FDD\u5B58\u6709\u4EF7\u503C\u5185\u5BB9",
28999
- "2. \u7528\u300C\u627E\u4E00\u4E0B\u5173\u4E8E XX \u7684\u300D\u68C0\u7D22\u77E5\u8BC6\u5E93"
29000
- ].join("\n")
29001
- };
29002
- } catch (err) {
29003
- return {
29004
- success: false,
29005
- message: `\u521D\u59CB\u5316\u5931\u8D25: ${err instanceof Error ? err.message : err}`
29006
- };
29007
- }
29008
- }
29009
- var DEFAULT_API_BASE_URL, workflowInitSchema;
29010
- var init_workflow = __esm({
29011
- "src/tools/workflow.ts"() {
29012
- "use strict";
29013
- init_zod();
29014
- init_state();
29015
- init_sync();
29016
- DEFAULT_API_BASE_URL = "https://app.claudeink.com";
29017
- workflowInitSchema = external_exports.object({
29018
- workDir: external_exports.string().describe("\u5DE5\u4F5C\u6D41\u521D\u59CB\u5316\u76EE\u6807\u76EE\u5F55\uFF08\u7EDD\u5BF9\u8DEF\u5F84\uFF09"),
29019
- licenseKey: external_exports.string().optional().describe("License Key\uFF08\u53EF\u9009\uFF0C\u4F20\u5165\u5219\u81EA\u52A8\u6FC0\u6D3B\uFF09")
29020
- });
29021
- }
29022
- });
29023
-
29024
28851
  // ../node_modules/kind-of/index.js
29025
28852
  var require_kind_of = __commonJS({
29026
28853
  "../node_modules/kind-of/index.js"(exports2, module2) {
@@ -32506,8 +32333,8 @@ var require_gray_matter = __commonJS({
32506
32333
  });
32507
32334
 
32508
32335
  // src/lib/knowledge.ts
32509
- import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir4, unlink as unlink2 } from "fs/promises";
32510
- import { join as join4 } from "path";
32336
+ import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, unlink } from "fs/promises";
32337
+ import { join as join2 } from "path";
32511
32338
  function withIndexLock(fn) {
32512
32339
  const prev = _lockPromise;
32513
32340
  let resolve;
@@ -32516,11 +32343,11 @@ function withIndexLock(fn) {
32516
32343
  });
32517
32344
  return prev.then(fn).finally(() => resolve());
32518
32345
  }
32519
- function getKnowledgeDir() {
32520
- return join4(getWorkDir(), ".claudeink", "knowledge");
32346
+ function getStoreDir(store = "knowledge") {
32347
+ return join2(getWorkDir(), ".claudeink", store);
32521
32348
  }
32522
- function getIndexPath() {
32523
- return join4(getWorkDir(), ".claudeink", "knowledge", "index.json");
32349
+ function getIndexPath(store = "knowledge") {
32350
+ return join2(getWorkDir(), ".claudeink", store, "index.json");
32524
32351
  }
32525
32352
  async function generateIdInternal(index) {
32526
32353
  const now = /* @__PURE__ */ new Date();
@@ -32542,28 +32369,28 @@ function toSlug(title) {
32542
32369
  function generatePreview(content, maxLen = 200) {
32543
32370
  return content.replace(/^#+\s.+$/gm, "").replace(/\n+/g, " ").trim().slice(0, maxLen);
32544
32371
  }
32545
- async function readIndex() {
32372
+ async function readIndex(store = "knowledge") {
32546
32373
  try {
32547
- const raw = await readFile2(getIndexPath(), "utf-8");
32374
+ const raw = await readFile2(getIndexPath(store), "utf-8");
32548
32375
  return JSON.parse(raw);
32549
32376
  } catch {
32550
32377
  return { entries: {}, updated_at: (/* @__PURE__ */ new Date()).toISOString() };
32551
32378
  }
32552
32379
  }
32553
- async function saveIndex(index) {
32380
+ async function saveIndex(index, store = "knowledge") {
32554
32381
  index.updated_at = (/* @__PURE__ */ new Date()).toISOString();
32555
- const dir = getKnowledgeDir();
32556
- await mkdir4(dir, { recursive: true });
32557
- await writeFile2(getIndexPath(), JSON.stringify(index, null, 2), "utf-8");
32382
+ const dir = getStoreDir(store);
32383
+ await mkdir2(dir, { recursive: true });
32384
+ await writeFile2(getIndexPath(store), JSON.stringify(index, null, 2), "utf-8");
32558
32385
  }
32559
- async function writeKnowledgeFile(meta, content) {
32386
+ async function writeKnowledgeFile(meta, content, store = "knowledge") {
32560
32387
  const now = /* @__PURE__ */ new Date();
32561
32388
  const monthDir = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}`;
32562
- const dir = join4(getKnowledgeDir(), monthDir);
32563
- await mkdir4(dir, { recursive: true });
32389
+ const dir = join2(getStoreDir(store), monthDir);
32390
+ await mkdir2(dir, { recursive: true });
32564
32391
  const slug = toSlug(meta.title) || meta.id;
32565
32392
  const filename = `${now.toISOString().slice(0, 10)}-${slug}.md`;
32566
- const filePath = join4(dir, filename);
32393
+ const filePath = join2(dir, filename);
32567
32394
  const frontmatter = {
32568
32395
  id: meta.id,
32569
32396
  title: meta.title,
@@ -32576,13 +32403,13 @@ async function writeKnowledgeFile(meta, content) {
32576
32403
  if (meta.url) frontmatter.url = meta.url;
32577
32404
  const output = import_gray_matter.default.stringify(content, frontmatter);
32578
32405
  await writeFile2(filePath, output, "utf-8");
32579
- return join4(monthDir, filename);
32406
+ return join2(monthDir, filename);
32580
32407
  }
32581
- async function readKnowledgeFile(id) {
32582
- const index = await readIndex();
32408
+ async function readKnowledgeFile(id, store = "knowledge") {
32409
+ const index = await readIndex(store);
32583
32410
  const entry = index.entries[id];
32584
32411
  if (!entry) return null;
32585
- const filePath = join4(getKnowledgeDir(), entry.file_path);
32412
+ const filePath = join2(getStoreDir(store), entry.file_path);
32586
32413
  try {
32587
32414
  const raw = await readFile2(filePath, "utf-8");
32588
32415
  const { data, content } = (0, import_gray_matter.default)(raw);
@@ -32596,8 +32423,9 @@ async function readKnowledgeFile(id) {
32596
32423
  }
32597
32424
  }
32598
32425
  async function saveKnowledge(params) {
32426
+ const store = params.store || "knowledge";
32599
32427
  return withIndexLock(async () => {
32600
- const index = await readIndex();
32428
+ const index = await readIndex(store);
32601
32429
  const id = await generateIdInternal(index);
32602
32430
  const now = (/* @__PURE__ */ new Date()).toISOString();
32603
32431
  const meta = {
@@ -32610,7 +32438,7 @@ async function saveKnowledge(params) {
32610
32438
  created_at: now,
32611
32439
  updated_at: now
32612
32440
  };
32613
- const relativePath = await writeKnowledgeFile(meta, params.content);
32441
+ const relativePath = await writeKnowledgeFile(meta, params.content, store);
32614
32442
  index.entries[id] = {
32615
32443
  id,
32616
32444
  title: params.title,
@@ -32622,13 +32450,13 @@ async function saveKnowledge(params) {
32622
32450
  created_at: now,
32623
32451
  updated_at: now
32624
32452
  };
32625
- await saveIndex(index);
32453
+ await saveIndex(index, store);
32626
32454
  return { id, filePath: relativePath };
32627
32455
  });
32628
32456
  }
32629
- async function updateKnowledgeFile(id, updates) {
32457
+ async function updateKnowledgeFile(id, updates, store = "knowledge") {
32630
32458
  return withIndexLock(async () => {
32631
- const file = await readKnowledgeFile(id);
32459
+ const file = await readKnowledgeFile(id, store);
32632
32460
  if (!file) return null;
32633
32461
  const now = (/* @__PURE__ */ new Date()).toISOString();
32634
32462
  const meta = { ...file.meta };
@@ -32649,7 +32477,7 @@ async function updateKnowledgeFile(id, updates) {
32649
32477
  if (meta.url) frontmatter.url = meta.url;
32650
32478
  const output = import_gray_matter.default.stringify(content, frontmatter);
32651
32479
  await writeFile2(file.filePath, output, "utf-8");
32652
- const index = await readIndex();
32480
+ const index = await readIndex(store);
32653
32481
  const entry = index.entries[id];
32654
32482
  if (entry) {
32655
32483
  entry.title = meta.title;
@@ -32657,23 +32485,23 @@ async function updateKnowledgeFile(id, updates) {
32657
32485
  entry.category = meta.category;
32658
32486
  entry.preview = generatePreview(content);
32659
32487
  entry.updated_at = now;
32660
- await saveIndex(index);
32488
+ await saveIndex(index, store);
32661
32489
  }
32662
32490
  return { meta, content, filePath: file.filePath };
32663
32491
  });
32664
32492
  }
32665
- async function deleteKnowledgeFile(id) {
32493
+ async function deleteKnowledgeFile(id, store = "knowledge") {
32666
32494
  return withIndexLock(async () => {
32667
- const index = await readIndex();
32495
+ const index = await readIndex(store);
32668
32496
  const entry = index.entries[id];
32669
32497
  if (!entry) return false;
32670
- const filePath = join4(getKnowledgeDir(), entry.file_path);
32498
+ const filePath = join2(getStoreDir(store), entry.file_path);
32671
32499
  try {
32672
- await unlink2(filePath);
32500
+ await unlink(filePath);
32673
32501
  } catch {
32674
32502
  }
32675
32503
  delete index.entries[id];
32676
- await saveIndex(index);
32504
+ await saveIndex(index, store);
32677
32505
  return true;
32678
32506
  });
32679
32507
  }
@@ -32686,16 +32514,16 @@ function getAllTags(index) {
32686
32514
  }
32687
32515
  return Object.entries(tagCounts).map(([name, count]) => ({ name, count })).sort((a, b) => b.count - a.count);
32688
32516
  }
32689
- async function renameTag(oldTag, newTag) {
32517
+ async function renameTag(oldTag, newTag, store = "knowledge") {
32690
32518
  return withIndexLock(async () => {
32691
- const index = await readIndex();
32519
+ const index = await readIndex(store);
32692
32520
  let count = 0;
32693
32521
  for (const entry of Object.values(index.entries)) {
32694
32522
  const idx = entry.tags.indexOf(oldTag);
32695
32523
  if (idx !== -1) {
32696
32524
  entry.tags[idx] = newTag;
32697
32525
  count++;
32698
- const filePath = join4(getKnowledgeDir(), entry.file_path);
32526
+ const filePath = join2(getStoreDir(store), entry.file_path);
32699
32527
  try {
32700
32528
  const raw = await readFile2(filePath, "utf-8");
32701
32529
  const { data, content } = (0, import_gray_matter.default)(raw);
@@ -32712,14 +32540,14 @@ async function renameTag(oldTag, newTag) {
32712
32540
  }
32713
32541
  }
32714
32542
  if (count > 0) {
32715
- await saveIndex(index);
32543
+ await saveIndex(index, store);
32716
32544
  }
32717
32545
  return count;
32718
32546
  });
32719
32547
  }
32720
- async function mergeTags(sourceTags, targetTag) {
32548
+ async function mergeTags(sourceTags, targetTag, store = "knowledge") {
32721
32549
  return withIndexLock(async () => {
32722
- const index = await readIndex();
32550
+ const index = await readIndex(store);
32723
32551
  let count = 0;
32724
32552
  for (const entry of Object.values(index.entries)) {
32725
32553
  const hasSource = entry.tags.some((t) => sourceTags.includes(t));
@@ -32730,7 +32558,7 @@ async function mergeTags(sourceTags, targetTag) {
32730
32558
  }
32731
32559
  entry.tags = newTags;
32732
32560
  count++;
32733
- const filePath = join4(getKnowledgeDir(), entry.file_path);
32561
+ const filePath = join2(getStoreDir(store), entry.file_path);
32734
32562
  try {
32735
32563
  const raw = await readFile2(filePath, "utf-8");
32736
32564
  const { data, content } = (0, import_gray_matter.default)(raw);
@@ -32742,7 +32570,7 @@ async function mergeTags(sourceTags, targetTag) {
32742
32570
  }
32743
32571
  }
32744
32572
  if (count > 0) {
32745
- await saveIndex(index);
32573
+ await saveIndex(index, store);
32746
32574
  }
32747
32575
  return count;
32748
32576
  });
@@ -32757,10 +32585,272 @@ var init_knowledge = __esm({
32757
32585
  }
32758
32586
  });
32759
32587
 
32588
+ // src/lib/logger.ts
32589
+ import { appendFile, mkdir as mkdir3 } from "fs/promises";
32590
+ import { join as join3 } from "path";
32591
+ function setLogLevel(level) {
32592
+ currentLevel = level;
32593
+ }
32594
+ async function log(level, scope, message) {
32595
+ if (LEVELS[level] > LEVELS[currentLevel]) return;
32596
+ const dir = join3(getClaudeinkDir(), "logs");
32597
+ await mkdir3(dir, { recursive: true });
32598
+ const date3 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
32599
+ const line = `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${scope} | ${message}
32600
+ `;
32601
+ await appendFile(join3(dir, `mcp-${date3}.log`), line);
32602
+ console.error(`[ClaudeInk] ${line.trim()}`);
32603
+ }
32604
+ var currentLevel, LEVELS;
32605
+ var init_logger = __esm({
32606
+ "src/lib/logger.ts"() {
32607
+ "use strict";
32608
+ init_state();
32609
+ currentLevel = "INFO";
32610
+ LEVELS = { ERROR: 0, WARN: 1, INFO: 2, DEBUG: 3 };
32611
+ }
32612
+ });
32613
+
32614
+ // src/tools/sync.ts
32615
+ import { writeFile as writeFile3, mkdir as mkdir4 } from "fs/promises";
32616
+ import { join as join4 } from "path";
32617
+ async function sync2(input) {
32618
+ if (input.workDir) setWorkDir(input.workDir);
32619
+ const creds = await getCredentials();
32620
+ if (!creds?.token) {
32621
+ return { success: false, message: "\u672A\u6FC0\u6D3B\uFF0C\u8BF7\u5148\u4F7F\u7528 ink.init \u6FC0\u6D3B License" };
32622
+ }
32623
+ return doPull(creds.token);
32624
+ }
32625
+ async function doPull(token) {
32626
+ const config2 = await getConfig();
32627
+ try {
32628
+ const res = await fetch(`${config2.apiBaseUrl}/api/sync/pull`, {
32629
+ headers: { Authorization: `Bearer ${token}` }
32630
+ });
32631
+ if (!res.ok) {
32632
+ if (res.status === 404) {
32633
+ return { success: true, message: "\u4E91\u7AEF\u65E0\u6570\u636E" };
32634
+ }
32635
+ await log("ERROR", "ink.sync", `pull failed: HTTP ${res.status}`);
32636
+ return { success: false, message: `\u62C9\u53D6\u5931\u8D25: HTTP ${res.status}` };
32637
+ }
32638
+ const data = await res.json();
32639
+ const results = [];
32640
+ if (data.configs) {
32641
+ const crawlerConfig = data.configs.find((c) => c.type === "crawler" && c.name === "config");
32642
+ if (crawlerConfig?.content) {
32643
+ try {
32644
+ const sources = JSON.parse(crawlerConfig.content);
32645
+ const crawlerDir = join4(config2.workflowDir || getWorkDir(), "tools", "crawler");
32646
+ await mkdir4(crawlerDir, { recursive: true });
32647
+ await writeFile3(join4(crawlerDir, "config.json"), JSON.stringify({ sources }, null, 2));
32648
+ results.push(`\u8BA2\u9605\u6E90: ${sources.length} \u4E2A`);
32649
+ } catch {
32650
+ }
32651
+ }
32652
+ }
32653
+ if (data.sources && Object.keys(data.sources).length > 0) {
32654
+ const index = await readIndex();
32655
+ let added = 0;
32656
+ for (const [localId, meta] of Object.entries(data.sources)) {
32657
+ if (!index.entries[localId]) {
32658
+ const entry = {
32659
+ id: localId,
32660
+ title: meta.title || "",
32661
+ tags: meta.tags || [],
32662
+ category: "reference",
32663
+ source_type: "url",
32664
+ preview: "",
32665
+ file_path: "",
32666
+ created_at: meta.publishedAt || (/* @__PURE__ */ new Date()).toISOString(),
32667
+ updated_at: meta.updatedAt || (/* @__PURE__ */ new Date()).toISOString()
32668
+ };
32669
+ index.entries[localId] = entry;
32670
+ added++;
32671
+ }
32672
+ }
32673
+ if (added > 0) {
32674
+ index.updated_at = (/* @__PURE__ */ new Date()).toISOString();
32675
+ const knowledgeDir = join4(getWorkDir(), ".claudeink", "knowledge");
32676
+ await mkdir4(knowledgeDir, { recursive: true });
32677
+ await writeFile3(join4(knowledgeDir, "index.json"), JSON.stringify(index, null, 2));
32678
+ results.push(`\u7D20\u6750\u7D22\u5F15: +${added} \u6761\uFF08\u5171 ${Object.keys(index.entries).length} \u6761\uFF09`);
32679
+ } else {
32680
+ results.push(`\u7D20\u6750\u7D22\u5F15: ${Object.keys(index.entries).length} \u6761\uFF08\u5DF2\u540C\u6B65\uFF09`);
32681
+ }
32682
+ }
32683
+ const draftCount = data.drafts ? Object.keys(data.drafts).length : 0;
32684
+ const pubCount = data.published ? Object.keys(data.published).length : 0;
32685
+ if (draftCount > 0 || pubCount > 0) {
32686
+ results.push(`\u8349\u7A3F: ${draftCount} \u7BC7, \u5DF2\u53D1\u5E03: ${pubCount} \u7BC7`);
32687
+ }
32688
+ await updateLastSyncAt();
32689
+ await log("INFO", "ink.sync", `pull completed: ${results.join(", ")}`);
32690
+ return {
32691
+ success: true,
32692
+ message: results.length > 0 ? `\u2705 \u540C\u6B65\u5B8C\u6210
32693
+ ${results.join("\n")}` : "\u2705 \u540C\u6B65\u5B8C\u6210\uFF08\u4E91\u7AEF\u65E0\u65B0\u6570\u636E\uFF09"
32694
+ };
32695
+ } catch (err) {
32696
+ return { success: false, message: `\u540C\u6B65\u5931\u8D25: ${err instanceof Error ? err.message : err}` };
32697
+ }
32698
+ }
32699
+ async function syncPull(input) {
32700
+ if (input.workDir) setWorkDir(input.workDir);
32701
+ const creds = await getCredentials();
32702
+ if (!creds?.token) {
32703
+ return { success: false, message: "\u672A\u6FC0\u6D3B" };
32704
+ }
32705
+ return doPull(creds.token);
32706
+ }
32707
+ var syncSchema;
32708
+ var init_sync = __esm({
32709
+ "src/tools/sync.ts"() {
32710
+ "use strict";
32711
+ init_zod();
32712
+ init_state();
32713
+ init_knowledge();
32714
+ init_logger();
32715
+ syncSchema = external_exports.object({
32716
+ workDir: external_exports.string().optional().describe("\u5DE5\u4F5C\u76EE\u5F55\uFF08\u9ED8\u8BA4\u4F7F\u7528\u914D\u7F6E\u4E2D\u7684 workflowDir\uFF09")
32717
+ });
32718
+ }
32719
+ });
32720
+
32721
+ // src/tools/workflow.ts
32722
+ import { mkdir as mkdir5, access, unlink as unlink2 } from "fs/promises";
32723
+ import { join as join5 } from "path";
32724
+ async function workflowInit(input) {
32725
+ const cwd = input.workDir;
32726
+ const results = [];
32727
+ try {
32728
+ setWorkDir(cwd);
32729
+ const claudeinkDir = join5(cwd, ".claudeink");
32730
+ await mkdir5(join5(claudeinkDir, "knowledge"), { recursive: true });
32731
+ results.push("\u2705 \u77E5\u8BC6\u5E93\u76EE\u5F55\u5DF2\u521B\u5EFA");
32732
+ const state = await readState();
32733
+ state.config.workflowDir = cwd;
32734
+ const oldCredsPath = join5(claudeinkDir, "credentials.json");
32735
+ try {
32736
+ await access(oldCredsPath);
32737
+ await unlink2(oldCredsPath);
32738
+ results.push("\u{1F9F9} \u5DF2\u6E05\u7406\u65E7\u7248 credentials.json");
32739
+ } catch {
32740
+ }
32741
+ let activated = false;
32742
+ if (input.licenseKey) {
32743
+ try {
32744
+ const res = await fetch(`${DEFAULT_API_BASE_URL}/api/auth/activate`, {
32745
+ method: "POST",
32746
+ headers: { "Content-Type": "application/json" },
32747
+ body: JSON.stringify({ key: input.licenseKey })
32748
+ });
32749
+ const data = await res.json();
32750
+ if (data.userId) {
32751
+ state.credentials = {
32752
+ licenseKey: input.licenseKey,
32753
+ token: data.token,
32754
+ userId: data.userId,
32755
+ plan: data.plan,
32756
+ expiresAt: data.expiresAt
32757
+ };
32758
+ results.push(`\u2705 License \u6FC0\u6D3B\u6210\u529F\uFF08\u5957\u9910: ${data.plan}\uFF09`);
32759
+ activated = true;
32760
+ } else {
32761
+ results.push(`\u26A0\uFE0F License \u6FC0\u6D3B\u5931\u8D25: ${JSON.stringify(data)}`);
32762
+ }
32763
+ } catch (err) {
32764
+ results.push(`\u26A0\uFE0F \u6FC0\u6D3B\u7F51\u7EDC\u9519\u8BEF: ${err instanceof Error ? err.message : err}`);
32765
+ }
32766
+ }
32767
+ await writeState(state);
32768
+ results.push("\u2705 state.json");
32769
+ if (state.credentials?.token) {
32770
+ try {
32771
+ const pullResult = await syncPull({ workDir: cwd });
32772
+ if (pullResult.success) {
32773
+ results.push("\u2705 \u5DF2\u4ECE\u4E91\u7AEF\u540C\u6B65\u6570\u636E");
32774
+ } else {
32775
+ results.push("\u2139\uFE0F \u4E91\u7AEF\u65E0\u5DF2\u6709\u6570\u636E");
32776
+ }
32777
+ } catch {
32778
+ results.push("\u2139\uFE0F \u4E91\u7AEF\u540C\u6B65\u8DF3\u8FC7");
32779
+ }
32780
+ }
32781
+ return {
32782
+ success: true,
32783
+ message: [
32784
+ "\u{1F389} ClaudeInk \u77E5\u8BC6\u5E93\u521D\u59CB\u5316\u5B8C\u6210\uFF01",
32785
+ "",
32786
+ ...results,
32787
+ "",
32788
+ "\u{1F3AF} \u4E0B\u4E00\u6B65\uFF1A",
32789
+ "1. \u5728\u5BF9\u8BDD\u4E2D\u8BF4\u300C\u5E2E\u6211\u5B58\u4E00\u4E0B\u300D\u4FDD\u5B58\u6709\u4EF7\u503C\u5185\u5BB9",
32790
+ "2. \u7528\u300C\u627E\u4E00\u4E0B\u5173\u4E8E XX \u7684\u300D\u68C0\u7D22\u77E5\u8BC6\u5E93"
32791
+ ].join("\n")
32792
+ };
32793
+ } catch (err) {
32794
+ return {
32795
+ success: false,
32796
+ message: `\u521D\u59CB\u5316\u5931\u8D25: ${err instanceof Error ? err.message : err}`
32797
+ };
32798
+ }
32799
+ }
32800
+ var DEFAULT_API_BASE_URL, workflowInitSchema;
32801
+ var init_workflow = __esm({
32802
+ "src/tools/workflow.ts"() {
32803
+ "use strict";
32804
+ init_zod();
32805
+ init_state();
32806
+ init_sync();
32807
+ DEFAULT_API_BASE_URL = "https://app.claudeink.com";
32808
+ workflowInitSchema = external_exports.object({
32809
+ workDir: external_exports.string().describe("\u5DE5\u4F5C\u6D41\u521D\u59CB\u5316\u76EE\u6807\u76EE\u5F55\uFF08\u7EDD\u5BF9\u8DEF\u5F84\uFF09"),
32810
+ licenseKey: external_exports.string().optional().describe("License Key\uFF08\u53EF\u9009\uFF0C\u4F20\u5165\u5219\u81EA\u52A8\u6FC0\u6D3B\uFF09")
32811
+ });
32812
+ }
32813
+ });
32814
+
32815
+ // src/lib/push.ts
32816
+ function fireAndForgetPush(payload) {
32817
+ doPush(payload).catch(() => {
32818
+ });
32819
+ }
32820
+ async function doPush(partial2) {
32821
+ const creds = await getCredentials();
32822
+ if (!creds?.token) return;
32823
+ const config2 = await getConfig();
32824
+ const payload = {
32825
+ knowledge: partial2.knowledge || [],
32826
+ crawlerSources: partial2.crawlerSources || []
32827
+ };
32828
+ await log("DEBUG", "push", `payload: ${partial2.knowledge?.length || 0} knowledge, ${partial2.crawlerSources?.length || 0} sources`);
32829
+ try {
32830
+ await fetch(`${config2.apiBaseUrl}/api/sync/batch`, {
32831
+ method: "POST",
32832
+ headers: {
32833
+ "Content-Type": "application/json",
32834
+ Authorization: `Bearer ${creds.token}`
32835
+ },
32836
+ body: JSON.stringify(payload)
32837
+ });
32838
+ } catch (err) {
32839
+ await log("WARN", "push", `failed: ${err instanceof Error ? err.message : err}`);
32840
+ }
32841
+ }
32842
+ var init_push = __esm({
32843
+ "src/lib/push.ts"() {
32844
+ "use strict";
32845
+ init_state();
32846
+ init_logger();
32847
+ }
32848
+ });
32849
+
32760
32850
  // src/tools/ink.ts
32761
32851
  import { readFile as readFile3 } from "fs/promises";
32762
32852
  import { extname } from "path";
32763
- async function inkWrite(input) {
32853
+ async function inkSave(input) {
32764
32854
  try {
32765
32855
  let localId;
32766
32856
  if (input.id) {
@@ -32769,9 +32859,9 @@ async function inkWrite(input) {
32769
32859
  content: input.content,
32770
32860
  tags: input.tags,
32771
32861
  category: input.category
32772
- });
32862
+ }, "knowledge");
32773
32863
  if (!result) {
32774
- return { success: false, message: `\u672A\u627E\u5230 ID \u4E3A ${input.id} \u7684\u672C\u5730\u6761\u76EE` };
32864
+ return { success: false, message: `\u672A\u627E\u5230 ID \u4E3A ${input.id} \u7684\u7D20\u6750` };
32775
32865
  }
32776
32866
  localId = input.id;
32777
32867
  } else {
@@ -32781,16 +32871,70 @@ async function inkWrite(input) {
32781
32871
  tags: input.tags,
32782
32872
  category: input.category,
32783
32873
  source_type: input.source_type,
32784
- url: input.url
32874
+ url: input.url,
32875
+ store: "knowledge"
32876
+ });
32877
+ localId = id;
32878
+ }
32879
+ const creds = await getCredentials();
32880
+ if (creds?.token) {
32881
+ const now = (/* @__PURE__ */ new Date()).toISOString();
32882
+ fireAndForgetPush({
32883
+ knowledge: [{
32884
+ id: localId,
32885
+ title: input.title,
32886
+ tags: input.tags || [],
32887
+ category: input.category || "reference",
32888
+ source_type: input.source_type || "conversation",
32889
+ url: input.url,
32890
+ created_at: now,
32891
+ updated_at: now
32892
+ }],
32893
+ crawlerSources: []
32894
+ });
32895
+ }
32896
+ await log("INFO", "ink.save", `saved source id=${localId} title="${input.title}"`);
32897
+ return {
32898
+ success: true,
32899
+ message: `\u5DF2\u4FDD\u5B58\u7D20\u6750\u300C${input.title}\u300D\u5230\u672C\u5730\u77E5\u8BC6\u5E93` + (creds?.token ? "\uFF08\u5143\u6570\u636E\u5DF2\u63A8\u4E91\u7AEF\uFF09" : "\uFF08\u672A\u767B\u5F55\uFF0C\u8DF3\u8FC7\u4E91\u7AEF\u540C\u6B65\uFF09"),
32900
+ data: { id: localId }
32901
+ };
32902
+ } catch (err) {
32903
+ await log("ERROR", "ink.save", `failed: ${err.message}`);
32904
+ return { success: false, message: `\u4FDD\u5B58\u7D20\u6750\u5931\u8D25: ${err.message}` };
32905
+ }
32906
+ }
32907
+ async function inkWrite(input) {
32908
+ try {
32909
+ let localId;
32910
+ if (input.id) {
32911
+ const result = await updateKnowledgeFile(input.id, {
32912
+ title: input.title,
32913
+ content: input.content,
32914
+ tags: input.tags,
32915
+ category: input.category
32916
+ }, "drafts");
32917
+ if (!result) {
32918
+ return { success: false, message: `\u672A\u627E\u5230 ID \u4E3A ${input.id} \u7684\u8349\u7A3F` };
32919
+ }
32920
+ localId = input.id;
32921
+ } else {
32922
+ const { id } = await saveKnowledge({
32923
+ content: input.content,
32924
+ title: input.title,
32925
+ tags: input.tags,
32926
+ category: input.category,
32927
+ source_type: "conversation",
32928
+ store: "drafts"
32785
32929
  });
32786
32930
  localId = id;
32787
32931
  }
32788
32932
  const creds = await getCredentials();
32789
32933
  if (!creds?.token) {
32790
- await log("INFO", "ink.write", `saved locally id=${localId} title="${input.title}" (no cloud auth)`);
32934
+ await log("INFO", "ink.write", `saved draft locally id=${localId} title="${input.title}" (no cloud auth)`);
32791
32935
  return {
32792
32936
  success: true,
32793
- message: `\u5DF2\u4FDD\u5B58\u300C${input.title}\u300D\u5230\u672C\u5730\uFF08\u672A\u767B\u5F55\uFF0C\u8DF3\u8FC7\u4E91\u7AEF\u540C\u6B65\uFF09`,
32937
+ message: `\u5DF2\u4FDD\u5B58\u8349\u7A3F\u300C${input.title}\u300D\u5230\u672C\u5730\uFF08\u672A\u767B\u5F55\uFF0C\u8DF3\u8FC7\u4E91\u7AEF\u540C\u6B65\uFF09`,
32794
32938
  data: { id: localId }
32795
32939
  };
32796
32940
  }
@@ -32812,51 +32956,64 @@ async function inkWrite(input) {
32812
32956
  }
32813
32957
  const slug = `${Date.now().toString(36)}-${input.title.toLowerCase().replace(/[^a-z0-9\u4e00-\u9fff]+/g, "-").replace(/^-|-$/g, "").slice(0, 60)}`;
32814
32958
  const excerpt = input.excerpt || input.content.replace(/^#+\s.+$/gm, "").replace(/\n+/g, " ").trim().slice(0, 200);
32815
- const res = await fetch(`${config2.apiBaseUrl}/api/blog/manage`, {
32816
- method: "POST",
32817
- headers: {
32818
- "Content-Type": "application/json",
32819
- Authorization: `Bearer ${creds.token}`
32820
- },
32821
- body: JSON.stringify({
32822
- title: input.title,
32823
- slug,
32824
- content: input.content,
32825
- cover_url: coverUrl,
32826
- tags: input.tags,
32827
- category: input.category,
32828
- excerpt,
32829
- source_type: input.source_type,
32830
- url: input.url,
32831
- source_ids: input.source_ids,
32832
- local_id: localId
32833
- })
32834
- });
32835
- if (!res.ok) {
32836
- const err = await res.text();
32837
- await log("ERROR", "ink.write", `cloud save failed: ${err}`);
32959
+ try {
32960
+ const controller = new AbortController();
32961
+ const timeout = setTimeout(() => controller.abort(), 1e4);
32962
+ const res = await fetch(`${config2.apiBaseUrl}/api/blog/manage`, {
32963
+ method: "POST",
32964
+ signal: controller.signal,
32965
+ headers: {
32966
+ "Content-Type": "application/json",
32967
+ Authorization: `Bearer ${creds.token}`
32968
+ },
32969
+ body: JSON.stringify({
32970
+ title: input.title,
32971
+ slug,
32972
+ content: input.content,
32973
+ cover_url: coverUrl,
32974
+ tags: input.tags,
32975
+ category: input.category,
32976
+ excerpt,
32977
+ source_type: "conversation",
32978
+ source_ids: input.source_ids,
32979
+ local_id: localId
32980
+ })
32981
+ });
32982
+ clearTimeout(timeout);
32983
+ if (!res.ok) {
32984
+ const err = await res.text();
32985
+ await log("ERROR", "ink.write", `cloud save failed: ${err}`);
32986
+ return {
32987
+ success: true,
32988
+ message: `\u5DF2\u4FDD\u5B58\u8349\u7A3F\u300C${input.title}\u300D\u5230\u672C\u5730\uFF0C\u4F46\u4E91\u7AEF\u540C\u6B65\u5931\u8D25: ${err}`,
32989
+ data: { id: localId }
32990
+ };
32991
+ }
32992
+ const data = await res.json();
32993
+ await log("INFO", "ink.write", `saved draft id=${localId} cloud_id=${data.id} title="${input.title}"`);
32994
+ return {
32995
+ success: true,
32996
+ message: `\u5DF2\u4FDD\u5B58\u8349\u7A3F\u300C${input.title}\u300D\uFF08\u672C\u5730 + \u4E91\u7AEF\uFF09`,
32997
+ data: { id: localId, cloud_id: data.id, slug: data.slug, status: data.status }
32998
+ };
32999
+ } catch (cloudErr) {
33000
+ await log("WARN", "ink.write", `cloud upload failed (local saved): ${cloudErr.message}`);
32838
33001
  return {
32839
33002
  success: true,
32840
- message: `\u5DF2\u4FDD\u5B58\u300C${input.title}\u300D\u5230\u672C\u5730\uFF0C\u4F46\u4E91\u7AEF\u540C\u6B65\u5931\u8D25: ${err}`,
33003
+ message: `\u5DF2\u4FDD\u5B58\u8349\u7A3F\u300C${input.title}\u300D\u5230\u672C\u5730\uFF0C\u4F46\u4E91\u7AEF\u540C\u6B65\u5931\u8D25: ${cloudErr.message}`,
32841
33004
  data: { id: localId }
32842
33005
  };
32843
33006
  }
32844
- const data = await res.json();
32845
- await log("INFO", "ink.write", `saved id=${localId} cloud_id=${data.id} title="${input.title}"`);
32846
- return {
32847
- success: true,
32848
- message: `\u5DF2\u4FDD\u5B58\u300C${input.title}\u300D\uFF08\u672C\u5730 + \u4E91\u7AEF\uFF09`,
32849
- data: { id: localId, cloud_id: data.id, slug: data.slug, status: data.status }
32850
- };
32851
33007
  } catch (err) {
32852
33008
  await log("ERROR", "ink.write", `failed: ${err.message}`);
32853
- return { success: false, message: `\u4FDD\u5B58\u5931\u8D25: ${err.message}` };
33009
+ return { success: false, message: `\u4FDD\u5B58\u8349\u7A3F\u5931\u8D25: ${err.message}` };
32854
33010
  }
32855
33011
  }
32856
33012
  async function inkDelete(input) {
32857
33013
  try {
33014
+ const store = input.store;
32858
33015
  if (!input.confirm) {
32859
- const index = await readIndex();
33016
+ const index = await readIndex(store);
32860
33017
  const entry = index.entries[input.id];
32861
33018
  if (!entry) {
32862
33019
  return { success: false, message: `\u672A\u627E\u5230 ID \u4E3A ${input.id} \u7684\u6761\u76EE` };
@@ -32864,10 +33021,10 @@ async function inkDelete(input) {
32864
33021
  return {
32865
33022
  success: false,
32866
33023
  message: `\u786E\u8BA4\u5220\u9664\u300C${entry.title}\u300D\uFF1F\u8BF7\u5C06 confirm \u8BBE\u4E3A true \u4EE5\u786E\u8BA4\u5220\u9664\u3002`,
32867
- data: { id: entry.id, title: entry.title, category: entry.category, tags: entry.tags }
33024
+ data: { id: entry.id, title: entry.title, store, category: entry.category, tags: entry.tags }
32868
33025
  };
32869
33026
  }
32870
- const deleted = await deleteKnowledgeFile(input.id);
33027
+ const deleted = await deleteKnowledgeFile(input.id, store);
32871
33028
  if (!deleted) {
32872
33029
  return { success: false, message: `\u672A\u627E\u5230 ID \u4E3A ${input.id} \u7684\u6761\u76EE` };
32873
33030
  }
@@ -32886,7 +33043,7 @@ async function inkDelete(input) {
32886
33043
  }
32887
33044
  } catch {
32888
33045
  }
32889
- await log("INFO", "ink.delete", `deleted id=${input.id}`);
33046
+ await log("INFO", "ink.delete", `deleted id=${input.id} store=${store}`);
32890
33047
  return { success: true, message: `\u5DF2\u5220\u9664 ${input.id}`, data: { id: input.id } };
32891
33048
  } catch (err) {
32892
33049
  await log("ERROR", "ink.delete", `failed: ${err.message}`);
@@ -32895,7 +33052,7 @@ async function inkDelete(input) {
32895
33052
  }
32896
33053
  async function inkTags(input) {
32897
33054
  try {
32898
- const index = await readIndex();
33055
+ const index = await readIndex("knowledge");
32899
33056
  switch (input.action) {
32900
33057
  case "list": {
32901
33058
  const tags = getAllTags(index);
@@ -32909,7 +33066,7 @@ async function inkTags(input) {
32909
33066
  if (!input.tag || !input.new_tag) {
32910
33067
  return { success: false, message: "rename \u9700\u8981 tag\uFF08\u539F\u6807\u7B7E\uFF09\u548C new_tag\uFF08\u65B0\u6807\u7B7E\u540D\uFF09" };
32911
33068
  }
32912
- const count = await renameTag(input.tag, input.new_tag);
33069
+ const count = await renameTag(input.tag, input.new_tag, "knowledge");
32913
33070
  if (count === 0) {
32914
33071
  return { success: false, message: `\u672A\u627E\u5230\u4F7F\u7528\u6807\u7B7E\u300C${input.tag}\u300D\u7684\u6761\u76EE` };
32915
33072
  }
@@ -32924,7 +33081,7 @@ async function inkTags(input) {
32924
33081
  if (!input.source_tags || input.source_tags.length === 0 || !input.new_tag) {
32925
33082
  return { success: false, message: "merge \u9700\u8981 source_tags\uFF08\u6E90\u6807\u7B7E\u5217\u8868\uFF09\u548C new_tag\uFF08\u76EE\u6807\u6807\u7B7E\uFF09" };
32926
33083
  }
32927
- const count = await mergeTags(input.source_tags, input.new_tag);
33084
+ const count = await mergeTags(input.source_tags, input.new_tag, "knowledge");
32928
33085
  if (count === 0) {
32929
33086
  return { success: false, message: "\u672A\u627E\u5230\u4F7F\u7528\u8FD9\u4E9B\u6807\u7B7E\u7684\u6761\u76EE" };
32930
33087
  }
@@ -32996,28 +33153,37 @@ async function uploadImageFromUrl(imageUrl, type, token, apiBase) {
32996
33153
  return { success: false, error: err.message };
32997
33154
  }
32998
33155
  }
32999
- var inkWriteSchema, inkDeleteSchema, inkTagsSchema;
33156
+ var inkSaveSchema, inkWriteSchema, inkDeleteSchema, inkTagsSchema;
33000
33157
  var init_ink = __esm({
33001
33158
  "src/tools/ink.ts"() {
33002
33159
  "use strict";
33003
33160
  init_zod();
33004
33161
  init_knowledge();
33005
33162
  init_state();
33163
+ init_push();
33006
33164
  init_logger();
33007
- inkWriteSchema = external_exports.object({
33008
- id: external_exports.string().optional().describe("\u672C\u5730 ID\uFF08\u63D0\u4F9B\u5219\u66F4\u65B0\u5DF2\u6709\u6761\u76EE\uFF0C\u4E0D\u63D0\u4F9B\u5219\u65B0\u5EFA\uFF09"),
33009
- title: external_exports.string().describe("\u6807\u9898"),
33165
+ inkSaveSchema = external_exports.object({
33166
+ id: external_exports.string().optional().describe("\u672C\u5730 ID\uFF08\u63D0\u4F9B\u5219\u66F4\u65B0\u5DF2\u6709\u7D20\u6750\uFF0C\u4E0D\u63D0\u4F9B\u5219\u65B0\u5EFA\uFF09"),
33167
+ title: external_exports.string().describe("\u7D20\u6750\u6807\u9898"),
33010
33168
  content: external_exports.string().describe("Markdown \u5168\u6587"),
33011
33169
  tags: external_exports.array(external_exports.string()).optional().default([]).describe("\u6807\u7B7E"),
33012
33170
  category: external_exports.enum(["insight", "decision", "analysis", "idea", "reference", "action"]).optional().default("reference").describe("\u5206\u7C7B"),
33013
33171
  source_type: external_exports.enum(["conversation", "url", "manual"]).optional().default("conversation").describe("\u6765\u6E90\u7C7B\u578B"),
33014
- url: external_exports.string().optional().describe("\u6765\u6E90 URL"),
33172
+ url: external_exports.string().optional().describe("\u6765\u6E90 URL")
33173
+ });
33174
+ inkWriteSchema = external_exports.object({
33175
+ id: external_exports.string().optional().describe("\u672C\u5730 ID\uFF08\u63D0\u4F9B\u5219\u66F4\u65B0\u5DF2\u6709\u8349\u7A3F\uFF0C\u4E0D\u63D0\u4F9B\u5219\u65B0\u5EFA\uFF09"),
33176
+ title: external_exports.string().describe("\u6587\u7AE0\u6807\u9898"),
33177
+ content: external_exports.string().describe("Markdown \u5168\u6587"),
33178
+ tags: external_exports.array(external_exports.string()).optional().default([]).describe("\u6807\u7B7E"),
33179
+ category: external_exports.enum(["insight", "decision", "analysis", "idea", "reference", "action"]).optional().default("reference").describe("\u5206\u7C7B"),
33015
33180
  cover: external_exports.string().optional().describe("\u5C01\u9762\u56FE\uFF08\u672C\u5730\u8DEF\u5F84\u6216 URL\uFF0C\u81EA\u52A8\u4E0A\u4F20\uFF09"),
33016
33181
  excerpt: external_exports.string().optional().describe("\u6458\u8981\uFF08\u4E0D\u586B\u81EA\u52A8\u622A\u53D6\u524D 200 \u5B57\uFF09"),
33017
33182
  source_ids: external_exports.array(external_exports.string()).optional().describe("\u5173\u8054\u7684\u7D20\u6750 ID\uFF08\u6EAF\u6E90\uFF09")
33018
33183
  });
33019
33184
  inkDeleteSchema = external_exports.object({
33020
33185
  id: external_exports.string().describe("\u6761\u76EE ID"),
33186
+ store: external_exports.enum(["knowledge", "drafts"]).optional().default("knowledge").describe("\u5B58\u50A8\u7C7B\u578B\uFF1Aknowledge\uFF08\u7D20\u6750\uFF09\u6216 drafts\uFF08\u8349\u7A3F\uFF09"),
33021
33187
  confirm: external_exports.boolean().optional().default(false).describe("\u786E\u8BA4\u5220\u9664\uFF08\u5FC5\u987B\u4E3A true \u624D\u4F1A\u6267\u884C\u5220\u9664\uFF09")
33022
33188
  });
33023
33189
  inkTagsSchema = external_exports.object({
@@ -33029,50 +33195,15 @@ var init_ink = __esm({
33029
33195
  }
33030
33196
  });
33031
33197
 
33032
- // src/lib/push.ts
33033
- function fireAndForgetPush(payload) {
33034
- doPush(payload).catch(() => {
33035
- });
33036
- }
33037
- async function doPush(partial2) {
33038
- const creds = await getCredentials();
33039
- if (!creds?.token) return;
33040
- const config2 = await getConfig();
33041
- const payload = {
33042
- knowledge: partial2.knowledge || [],
33043
- crawlerSources: partial2.crawlerSources || []
33044
- };
33045
- await log("DEBUG", "push", `payload: ${partial2.knowledge?.length || 0} knowledge, ${partial2.crawlerSources?.length || 0} sources`);
33046
- try {
33047
- await fetch(`${config2.apiBaseUrl}/api/sync/batch`, {
33048
- method: "POST",
33049
- headers: {
33050
- "Content-Type": "application/json",
33051
- Authorization: `Bearer ${creds.token}`
33052
- },
33053
- body: JSON.stringify(payload)
33054
- });
33055
- } catch (err) {
33056
- await log("WARN", "push", `failed: ${err instanceof Error ? err.message : err}`);
33057
- }
33058
- }
33059
- var init_push = __esm({
33060
- "src/lib/push.ts"() {
33061
- "use strict";
33062
- init_state();
33063
- init_logger();
33064
- }
33065
- });
33066
-
33067
33198
  // src/tools/source.ts
33068
33199
  import { readFile as readFile4 } from "fs/promises";
33069
- import { join as join5 } from "path";
33200
+ import { join as join6 } from "path";
33070
33201
  import { readdirSync as readdirSync2 } from "fs";
33071
33202
  import { execSync } from "child_process";
33072
33203
  async function sourceCrawl(input) {
33073
33204
  const config2 = await getConfig();
33074
- const crawlerDir = join5(config2.workflowDir || process.cwd(), "tools", "crawler");
33075
- const configPath = join5(crawlerDir, "config.json");
33205
+ const crawlerDir = join6(config2.workflowDir || process.cwd(), "tools", "crawler");
33206
+ const configPath = join6(crawlerDir, "config.json");
33076
33207
  let crawlerConfig;
33077
33208
  try {
33078
33209
  crawlerConfig = JSON.parse(await readFile4(configPath, "utf-8"));
@@ -33089,7 +33220,7 @@ async function sourceCrawl(input) {
33089
33220
  message: input.sourceId ? `\u672A\u627E\u5230\u722C\u866B\u6E90: ${input.sourceId}` : "\u6CA1\u6709\u5DF2\u542F\u7528\u7684\u722C\u866B\u6E90"
33090
33221
  };
33091
33222
  }
33092
- const crawlScript = join5(crawlerDir, "crawl.mjs");
33223
+ const crawlScript = join6(crawlerDir, "crawl.mjs");
33093
33224
  const args2 = input.sourceId ? `--source ${input.sourceId}` : "";
33094
33225
  try {
33095
33226
  execSync(`node "${crawlScript}" ${args2}`, {
@@ -33101,7 +33232,7 @@ async function sourceCrawl(input) {
33101
33232
  let saved = 0;
33102
33233
  let queued = 0;
33103
33234
  for (const target of targets) {
33104
- const sourceDir = join5(config2.workflowDir, "sources", "articles", target.id);
33235
+ const sourceDir = join6(config2.workflowDir, "sources", "articles", target.id);
33105
33236
  let files;
33106
33237
  try {
33107
33238
  files = readdirSync2(sourceDir).filter((f) => f.endsWith(".md"));
@@ -33109,7 +33240,7 @@ async function sourceCrawl(input) {
33109
33240
  continue;
33110
33241
  }
33111
33242
  for (const f of files) {
33112
- const filePath = join5(sourceDir, f);
33243
+ const filePath = join6(sourceDir, f);
33113
33244
  try {
33114
33245
  const raw = await readFile4(filePath, "utf-8");
33115
33246
  const { data, content } = (0, import_gray_matter2.default)(raw);
@@ -33184,8 +33315,8 @@ var init_source = __esm({
33184
33315
  });
33185
33316
 
33186
33317
  // src/tools/subscribe.ts
33187
- import { readFile as readFile5, writeFile as writeFile3, mkdir as mkdir5 } from "fs/promises";
33188
- import { join as join6 } from "path";
33318
+ import { readFile as readFile5, writeFile as writeFile4, mkdir as mkdir6 } from "fs/promises";
33319
+ import { join as join7 } from "path";
33189
33320
  async function readCrawlerConfig(configPath) {
33190
33321
  try {
33191
33322
  return JSON.parse(await readFile5(configPath, "utf-8"));
@@ -33195,9 +33326,9 @@ async function readCrawlerConfig(configPath) {
33195
33326
  }
33196
33327
  async function sourceSubscribe(input) {
33197
33328
  const config2 = await getConfig();
33198
- const crawlerDir = join6(config2.workflowDir || process.cwd(), "tools", "crawler");
33199
- await mkdir5(crawlerDir, { recursive: true });
33200
- const configPath = join6(crawlerDir, "config.json");
33329
+ const crawlerDir = join7(config2.workflowDir || process.cwd(), "tools", "crawler");
33330
+ await mkdir6(crawlerDir, { recursive: true });
33331
+ const configPath = join7(crawlerDir, "config.json");
33201
33332
  const crawlerConfig = await readCrawlerConfig(configPath);
33202
33333
  if (input.action === "list") {
33203
33334
  return {
@@ -33229,7 +33360,7 @@ async function sourceSubscribe(input) {
33229
33360
  if (input.crawlConfig.maxArticles) newSource.maxArticles = input.crawlConfig.maxArticles;
33230
33361
  }
33231
33362
  crawlerConfig.sources.push(newSource);
33232
- await writeFile3(configPath, JSON.stringify(crawlerConfig, null, 2));
33363
+ await writeFile4(configPath, JSON.stringify(crawlerConfig, null, 2));
33233
33364
  fireAndForgetPush({
33234
33365
  crawlerSources: crawlerConfig.sources.map((s) => ({
33235
33366
  id: s.id,
@@ -33247,7 +33378,7 @@ async function sourceSubscribe(input) {
33247
33378
  return { success: false, message: "\u5220\u9664\u8BA2\u9605\u6E90\u9700\u8981 id \u53C2\u6570" };
33248
33379
  }
33249
33380
  crawlerConfig.sources = crawlerConfig.sources.filter((s) => s.id !== input.id);
33250
- await writeFile3(configPath, JSON.stringify(crawlerConfig, null, 2));
33381
+ await writeFile4(configPath, JSON.stringify(crawlerConfig, null, 2));
33251
33382
  fireAndForgetPush({
33252
33383
  crawlerSources: crawlerConfig.sources.map((s) => ({
33253
33384
  id: s.id,
@@ -33321,7 +33452,7 @@ var init_index = __esm({
33321
33452
  init_logger();
33322
33453
  server = new McpServer({
33323
33454
  name: "ClaudeInk",
33324
- version: "2.1.0"
33455
+ version: "2.2.0"
33325
33456
  });
33326
33457
  server.tool("ink.init", "\u521D\u59CB\u5316\u77E5\u8BC6\u5E93\uFF08\u521B\u5EFA\u76EE\u5F55 + \u6FC0\u6D3B License + \u540C\u6B65\u4E91\u7AEF\uFF09", workflowInitSchema.shape, async (input) => {
33327
33458
  const result = await workflowInit(input);
@@ -33331,7 +33462,11 @@ var init_index = __esm({
33331
33462
  const result = await sync2(input);
33332
33463
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
33333
33464
  });
33334
- server.tool("ink.write", "\u4FDD\u5B58\u5185\u5BB9\uFF08\u672C\u5730 .md + \u4E0A\u4F20\u4E91\u7AEF\uFF09\u3002Claude \u751F\u6210\u5185\u5BB9\u540E\u8C03\u7528\u6B64\u5DE5\u5177\u4FDD\u5B58\u3002", inkWriteSchema.shape, async (input) => {
33465
+ server.tool("ink.save", "\u6536\u96C6\u7D20\u6750\u5230\u77E5\u8BC6\u5E93\uFF08\u539F\u59CB\u5185\u5BB9\u3001\u7F51\u9875\u6458\u5F55\u3001\u5BF9\u8BDD\u7247\u6BB5\u7B49\uFF09\u3002\u5B58\u5165\u672C\u5730 knowledge/ \u76EE\u5F55\uFF0C\u5143\u6570\u636E\u540C\u6B65\u5230\u4E91\u7AEF source_meta\u3002", inkSaveSchema.shape, async (input) => {
33466
+ const result = await inkSave(input);
33467
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
33468
+ });
33469
+ server.tool("ink.write", "\u4FDD\u5B58\u8349\u7A3F/\u6587\u7AE0\uFF08AI \u521B\u4F5C\u7684\u5B8C\u6574\u6587\u7AE0\uFF09\u3002\u5B58\u5165\u672C\u5730 drafts/ \u76EE\u5F55\uFF0C\u5168\u6587\u4E0A\u4F20\u5230\u4E91\u7AEF blog_posts\u3002", inkWriteSchema.shape, async (input) => {
33335
33470
  const result = await inkWrite(input);
33336
33471
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
33337
33472
  });
@@ -33362,14 +33497,14 @@ var init_index = __esm({
33362
33497
  });
33363
33498
 
33364
33499
  // src/cli.ts
33365
- import { writeFile as writeFile4, readFile as readFile6, mkdir as mkdir6, cp, access as access2 } from "fs/promises";
33366
- import { join as join7, dirname } from "path";
33500
+ import { writeFile as writeFile5, readFile as readFile6, mkdir as mkdir7, cp, access as access2 } from "fs/promises";
33501
+ import { join as join8, dirname } from "path";
33367
33502
  import { fileURLToPath as fileURLToPath3 } from "url";
33368
33503
  var args = process.argv.slice(2);
33369
33504
  var command = args[0];
33370
33505
  var __filename = fileURLToPath3(import.meta.url);
33371
33506
  var __dirname = dirname(__filename);
33372
- var WORKFLOW_SRC = join7(__dirname, "..", "workflow");
33507
+ var WORKFLOW_SRC = join8(__dirname, "..", "workflow");
33373
33508
  async function init() {
33374
33509
  const keyIdx = args.indexOf("--key");
33375
33510
  const key = keyIdx >= 0 ? args[keyIdx + 1] : void 0;
@@ -33385,8 +33520,8 @@ async function init() {
33385
33520
  console.log("\u{1F4E6} \u91CA\u653E\u5DE5\u4F5C\u6D41\u6A21\u677F...");
33386
33521
  const items = ["CLAUDE.md", "base-rules.md", "platforms", "accounts", "tools"];
33387
33522
  for (const item of items) {
33388
- const src = join7(WORKFLOW_SRC, item);
33389
- const dest = join7(cwd, item);
33523
+ const src = join8(WORKFLOW_SRC, item);
33524
+ const dest = join8(cwd, item);
33390
33525
  try {
33391
33526
  await access2(dest);
33392
33527
  console.log(` \u23ED\uFE0F ${item} \u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7`);
@@ -33406,14 +33541,14 @@ async function init() {
33406
33541
  ".claudeink"
33407
33542
  ];
33408
33543
  for (const dir of dirs) {
33409
- await mkdir6(join7(cwd, dir), { recursive: true });
33544
+ await mkdir7(join8(cwd, dir), { recursive: true });
33410
33545
  }
33411
33546
  console.log(" \u2705 sources/, templates/, .claudeink/");
33412
33547
  const { glob: glob2 } = await Promise.resolve().then(() => (init_esm5(), esm_exports));
33413
33548
  const yamlFiles = await glob2("accounts/*.yaml", { cwd, ignore: "accounts/_template.yaml" });
33414
33549
  for (const yamlFile of yamlFiles) {
33415
33550
  try {
33416
- const content = await readFile6(join7(cwd, yamlFile), "utf-8");
33551
+ const content = await readFile6(join8(cwd, yamlFile), "utf-8");
33417
33552
  const idMatch = content.match(/^id:\s*"?([^"\n]+)"?/m);
33418
33553
  if (idMatch) {
33419
33554
  const id = idMatch[1].trim();
@@ -33423,9 +33558,9 @@ async function init() {
33423
33558
  const drafts = (draftsMatch?.[1] || `accounts/${id}/drafts/`).replace("{id}", id).trim();
33424
33559
  const published = (publishedMatch?.[1] || `accounts/${id}/published/`).replace("{id}", id).trim();
33425
33560
  const assets = (assetsMatch?.[1] || `accounts/${id}/assets/`).replace("{id}", id).trim();
33426
- await mkdir6(join7(cwd, drafts), { recursive: true });
33427
- await mkdir6(join7(cwd, published), { recursive: true });
33428
- await mkdir6(join7(cwd, assets), { recursive: true });
33561
+ await mkdir7(join8(cwd, drafts), { recursive: true });
33562
+ await mkdir7(join8(cwd, published), { recursive: true });
33563
+ await mkdir7(join8(cwd, assets), { recursive: true });
33429
33564
  console.log(` \u2705 \u8D26\u53F7 ${id}: ${drafts}, ${published}, ${assets}`);
33430
33565
  }
33431
33566
  } catch {
@@ -33440,8 +33575,8 @@ async function init() {
33440
33575
  });
33441
33576
  const data = await res.json();
33442
33577
  if (data.userId) {
33443
- await writeFile4(
33444
- join7(cwd, ".claudeink", "credentials.json"),
33578
+ await writeFile5(
33579
+ join8(cwd, ".claudeink", "credentials.json"),
33445
33580
  JSON.stringify(data, null, 2),
33446
33581
  { mode: 384 }
33447
33582
  );
@@ -33455,11 +33590,11 @@ async function init() {
33455
33590
  console.log(" \u53EF\u7A0D\u540E\u624B\u52A8\u6FC0\u6D3B\u3002");
33456
33591
  }
33457
33592
  try {
33458
- await access2(join7(cwd, "tools", "crawler", "package.json"));
33593
+ await access2(join8(cwd, "tools", "crawler", "package.json"));
33459
33594
  console.log("\n\u{1F4E6} \u5B89\u88C5\u722C\u866B\u4F9D\u8D56...");
33460
33595
  const { execSync: execSync2 } = await import("child_process");
33461
33596
  execSync2("npm install --silent", {
33462
- cwd: join7(cwd, "tools", "crawler"),
33597
+ cwd: join8(cwd, "tools", "crawler"),
33463
33598
  stdio: "pipe"
33464
33599
  });
33465
33600
  console.log(" \u2705 \u722C\u866B\u4F9D\u8D56\u5DF2\u5B89\u88C5");