@claudeink/mcp-server 2.1.0 → 2.2.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 (3) hide show
  1. package/dist/cli.js +461 -327
  2. package/dist/index.js +416 -284
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -24477,8 +24477,8 @@ var StdioServerTransport = class {
24477
24477
  };
24478
24478
 
24479
24479
  // src/tools/workflow.ts
24480
- import { mkdir as mkdir3, access, unlink } from "fs/promises";
24481
- import { join as join3 } from "path";
24480
+ import { mkdir as mkdir5, access, unlink as unlink2 } from "fs/promises";
24481
+ import { join as join5 } from "path";
24482
24482
 
24483
24483
  // src/lib/state.ts
24484
24484
  import { readFile, writeFile, mkdir, chmod } from "fs/promises";
@@ -24576,160 +24576,14 @@ async function addToTagQueue(item) {
24576
24576
  await writeState(state);
24577
24577
  }
24578
24578
 
24579
- // src/lib/logger.ts
24580
- import { appendFile, mkdir as mkdir2 } from "fs/promises";
24581
- import { join as join2 } from "path";
24582
- var currentLevel = "INFO";
24583
- var LEVELS = { ERROR: 0, WARN: 1, INFO: 2, DEBUG: 3 };
24584
- function setLogLevel(level) {
24585
- currentLevel = level;
24586
- }
24587
- async function log(level, scope, message) {
24588
- if (LEVELS[level] > LEVELS[currentLevel]) return;
24589
- const dir = join2(getClaudeinkDir(), "logs");
24590
- await mkdir2(dir, { recursive: true });
24591
- const date3 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
24592
- const line = `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${scope} | ${message}
24593
- `;
24594
- await appendFile(join2(dir, `mcp-${date3}.log`), line);
24595
- console.error(`[ClaudeInk] ${line.trim()}`);
24596
- }
24597
-
24598
24579
  // src/tools/sync.ts
24599
- var syncSchema = external_exports.object({
24600
- workDir: external_exports.string().optional().describe("\u5DE5\u4F5C\u76EE\u5F55\uFF08\u9ED8\u8BA4\u4F7F\u7528\u914D\u7F6E\u4E2D\u7684 workflowDir\uFF09")
24601
- });
24602
- async function sync(input) {
24603
- if (input.workDir) setWorkDir(input.workDir);
24604
- const creds = await getCredentials();
24605
- if (!creds?.token) {
24606
- return { success: false, message: "\u672A\u6FC0\u6D3B\uFF0C\u8BF7\u5148\u4F7F\u7528 workflow.init \u6FC0\u6D3B License" };
24607
- }
24608
- return doPull(creds.token);
24609
- }
24610
- async function doPull(token) {
24611
- const config2 = await getConfig();
24612
- try {
24613
- const res = await fetch(`${config2.apiBaseUrl}/api/sync/pull`, {
24614
- headers: { Authorization: `Bearer ${token}` }
24615
- });
24616
- if (!res.ok) {
24617
- if (res.status === 404) {
24618
- return { success: true, message: "\u4E91\u7AEF\u65E0\u6570\u636E" };
24619
- }
24620
- await log("ERROR", "ink.sync", `pull failed: HTTP ${res.status}`);
24621
- return { success: false, message: `\u62C9\u53D6\u5931\u8D25: HTTP ${res.status}` };
24622
- }
24623
- await updateLastSyncAt();
24624
- await log("INFO", "ink.sync", "pull completed");
24625
- return {
24626
- success: true,
24627
- message: "\u2705 \u540C\u6B65\u5B8C\u6210"
24628
- };
24629
- } catch (err) {
24630
- return { success: false, message: `\u540C\u6B65\u5931\u8D25: ${err instanceof Error ? err.message : err}` };
24631
- }
24632
- }
24633
- async function syncPull(input) {
24634
- if (input.workDir) setWorkDir(input.workDir);
24635
- const creds = await getCredentials();
24636
- if (!creds?.token) {
24637
- return { success: false, message: "\u672A\u6FC0\u6D3B" };
24638
- }
24639
- return doPull(creds.token);
24640
- }
24641
-
24642
- // src/tools/workflow.ts
24643
- var DEFAULT_API_BASE_URL = "https://app.claudeink.com";
24644
- var workflowInitSchema = external_exports.object({
24645
- workDir: external_exports.string().describe("\u5DE5\u4F5C\u6D41\u521D\u59CB\u5316\u76EE\u6807\u76EE\u5F55\uFF08\u7EDD\u5BF9\u8DEF\u5F84\uFF09"),
24646
- licenseKey: external_exports.string().optional().describe("License Key\uFF08\u53EF\u9009\uFF0C\u4F20\u5165\u5219\u81EA\u52A8\u6FC0\u6D3B\uFF09")
24647
- });
24648
- async function workflowInit(input) {
24649
- const cwd = input.workDir;
24650
- const results = [];
24651
- try {
24652
- setWorkDir(cwd);
24653
- const claudeinkDir = join3(cwd, ".claudeink");
24654
- await mkdir3(join3(claudeinkDir, "knowledge"), { recursive: true });
24655
- results.push("\u2705 \u77E5\u8BC6\u5E93\u76EE\u5F55\u5DF2\u521B\u5EFA");
24656
- const state = await readState();
24657
- state.config.workflowDir = cwd;
24658
- const oldCredsPath = join3(claudeinkDir, "credentials.json");
24659
- try {
24660
- await access(oldCredsPath);
24661
- await unlink(oldCredsPath);
24662
- results.push("\u{1F9F9} \u5DF2\u6E05\u7406\u65E7\u7248 credentials.json");
24663
- } catch {
24664
- }
24665
- let activated = false;
24666
- if (input.licenseKey) {
24667
- try {
24668
- const res = await fetch(`${DEFAULT_API_BASE_URL}/api/auth/activate`, {
24669
- method: "POST",
24670
- headers: { "Content-Type": "application/json" },
24671
- body: JSON.stringify({ key: input.licenseKey })
24672
- });
24673
- const data = await res.json();
24674
- if (data.userId) {
24675
- state.credentials = {
24676
- licenseKey: input.licenseKey,
24677
- token: data.token,
24678
- userId: data.userId,
24679
- plan: data.plan,
24680
- expiresAt: data.expiresAt
24681
- };
24682
- results.push(`\u2705 License \u6FC0\u6D3B\u6210\u529F\uFF08\u5957\u9910: ${data.plan}\uFF09`);
24683
- activated = true;
24684
- } else {
24685
- results.push(`\u26A0\uFE0F License \u6FC0\u6D3B\u5931\u8D25: ${JSON.stringify(data)}`);
24686
- }
24687
- } catch (err) {
24688
- results.push(`\u26A0\uFE0F \u6FC0\u6D3B\u7F51\u7EDC\u9519\u8BEF: ${err instanceof Error ? err.message : err}`);
24689
- }
24690
- }
24691
- await writeState(state);
24692
- results.push("\u2705 state.json");
24693
- if (state.credentials?.token) {
24694
- try {
24695
- const pullResult = await syncPull({ workDir: cwd });
24696
- if (pullResult.success) {
24697
- results.push("\u2705 \u5DF2\u4ECE\u4E91\u7AEF\u540C\u6B65\u6570\u636E");
24698
- } else {
24699
- results.push("\u2139\uFE0F \u4E91\u7AEF\u65E0\u5DF2\u6709\u6570\u636E");
24700
- }
24701
- } catch {
24702
- results.push("\u2139\uFE0F \u4E91\u7AEF\u540C\u6B65\u8DF3\u8FC7");
24703
- }
24704
- }
24705
- return {
24706
- success: true,
24707
- message: [
24708
- "\u{1F389} ClaudeInk \u77E5\u8BC6\u5E93\u521D\u59CB\u5316\u5B8C\u6210\uFF01",
24709
- "",
24710
- ...results,
24711
- "",
24712
- "\u{1F3AF} \u4E0B\u4E00\u6B65\uFF1A",
24713
- "1. \u5728\u5BF9\u8BDD\u4E2D\u8BF4\u300C\u5E2E\u6211\u5B58\u4E00\u4E0B\u300D\u4FDD\u5B58\u6709\u4EF7\u503C\u5185\u5BB9",
24714
- "2. \u7528\u300C\u627E\u4E00\u4E0B\u5173\u4E8E XX \u7684\u300D\u68C0\u7D22\u77E5\u8BC6\u5E93"
24715
- ].join("\n")
24716
- };
24717
- } catch (err) {
24718
- return {
24719
- success: false,
24720
- message: `\u521D\u59CB\u5316\u5931\u8D25: ${err instanceof Error ? err.message : err}`
24721
- };
24722
- }
24723
- }
24724
-
24725
- // src/tools/ink.ts
24726
- import { readFile as readFile3 } from "fs/promises";
24727
- import { extname } from "path";
24580
+ import { writeFile as writeFile3, mkdir as mkdir4 } from "fs/promises";
24581
+ import { join as join4 } from "path";
24728
24582
 
24729
24583
  // src/lib/knowledge.ts
24730
24584
  var import_gray_matter = __toESM(require_gray_matter(), 1);
24731
- import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir4, unlink as unlink2 } from "fs/promises";
24732
- import { join as join4 } from "path";
24585
+ import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, unlink } from "fs/promises";
24586
+ import { join as join2 } from "path";
24733
24587
  var _lockPromise = Promise.resolve();
24734
24588
  function withIndexLock(fn) {
24735
24589
  const prev = _lockPromise;
@@ -24739,11 +24593,11 @@ function withIndexLock(fn) {
24739
24593
  });
24740
24594
  return prev.then(fn).finally(() => resolve());
24741
24595
  }
24742
- function getKnowledgeDir() {
24743
- return join4(getWorkDir(), ".claudeink", "knowledge");
24596
+ function getStoreDir(store = "knowledge") {
24597
+ return join2(getWorkDir(), ".claudeink", store);
24744
24598
  }
24745
- function getIndexPath() {
24746
- return join4(getWorkDir(), ".claudeink", "knowledge", "index.json");
24599
+ function getIndexPath(store = "knowledge") {
24600
+ return join2(getWorkDir(), ".claudeink", store, "index.json");
24747
24601
  }
24748
24602
  async function generateIdInternal(index) {
24749
24603
  const now = /* @__PURE__ */ new Date();
@@ -24765,28 +24619,28 @@ function toSlug(title) {
24765
24619
  function generatePreview(content, maxLen = 200) {
24766
24620
  return content.replace(/^#+\s.+$/gm, "").replace(/\n+/g, " ").trim().slice(0, maxLen);
24767
24621
  }
24768
- async function readIndex() {
24622
+ async function readIndex(store = "knowledge") {
24769
24623
  try {
24770
- const raw = await readFile2(getIndexPath(), "utf-8");
24624
+ const raw = await readFile2(getIndexPath(store), "utf-8");
24771
24625
  return JSON.parse(raw);
24772
24626
  } catch {
24773
24627
  return { entries: {}, updated_at: (/* @__PURE__ */ new Date()).toISOString() };
24774
24628
  }
24775
24629
  }
24776
- async function saveIndex(index) {
24630
+ async function saveIndex(index, store = "knowledge") {
24777
24631
  index.updated_at = (/* @__PURE__ */ new Date()).toISOString();
24778
- const dir = getKnowledgeDir();
24779
- await mkdir4(dir, { recursive: true });
24780
- await writeFile2(getIndexPath(), JSON.stringify(index, null, 2), "utf-8");
24632
+ const dir = getStoreDir(store);
24633
+ await mkdir2(dir, { recursive: true });
24634
+ await writeFile2(getIndexPath(store), JSON.stringify(index, null, 2), "utf-8");
24781
24635
  }
24782
- async function writeKnowledgeFile(meta, content) {
24636
+ async function writeKnowledgeFile(meta, content, store = "knowledge") {
24783
24637
  const now = /* @__PURE__ */ new Date();
24784
24638
  const monthDir = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}`;
24785
- const dir = join4(getKnowledgeDir(), monthDir);
24786
- await mkdir4(dir, { recursive: true });
24639
+ const dir = join2(getStoreDir(store), monthDir);
24640
+ await mkdir2(dir, { recursive: true });
24787
24641
  const slug = toSlug(meta.title) || meta.id;
24788
24642
  const filename = `${now.toISOString().slice(0, 10)}-${slug}.md`;
24789
- const filePath = join4(dir, filename);
24643
+ const filePath = join2(dir, filename);
24790
24644
  const frontmatter = {
24791
24645
  id: meta.id,
24792
24646
  title: meta.title,
@@ -24799,13 +24653,13 @@ async function writeKnowledgeFile(meta, content) {
24799
24653
  if (meta.url) frontmatter.url = meta.url;
24800
24654
  const output = import_gray_matter.default.stringify(content, frontmatter);
24801
24655
  await writeFile2(filePath, output, "utf-8");
24802
- return join4(monthDir, filename);
24656
+ return join2(monthDir, filename);
24803
24657
  }
24804
- async function readKnowledgeFile(id) {
24805
- const index = await readIndex();
24658
+ async function readKnowledgeFile(id, store = "knowledge") {
24659
+ const index = await readIndex(store);
24806
24660
  const entry = index.entries[id];
24807
24661
  if (!entry) return null;
24808
- const filePath = join4(getKnowledgeDir(), entry.file_path);
24662
+ const filePath = join2(getStoreDir(store), entry.file_path);
24809
24663
  try {
24810
24664
  const raw = await readFile2(filePath, "utf-8");
24811
24665
  const { data, content } = (0, import_gray_matter.default)(raw);
@@ -24819,8 +24673,9 @@ async function readKnowledgeFile(id) {
24819
24673
  }
24820
24674
  }
24821
24675
  async function saveKnowledge(params) {
24676
+ const store = params.store || "knowledge";
24822
24677
  return withIndexLock(async () => {
24823
- const index = await readIndex();
24678
+ const index = await readIndex(store);
24824
24679
  const id = await generateIdInternal(index);
24825
24680
  const now = (/* @__PURE__ */ new Date()).toISOString();
24826
24681
  const meta = {
@@ -24833,7 +24688,7 @@ async function saveKnowledge(params) {
24833
24688
  created_at: now,
24834
24689
  updated_at: now
24835
24690
  };
24836
- const relativePath = await writeKnowledgeFile(meta, params.content);
24691
+ const relativePath = await writeKnowledgeFile(meta, params.content, store);
24837
24692
  index.entries[id] = {
24838
24693
  id,
24839
24694
  title: params.title,
@@ -24845,13 +24700,13 @@ async function saveKnowledge(params) {
24845
24700
  created_at: now,
24846
24701
  updated_at: now
24847
24702
  };
24848
- await saveIndex(index);
24703
+ await saveIndex(index, store);
24849
24704
  return { id, filePath: relativePath };
24850
24705
  });
24851
24706
  }
24852
- async function updateKnowledgeFile(id, updates) {
24707
+ async function updateKnowledgeFile(id, updates, store = "knowledge") {
24853
24708
  return withIndexLock(async () => {
24854
- const file = await readKnowledgeFile(id);
24709
+ const file = await readKnowledgeFile(id, store);
24855
24710
  if (!file) return null;
24856
24711
  const now = (/* @__PURE__ */ new Date()).toISOString();
24857
24712
  const meta = { ...file.meta };
@@ -24872,7 +24727,7 @@ async function updateKnowledgeFile(id, updates) {
24872
24727
  if (meta.url) frontmatter.url = meta.url;
24873
24728
  const output = import_gray_matter.default.stringify(content, frontmatter);
24874
24729
  await writeFile2(file.filePath, output, "utf-8");
24875
- const index = await readIndex();
24730
+ const index = await readIndex(store);
24876
24731
  const entry = index.entries[id];
24877
24732
  if (entry) {
24878
24733
  entry.title = meta.title;
@@ -24880,23 +24735,23 @@ async function updateKnowledgeFile(id, updates) {
24880
24735
  entry.category = meta.category;
24881
24736
  entry.preview = generatePreview(content);
24882
24737
  entry.updated_at = now;
24883
- await saveIndex(index);
24738
+ await saveIndex(index, store);
24884
24739
  }
24885
24740
  return { meta, content, filePath: file.filePath };
24886
24741
  });
24887
24742
  }
24888
- async function deleteKnowledgeFile(id) {
24743
+ async function deleteKnowledgeFile(id, store = "knowledge") {
24889
24744
  return withIndexLock(async () => {
24890
- const index = await readIndex();
24745
+ const index = await readIndex(store);
24891
24746
  const entry = index.entries[id];
24892
24747
  if (!entry) return false;
24893
- const filePath = join4(getKnowledgeDir(), entry.file_path);
24748
+ const filePath = join2(getStoreDir(store), entry.file_path);
24894
24749
  try {
24895
- await unlink2(filePath);
24750
+ await unlink(filePath);
24896
24751
  } catch {
24897
24752
  }
24898
24753
  delete index.entries[id];
24899
- await saveIndex(index);
24754
+ await saveIndex(index, store);
24900
24755
  return true;
24901
24756
  });
24902
24757
  }
@@ -24909,16 +24764,16 @@ function getAllTags(index) {
24909
24764
  }
24910
24765
  return Object.entries(tagCounts).map(([name, count]) => ({ name, count })).sort((a, b) => b.count - a.count);
24911
24766
  }
24912
- async function renameTag(oldTag, newTag) {
24767
+ async function renameTag(oldTag, newTag, store = "knowledge") {
24913
24768
  return withIndexLock(async () => {
24914
- const index = await readIndex();
24769
+ const index = await readIndex(store);
24915
24770
  let count = 0;
24916
24771
  for (const entry of Object.values(index.entries)) {
24917
24772
  const idx = entry.tags.indexOf(oldTag);
24918
24773
  if (idx !== -1) {
24919
24774
  entry.tags[idx] = newTag;
24920
24775
  count++;
24921
- const filePath = join4(getKnowledgeDir(), entry.file_path);
24776
+ const filePath = join2(getStoreDir(store), entry.file_path);
24922
24777
  try {
24923
24778
  const raw = await readFile2(filePath, "utf-8");
24924
24779
  const { data, content } = (0, import_gray_matter.default)(raw);
@@ -24935,14 +24790,14 @@ async function renameTag(oldTag, newTag) {
24935
24790
  }
24936
24791
  }
24937
24792
  if (count > 0) {
24938
- await saveIndex(index);
24793
+ await saveIndex(index, store);
24939
24794
  }
24940
24795
  return count;
24941
24796
  });
24942
24797
  }
24943
- async function mergeTags(sourceTags, targetTag) {
24798
+ async function mergeTags(sourceTags, targetTag, store = "knowledge") {
24944
24799
  return withIndexLock(async () => {
24945
- const index = await readIndex();
24800
+ const index = await readIndex(store);
24946
24801
  let count = 0;
24947
24802
  for (const entry of Object.values(index.entries)) {
24948
24803
  const hasSource = entry.tags.some((t) => sourceTags.includes(t));
@@ -24953,7 +24808,7 @@ async function mergeTags(sourceTags, targetTag) {
24953
24808
  }
24954
24809
  entry.tags = newTags;
24955
24810
  count++;
24956
- const filePath = join4(getKnowledgeDir(), entry.file_path);
24811
+ const filePath = join2(getStoreDir(store), entry.file_path);
24957
24812
  try {
24958
24813
  const raw = await readFile2(filePath, "utf-8");
24959
24814
  const { data, content } = (0, import_gray_matter.default)(raw);
@@ -24965,21 +24820,310 @@ async function mergeTags(sourceTags, targetTag) {
24965
24820
  }
24966
24821
  }
24967
24822
  if (count > 0) {
24968
- await saveIndex(index);
24823
+ await saveIndex(index, store);
24969
24824
  }
24970
24825
  return count;
24971
24826
  });
24972
24827
  }
24973
24828
 
24829
+ // src/lib/logger.ts
24830
+ import { appendFile, mkdir as mkdir3 } from "fs/promises";
24831
+ import { join as join3 } from "path";
24832
+ var currentLevel = "INFO";
24833
+ var LEVELS = { ERROR: 0, WARN: 1, INFO: 2, DEBUG: 3 };
24834
+ function setLogLevel(level) {
24835
+ currentLevel = level;
24836
+ }
24837
+ async function log(level, scope, message) {
24838
+ if (LEVELS[level] > LEVELS[currentLevel]) return;
24839
+ const dir = join3(getClaudeinkDir(), "logs");
24840
+ await mkdir3(dir, { recursive: true });
24841
+ const date3 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
24842
+ const line = `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${scope} | ${message}
24843
+ `;
24844
+ await appendFile(join3(dir, `mcp-${date3}.log`), line);
24845
+ console.error(`[ClaudeInk] ${line.trim()}`);
24846
+ }
24847
+
24848
+ // src/tools/sync.ts
24849
+ var syncSchema = external_exports.object({
24850
+ workDir: external_exports.string().optional().describe("\u5DE5\u4F5C\u76EE\u5F55\uFF08\u9ED8\u8BA4\u4F7F\u7528\u914D\u7F6E\u4E2D\u7684 workflowDir\uFF09")
24851
+ });
24852
+ async function sync(input) {
24853
+ if (input.workDir) setWorkDir(input.workDir);
24854
+ const creds = await getCredentials();
24855
+ if (!creds?.token) {
24856
+ return { success: false, message: "\u672A\u6FC0\u6D3B\uFF0C\u8BF7\u5148\u4F7F\u7528 ink.init \u6FC0\u6D3B License" };
24857
+ }
24858
+ return doPull(creds.token);
24859
+ }
24860
+ async function doPull(token) {
24861
+ const config2 = await getConfig();
24862
+ try {
24863
+ const res = await fetch(`${config2.apiBaseUrl}/api/sync/pull`, {
24864
+ headers: { Authorization: `Bearer ${token}` }
24865
+ });
24866
+ if (!res.ok) {
24867
+ if (res.status === 404) {
24868
+ return { success: true, message: "\u4E91\u7AEF\u65E0\u6570\u636E" };
24869
+ }
24870
+ await log("ERROR", "ink.sync", `pull failed: HTTP ${res.status}`);
24871
+ return { success: false, message: `\u62C9\u53D6\u5931\u8D25: HTTP ${res.status}` };
24872
+ }
24873
+ const data = await res.json();
24874
+ const results = [];
24875
+ if (data.configs) {
24876
+ const crawlerConfig = data.configs.find((c) => c.type === "crawler" && c.name === "config");
24877
+ if (crawlerConfig?.content) {
24878
+ try {
24879
+ const sources = JSON.parse(crawlerConfig.content);
24880
+ const crawlerDir = join4(config2.workflowDir || getWorkDir(), "tools", "crawler");
24881
+ await mkdir4(crawlerDir, { recursive: true });
24882
+ await writeFile3(join4(crawlerDir, "config.json"), JSON.stringify({ sources }, null, 2));
24883
+ results.push(`\u8BA2\u9605\u6E90: ${sources.length} \u4E2A`);
24884
+ } catch {
24885
+ }
24886
+ }
24887
+ }
24888
+ if (data.sources && Object.keys(data.sources).length > 0) {
24889
+ const index = await readIndex();
24890
+ let added = 0;
24891
+ for (const [localId, meta] of Object.entries(data.sources)) {
24892
+ if (!index.entries[localId]) {
24893
+ const entry = {
24894
+ id: localId,
24895
+ title: meta.title || "",
24896
+ tags: meta.tags || [],
24897
+ category: "reference",
24898
+ source_type: "url",
24899
+ preview: "",
24900
+ file_path: "",
24901
+ created_at: meta.publishedAt || (/* @__PURE__ */ new Date()).toISOString(),
24902
+ updated_at: meta.updatedAt || (/* @__PURE__ */ new Date()).toISOString()
24903
+ };
24904
+ index.entries[localId] = entry;
24905
+ added++;
24906
+ }
24907
+ }
24908
+ if (added > 0) {
24909
+ index.updated_at = (/* @__PURE__ */ new Date()).toISOString();
24910
+ const knowledgeDir = join4(getWorkDir(), ".claudeink", "knowledge");
24911
+ await mkdir4(knowledgeDir, { recursive: true });
24912
+ await writeFile3(join4(knowledgeDir, "index.json"), JSON.stringify(index, null, 2));
24913
+ results.push(`\u7D20\u6750\u7D22\u5F15: +${added} \u6761\uFF08\u5171 ${Object.keys(index.entries).length} \u6761\uFF09`);
24914
+ } else {
24915
+ results.push(`\u7D20\u6750\u7D22\u5F15: ${Object.keys(index.entries).length} \u6761\uFF08\u5DF2\u540C\u6B65\uFF09`);
24916
+ }
24917
+ }
24918
+ const draftCount = data.drafts ? Object.keys(data.drafts).length : 0;
24919
+ const pubCount = data.published ? Object.keys(data.published).length : 0;
24920
+ if (draftCount > 0 || pubCount > 0) {
24921
+ results.push(`\u8349\u7A3F: ${draftCount} \u7BC7, \u5DF2\u53D1\u5E03: ${pubCount} \u7BC7`);
24922
+ }
24923
+ await updateLastSyncAt();
24924
+ await log("INFO", "ink.sync", `pull completed: ${results.join(", ")}`);
24925
+ return {
24926
+ success: true,
24927
+ message: results.length > 0 ? `\u2705 \u540C\u6B65\u5B8C\u6210
24928
+ ${results.join("\n")}` : "\u2705 \u540C\u6B65\u5B8C\u6210\uFF08\u4E91\u7AEF\u65E0\u65B0\u6570\u636E\uFF09"
24929
+ };
24930
+ } catch (err) {
24931
+ return { success: false, message: `\u540C\u6B65\u5931\u8D25: ${err instanceof Error ? err.message : err}` };
24932
+ }
24933
+ }
24934
+ async function syncPull(input) {
24935
+ if (input.workDir) setWorkDir(input.workDir);
24936
+ const creds = await getCredentials();
24937
+ if (!creds?.token) {
24938
+ return { success: false, message: "\u672A\u6FC0\u6D3B" };
24939
+ }
24940
+ return doPull(creds.token);
24941
+ }
24942
+
24943
+ // src/tools/workflow.ts
24944
+ var DEFAULT_API_BASE_URL = "https://app.claudeink.com";
24945
+ var workflowInitSchema = external_exports.object({
24946
+ workDir: external_exports.string().describe("\u5DE5\u4F5C\u6D41\u521D\u59CB\u5316\u76EE\u6807\u76EE\u5F55\uFF08\u7EDD\u5BF9\u8DEF\u5F84\uFF09"),
24947
+ licenseKey: external_exports.string().optional().describe("License Key\uFF08\u53EF\u9009\uFF0C\u4F20\u5165\u5219\u81EA\u52A8\u6FC0\u6D3B\uFF09")
24948
+ });
24949
+ async function workflowInit(input) {
24950
+ const cwd = input.workDir;
24951
+ const results = [];
24952
+ try {
24953
+ setWorkDir(cwd);
24954
+ const claudeinkDir = join5(cwd, ".claudeink");
24955
+ await mkdir5(join5(claudeinkDir, "knowledge"), { recursive: true });
24956
+ results.push("\u2705 \u77E5\u8BC6\u5E93\u76EE\u5F55\u5DF2\u521B\u5EFA");
24957
+ const state = await readState();
24958
+ state.config.workflowDir = cwd;
24959
+ const oldCredsPath = join5(claudeinkDir, "credentials.json");
24960
+ try {
24961
+ await access(oldCredsPath);
24962
+ await unlink2(oldCredsPath);
24963
+ results.push("\u{1F9F9} \u5DF2\u6E05\u7406\u65E7\u7248 credentials.json");
24964
+ } catch {
24965
+ }
24966
+ let activated = false;
24967
+ if (input.licenseKey) {
24968
+ try {
24969
+ const res = await fetch(`${DEFAULT_API_BASE_URL}/api/auth/activate`, {
24970
+ method: "POST",
24971
+ headers: { "Content-Type": "application/json" },
24972
+ body: JSON.stringify({ key: input.licenseKey })
24973
+ });
24974
+ const data = await res.json();
24975
+ if (data.userId) {
24976
+ state.credentials = {
24977
+ licenseKey: input.licenseKey,
24978
+ token: data.token,
24979
+ userId: data.userId,
24980
+ plan: data.plan,
24981
+ expiresAt: data.expiresAt
24982
+ };
24983
+ results.push(`\u2705 License \u6FC0\u6D3B\u6210\u529F\uFF08\u5957\u9910: ${data.plan}\uFF09`);
24984
+ activated = true;
24985
+ } else {
24986
+ results.push(`\u26A0\uFE0F License \u6FC0\u6D3B\u5931\u8D25: ${JSON.stringify(data)}`);
24987
+ }
24988
+ } catch (err) {
24989
+ results.push(`\u26A0\uFE0F \u6FC0\u6D3B\u7F51\u7EDC\u9519\u8BEF: ${err instanceof Error ? err.message : err}`);
24990
+ }
24991
+ }
24992
+ await writeState(state);
24993
+ results.push("\u2705 state.json");
24994
+ if (state.credentials?.token) {
24995
+ try {
24996
+ const pullResult = await syncPull({ workDir: cwd });
24997
+ if (pullResult.success) {
24998
+ results.push("\u2705 \u5DF2\u4ECE\u4E91\u7AEF\u540C\u6B65\u6570\u636E");
24999
+ } else {
25000
+ results.push("\u2139\uFE0F \u4E91\u7AEF\u65E0\u5DF2\u6709\u6570\u636E");
25001
+ }
25002
+ } catch {
25003
+ results.push("\u2139\uFE0F \u4E91\u7AEF\u540C\u6B65\u8DF3\u8FC7");
25004
+ }
25005
+ }
25006
+ return {
25007
+ success: true,
25008
+ message: [
25009
+ "\u{1F389} ClaudeInk \u77E5\u8BC6\u5E93\u521D\u59CB\u5316\u5B8C\u6210\uFF01",
25010
+ "",
25011
+ ...results,
25012
+ "",
25013
+ "\u{1F3AF} \u4E0B\u4E00\u6B65\uFF1A",
25014
+ "1. \u5728\u5BF9\u8BDD\u4E2D\u8BF4\u300C\u5E2E\u6211\u5B58\u4E00\u4E0B\u300D\u4FDD\u5B58\u6709\u4EF7\u503C\u5185\u5BB9",
25015
+ "2. \u7528\u300C\u627E\u4E00\u4E0B\u5173\u4E8E XX \u7684\u300D\u68C0\u7D22\u77E5\u8BC6\u5E93"
25016
+ ].join("\n")
25017
+ };
25018
+ } catch (err) {
25019
+ return {
25020
+ success: false,
25021
+ message: `\u521D\u59CB\u5316\u5931\u8D25: ${err instanceof Error ? err.message : err}`
25022
+ };
25023
+ }
25024
+ }
25025
+
24974
25026
  // src/tools/ink.ts
24975
- var inkWriteSchema = external_exports.object({
24976
- 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"),
24977
- title: external_exports.string().describe("\u6807\u9898"),
25027
+ import { readFile as readFile3 } from "fs/promises";
25028
+ import { extname } from "path";
25029
+
25030
+ // src/lib/push.ts
25031
+ function fireAndForgetPush(payload) {
25032
+ doPush(payload).catch(() => {
25033
+ });
25034
+ }
25035
+ async function doPush(partial2) {
25036
+ const creds = await getCredentials();
25037
+ if (!creds?.token) return;
25038
+ const config2 = await getConfig();
25039
+ const payload = {
25040
+ knowledge: partial2.knowledge || [],
25041
+ crawlerSources: partial2.crawlerSources || []
25042
+ };
25043
+ await log("DEBUG", "push", `payload: ${partial2.knowledge?.length || 0} knowledge, ${partial2.crawlerSources?.length || 0} sources`);
25044
+ try {
25045
+ await fetch(`${config2.apiBaseUrl}/api/sync/batch`, {
25046
+ method: "POST",
25047
+ headers: {
25048
+ "Content-Type": "application/json",
25049
+ Authorization: `Bearer ${creds.token}`
25050
+ },
25051
+ body: JSON.stringify(payload)
25052
+ });
25053
+ } catch (err) {
25054
+ await log("WARN", "push", `failed: ${err instanceof Error ? err.message : err}`);
25055
+ }
25056
+ }
25057
+
25058
+ // src/tools/ink.ts
25059
+ var inkSaveSchema = external_exports.object({
25060
+ 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"),
25061
+ title: external_exports.string().describe("\u7D20\u6750\u6807\u9898"),
24978
25062
  content: external_exports.string().describe("Markdown \u5168\u6587"),
24979
25063
  tags: external_exports.array(external_exports.string()).optional().default([]).describe("\u6807\u7B7E"),
24980
25064
  category: external_exports.enum(["insight", "decision", "analysis", "idea", "reference", "action"]).optional().default("reference").describe("\u5206\u7C7B"),
24981
25065
  source_type: external_exports.enum(["conversation", "url", "manual"]).optional().default("conversation").describe("\u6765\u6E90\u7C7B\u578B"),
24982
- url: external_exports.string().optional().describe("\u6765\u6E90 URL"),
25066
+ url: external_exports.string().optional().describe("\u6765\u6E90 URL")
25067
+ });
25068
+ async function inkSave(input) {
25069
+ try {
25070
+ let localId;
25071
+ if (input.id) {
25072
+ const result = await updateKnowledgeFile(input.id, {
25073
+ title: input.title,
25074
+ content: input.content,
25075
+ tags: input.tags,
25076
+ category: input.category
25077
+ }, "knowledge");
25078
+ if (!result) {
25079
+ return { success: false, message: `\u672A\u627E\u5230 ID \u4E3A ${input.id} \u7684\u7D20\u6750` };
25080
+ }
25081
+ localId = input.id;
25082
+ } else {
25083
+ const { id } = await saveKnowledge({
25084
+ content: input.content,
25085
+ title: input.title,
25086
+ tags: input.tags,
25087
+ category: input.category,
25088
+ source_type: input.source_type,
25089
+ url: input.url,
25090
+ store: "knowledge"
25091
+ });
25092
+ localId = id;
25093
+ }
25094
+ const creds = await getCredentials();
25095
+ if (creds?.token) {
25096
+ const index = await readIndex("knowledge");
25097
+ fireAndForgetPush({
25098
+ knowledge: Object.values(index.entries).map((e) => ({
25099
+ id: e.id,
25100
+ title: e.title,
25101
+ tags: e.tags,
25102
+ category: e.category,
25103
+ source_type: e.source_type,
25104
+ created_at: e.created_at,
25105
+ updated_at: e.updated_at
25106
+ })),
25107
+ crawlerSources: []
25108
+ });
25109
+ }
25110
+ await log("INFO", "ink.save", `saved source id=${localId} title="${input.title}"`);
25111
+ return {
25112
+ success: true,
25113
+ 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"),
25114
+ data: { id: localId }
25115
+ };
25116
+ } catch (err) {
25117
+ await log("ERROR", "ink.save", `failed: ${err.message}`);
25118
+ return { success: false, message: `\u4FDD\u5B58\u7D20\u6750\u5931\u8D25: ${err.message}` };
25119
+ }
25120
+ }
25121
+ var inkWriteSchema = external_exports.object({
25122
+ 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"),
25123
+ title: external_exports.string().describe("\u6587\u7AE0\u6807\u9898"),
25124
+ content: external_exports.string().describe("Markdown \u5168\u6587"),
25125
+ tags: external_exports.array(external_exports.string()).optional().default([]).describe("\u6807\u7B7E"),
25126
+ category: external_exports.enum(["insight", "decision", "analysis", "idea", "reference", "action"]).optional().default("reference").describe("\u5206\u7C7B"),
24983
25127
  cover: external_exports.string().optional().describe("\u5C01\u9762\u56FE\uFF08\u672C\u5730\u8DEF\u5F84\u6216 URL\uFF0C\u81EA\u52A8\u4E0A\u4F20\uFF09"),
24984
25128
  excerpt: external_exports.string().optional().describe("\u6458\u8981\uFF08\u4E0D\u586B\u81EA\u52A8\u622A\u53D6\u524D 200 \u5B57\uFF09"),
24985
25129
  source_ids: external_exports.array(external_exports.string()).optional().describe("\u5173\u8054\u7684\u7D20\u6750 ID\uFF08\u6EAF\u6E90\uFF09")
@@ -24993,9 +25137,9 @@ async function inkWrite(input) {
24993
25137
  content: input.content,
24994
25138
  tags: input.tags,
24995
25139
  category: input.category
24996
- });
25140
+ }, "drafts");
24997
25141
  if (!result) {
24998
- return { success: false, message: `\u672A\u627E\u5230 ID \u4E3A ${input.id} \u7684\u672C\u5730\u6761\u76EE` };
25142
+ return { success: false, message: `\u672A\u627E\u5230 ID \u4E3A ${input.id} \u7684\u8349\u7A3F` };
24999
25143
  }
25000
25144
  localId = input.id;
25001
25145
  } else {
@@ -25004,17 +25148,17 @@ async function inkWrite(input) {
25004
25148
  title: input.title,
25005
25149
  tags: input.tags,
25006
25150
  category: input.category,
25007
- source_type: input.source_type,
25008
- url: input.url
25151
+ source_type: "conversation",
25152
+ store: "drafts"
25009
25153
  });
25010
25154
  localId = id;
25011
25155
  }
25012
25156
  const creds = await getCredentials();
25013
25157
  if (!creds?.token) {
25014
- await log("INFO", "ink.write", `saved locally id=${localId} title="${input.title}" (no cloud auth)`);
25158
+ await log("INFO", "ink.write", `saved draft locally id=${localId} title="${input.title}" (no cloud auth)`);
25015
25159
  return {
25016
25160
  success: true,
25017
- message: `\u5DF2\u4FDD\u5B58\u300C${input.title}\u300D\u5230\u672C\u5730\uFF08\u672A\u767B\u5F55\uFF0C\u8DF3\u8FC7\u4E91\u7AEF\u540C\u6B65\uFF09`,
25161
+ 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`,
25018
25162
  data: { id: localId }
25019
25163
  };
25020
25164
  }
@@ -25036,55 +25180,69 @@ async function inkWrite(input) {
25036
25180
  }
25037
25181
  const slug = `${Date.now().toString(36)}-${input.title.toLowerCase().replace(/[^a-z0-9\u4e00-\u9fff]+/g, "-").replace(/^-|-$/g, "").slice(0, 60)}`;
25038
25182
  const excerpt = input.excerpt || input.content.replace(/^#+\s.+$/gm, "").replace(/\n+/g, " ").trim().slice(0, 200);
25039
- const res = await fetch(`${config2.apiBaseUrl}/api/blog/manage`, {
25040
- method: "POST",
25041
- headers: {
25042
- "Content-Type": "application/json",
25043
- Authorization: `Bearer ${creds.token}`
25044
- },
25045
- body: JSON.stringify({
25046
- title: input.title,
25047
- slug,
25048
- content: input.content,
25049
- cover_url: coverUrl,
25050
- tags: input.tags,
25051
- category: input.category,
25052
- excerpt,
25053
- source_type: input.source_type,
25054
- url: input.url,
25055
- source_ids: input.source_ids,
25056
- local_id: localId
25057
- })
25058
- });
25059
- if (!res.ok) {
25060
- const err = await res.text();
25061
- await log("ERROR", "ink.write", `cloud save failed: ${err}`);
25183
+ try {
25184
+ const controller = new AbortController();
25185
+ const timeout = setTimeout(() => controller.abort(), 1e4);
25186
+ const res = await fetch(`${config2.apiBaseUrl}/api/blog/manage`, {
25187
+ method: "POST",
25188
+ signal: controller.signal,
25189
+ headers: {
25190
+ "Content-Type": "application/json",
25191
+ Authorization: `Bearer ${creds.token}`
25192
+ },
25193
+ body: JSON.stringify({
25194
+ title: input.title,
25195
+ slug,
25196
+ content: input.content,
25197
+ cover_url: coverUrl,
25198
+ tags: input.tags,
25199
+ category: input.category,
25200
+ excerpt,
25201
+ source_type: "conversation",
25202
+ source_ids: input.source_ids,
25203
+ local_id: localId
25204
+ })
25205
+ });
25206
+ clearTimeout(timeout);
25207
+ if (!res.ok) {
25208
+ const err = await res.text();
25209
+ await log("ERROR", "ink.write", `cloud save failed: ${err}`);
25210
+ return {
25211
+ success: true,
25212
+ message: `\u5DF2\u4FDD\u5B58\u8349\u7A3F\u300C${input.title}\u300D\u5230\u672C\u5730\uFF0C\u4F46\u4E91\u7AEF\u540C\u6B65\u5931\u8D25: ${err}`,
25213
+ data: { id: localId }
25214
+ };
25215
+ }
25216
+ const data = await res.json();
25217
+ await log("INFO", "ink.write", `saved draft id=${localId} cloud_id=${data.id} title="${input.title}"`);
25062
25218
  return {
25063
25219
  success: true,
25064
- message: `\u5DF2\u4FDD\u5B58\u300C${input.title}\u300D\u5230\u672C\u5730\uFF0C\u4F46\u4E91\u7AEF\u540C\u6B65\u5931\u8D25: ${err}`,
25220
+ message: `\u5DF2\u4FDD\u5B58\u8349\u7A3F\u300C${input.title}\u300D\uFF08\u672C\u5730 + \u4E91\u7AEF\uFF09`,
25221
+ data: { id: localId, cloud_id: data.id, slug: data.slug, status: data.status }
25222
+ };
25223
+ } catch (cloudErr) {
25224
+ await log("WARN", "ink.write", `cloud upload failed (local saved): ${cloudErr.message}`);
25225
+ return {
25226
+ success: true,
25227
+ message: `\u5DF2\u4FDD\u5B58\u8349\u7A3F\u300C${input.title}\u300D\u5230\u672C\u5730\uFF0C\u4F46\u4E91\u7AEF\u540C\u6B65\u5931\u8D25: ${cloudErr.message}`,
25065
25228
  data: { id: localId }
25066
25229
  };
25067
25230
  }
25068
- const data = await res.json();
25069
- await log("INFO", "ink.write", `saved id=${localId} cloud_id=${data.id} title="${input.title}"`);
25070
- return {
25071
- success: true,
25072
- message: `\u5DF2\u4FDD\u5B58\u300C${input.title}\u300D\uFF08\u672C\u5730 + \u4E91\u7AEF\uFF09`,
25073
- data: { id: localId, cloud_id: data.id, slug: data.slug, status: data.status }
25074
- };
25075
25231
  } catch (err) {
25076
25232
  await log("ERROR", "ink.write", `failed: ${err.message}`);
25077
- return { success: false, message: `\u4FDD\u5B58\u5931\u8D25: ${err.message}` };
25233
+ return { success: false, message: `\u4FDD\u5B58\u8349\u7A3F\u5931\u8D25: ${err.message}` };
25078
25234
  }
25079
25235
  }
25080
25236
  var inkDeleteSchema = external_exports.object({
25081
25237
  id: external_exports.string().describe("\u6761\u76EE ID"),
25238
+ 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"),
25082
25239
  confirm: external_exports.boolean().optional().default(false).describe("\u786E\u8BA4\u5220\u9664\uFF08\u5FC5\u987B\u4E3A true \u624D\u4F1A\u6267\u884C\u5220\u9664\uFF09")
25083
25240
  });
25084
25241
  async function inkDelete(input) {
25085
25242
  try {
25243
+ const store = input.store;
25086
25244
  if (!input.confirm) {
25087
- const index = await readIndex();
25245
+ const index = await readIndex(store);
25088
25246
  const entry = index.entries[input.id];
25089
25247
  if (!entry) {
25090
25248
  return { success: false, message: `\u672A\u627E\u5230 ID \u4E3A ${input.id} \u7684\u6761\u76EE` };
@@ -25092,10 +25250,10 @@ async function inkDelete(input) {
25092
25250
  return {
25093
25251
  success: false,
25094
25252
  message: `\u786E\u8BA4\u5220\u9664\u300C${entry.title}\u300D\uFF1F\u8BF7\u5C06 confirm \u8BBE\u4E3A true \u4EE5\u786E\u8BA4\u5220\u9664\u3002`,
25095
- data: { id: entry.id, title: entry.title, category: entry.category, tags: entry.tags }
25253
+ data: { id: entry.id, title: entry.title, store, category: entry.category, tags: entry.tags }
25096
25254
  };
25097
25255
  }
25098
- const deleted = await deleteKnowledgeFile(input.id);
25256
+ const deleted = await deleteKnowledgeFile(input.id, store);
25099
25257
  if (!deleted) {
25100
25258
  return { success: false, message: `\u672A\u627E\u5230 ID \u4E3A ${input.id} \u7684\u6761\u76EE` };
25101
25259
  }
@@ -25114,7 +25272,7 @@ async function inkDelete(input) {
25114
25272
  }
25115
25273
  } catch {
25116
25274
  }
25117
- await log("INFO", "ink.delete", `deleted id=${input.id}`);
25275
+ await log("INFO", "ink.delete", `deleted id=${input.id} store=${store}`);
25118
25276
  return { success: true, message: `\u5DF2\u5220\u9664 ${input.id}`, data: { id: input.id } };
25119
25277
  } catch (err) {
25120
25278
  await log("ERROR", "ink.delete", `failed: ${err.message}`);
@@ -25129,7 +25287,7 @@ var inkTagsSchema = external_exports.object({
25129
25287
  });
25130
25288
  async function inkTags(input) {
25131
25289
  try {
25132
- const index = await readIndex();
25290
+ const index = await readIndex("knowledge");
25133
25291
  switch (input.action) {
25134
25292
  case "list": {
25135
25293
  const tags = getAllTags(index);
@@ -25143,7 +25301,7 @@ async function inkTags(input) {
25143
25301
  if (!input.tag || !input.new_tag) {
25144
25302
  return { success: false, message: "rename \u9700\u8981 tag\uFF08\u539F\u6807\u7B7E\uFF09\u548C new_tag\uFF08\u65B0\u6807\u7B7E\u540D\uFF09" };
25145
25303
  }
25146
- const count = await renameTag(input.tag, input.new_tag);
25304
+ const count = await renameTag(input.tag, input.new_tag, "knowledge");
25147
25305
  if (count === 0) {
25148
25306
  return { success: false, message: `\u672A\u627E\u5230\u4F7F\u7528\u6807\u7B7E\u300C${input.tag}\u300D\u7684\u6761\u76EE` };
25149
25307
  }
@@ -25158,7 +25316,7 @@ async function inkTags(input) {
25158
25316
  if (!input.source_tags || input.source_tags.length === 0 || !input.new_tag) {
25159
25317
  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" };
25160
25318
  }
25161
- const count = await mergeTags(input.source_tags, input.new_tag);
25319
+ const count = await mergeTags(input.source_tags, input.new_tag, "knowledge");
25162
25320
  if (count === 0) {
25163
25321
  return { success: false, message: "\u672A\u627E\u5230\u4F7F\u7528\u8FD9\u4E9B\u6807\u7B7E\u7684\u6761\u76EE" };
25164
25322
  }
@@ -25234,46 +25392,16 @@ async function uploadImageFromUrl(imageUrl, type, token, apiBase) {
25234
25392
  // src/tools/source.ts
25235
25393
  var import_gray_matter2 = __toESM(require_gray_matter(), 1);
25236
25394
  import { readFile as readFile4 } from "fs/promises";
25237
- import { join as join5 } from "path";
25395
+ import { join as join6 } from "path";
25238
25396
  import { readdirSync } from "fs";
25239
25397
  import { execSync } from "child_process";
25240
-
25241
- // src/lib/push.ts
25242
- function fireAndForgetPush(payload) {
25243
- doPush(payload).catch(() => {
25244
- });
25245
- }
25246
- async function doPush(partial2) {
25247
- const creds = await getCredentials();
25248
- if (!creds?.token) return;
25249
- const config2 = await getConfig();
25250
- const payload = {
25251
- knowledge: partial2.knowledge || [],
25252
- crawlerSources: partial2.crawlerSources || []
25253
- };
25254
- await log("DEBUG", "push", `payload: ${partial2.knowledge?.length || 0} knowledge, ${partial2.crawlerSources?.length || 0} sources`);
25255
- try {
25256
- await fetch(`${config2.apiBaseUrl}/api/sync/batch`, {
25257
- method: "POST",
25258
- headers: {
25259
- "Content-Type": "application/json",
25260
- Authorization: `Bearer ${creds.token}`
25261
- },
25262
- body: JSON.stringify(payload)
25263
- });
25264
- } catch (err) {
25265
- await log("WARN", "push", `failed: ${err instanceof Error ? err.message : err}`);
25266
- }
25267
- }
25268
-
25269
- // src/tools/source.ts
25270
25398
  var sourceCrawlSchema = external_exports.object({
25271
25399
  sourceId: external_exports.string().optional().describe("\u6307\u5B9A\u722C\u866B\u6E90\u540D\u79F0\uFF0C\u4E0D\u4F20\u5219\u5168\u91CF")
25272
25400
  });
25273
25401
  async function sourceCrawl(input) {
25274
25402
  const config2 = await getConfig();
25275
- const crawlerDir = join5(config2.workflowDir || process.cwd(), "tools", "crawler");
25276
- const configPath = join5(crawlerDir, "config.json");
25403
+ const crawlerDir = join6(config2.workflowDir || process.cwd(), "tools", "crawler");
25404
+ const configPath = join6(crawlerDir, "config.json");
25277
25405
  let crawlerConfig;
25278
25406
  try {
25279
25407
  crawlerConfig = JSON.parse(await readFile4(configPath, "utf-8"));
@@ -25290,7 +25418,7 @@ async function sourceCrawl(input) {
25290
25418
  message: input.sourceId ? `\u672A\u627E\u5230\u722C\u866B\u6E90: ${input.sourceId}` : "\u6CA1\u6709\u5DF2\u542F\u7528\u7684\u722C\u866B\u6E90"
25291
25419
  };
25292
25420
  }
25293
- const crawlScript = join5(crawlerDir, "crawl.mjs");
25421
+ const crawlScript = join6(crawlerDir, "crawl.mjs");
25294
25422
  const args = input.sourceId ? `--source ${input.sourceId}` : "";
25295
25423
  try {
25296
25424
  execSync(`node "${crawlScript}" ${args}`, {
@@ -25302,7 +25430,7 @@ async function sourceCrawl(input) {
25302
25430
  let saved = 0;
25303
25431
  let queued = 0;
25304
25432
  for (const target of targets) {
25305
- const sourceDir = join5(config2.workflowDir, "sources", "articles", target.id);
25433
+ const sourceDir = join6(config2.workflowDir, "sources", "articles", target.id);
25306
25434
  let files;
25307
25435
  try {
25308
25436
  files = readdirSync(sourceDir).filter((f) => f.endsWith(".md"));
@@ -25310,7 +25438,7 @@ async function sourceCrawl(input) {
25310
25438
  continue;
25311
25439
  }
25312
25440
  for (const f of files) {
25313
- const filePath = join5(sourceDir, f);
25441
+ const filePath = join6(sourceDir, f);
25314
25442
  try {
25315
25443
  const raw = await readFile4(filePath, "utf-8");
25316
25444
  const { data, content } = (0, import_gray_matter2.default)(raw);
@@ -25371,8 +25499,8 @@ async function sourceCrawl(input) {
25371
25499
  }
25372
25500
 
25373
25501
  // src/tools/subscribe.ts
25374
- import { readFile as readFile5, writeFile as writeFile3, mkdir as mkdir5 } from "fs/promises";
25375
- import { join as join6 } from "path";
25502
+ import { readFile as readFile5, writeFile as writeFile4, mkdir as mkdir6 } from "fs/promises";
25503
+ import { join as join7 } from "path";
25376
25504
  var sourceSubscribeSchema = external_exports.object({
25377
25505
  action: external_exports.enum(["add", "remove", "list"]).describe("\u64CD\u4F5C\u7C7B\u578B"),
25378
25506
  id: external_exports.string().optional().describe("\u8BA2\u9605\u6E90 ID"),
@@ -25401,9 +25529,9 @@ async function readCrawlerConfig(configPath) {
25401
25529
  }
25402
25530
  async function sourceSubscribe(input) {
25403
25531
  const config2 = await getConfig();
25404
- const crawlerDir = join6(config2.workflowDir || process.cwd(), "tools", "crawler");
25405
- await mkdir5(crawlerDir, { recursive: true });
25406
- const configPath = join6(crawlerDir, "config.json");
25532
+ const crawlerDir = join7(config2.workflowDir || process.cwd(), "tools", "crawler");
25533
+ await mkdir6(crawlerDir, { recursive: true });
25534
+ const configPath = join7(crawlerDir, "config.json");
25407
25535
  const crawlerConfig = await readCrawlerConfig(configPath);
25408
25536
  if (input.action === "list") {
25409
25537
  return {
@@ -25435,7 +25563,7 @@ async function sourceSubscribe(input) {
25435
25563
  if (input.crawlConfig.maxArticles) newSource.maxArticles = input.crawlConfig.maxArticles;
25436
25564
  }
25437
25565
  crawlerConfig.sources.push(newSource);
25438
- await writeFile3(configPath, JSON.stringify(crawlerConfig, null, 2));
25566
+ await writeFile4(configPath, JSON.stringify(crawlerConfig, null, 2));
25439
25567
  fireAndForgetPush({
25440
25568
  crawlerSources: crawlerConfig.sources.map((s) => ({
25441
25569
  id: s.id,
@@ -25453,7 +25581,7 @@ async function sourceSubscribe(input) {
25453
25581
  return { success: false, message: "\u5220\u9664\u8BA2\u9605\u6E90\u9700\u8981 id \u53C2\u6570" };
25454
25582
  }
25455
25583
  crawlerConfig.sources = crawlerConfig.sources.filter((s) => s.id !== input.id);
25456
- await writeFile3(configPath, JSON.stringify(crawlerConfig, null, 2));
25584
+ await writeFile4(configPath, JSON.stringify(crawlerConfig, null, 2));
25457
25585
  fireAndForgetPush({
25458
25586
  crawlerSources: crawlerConfig.sources.map((s) => ({
25459
25587
  id: s.id,
@@ -25472,7 +25600,7 @@ async function sourceSubscribe(input) {
25472
25600
  // src/index.ts
25473
25601
  var server = new McpServer({
25474
25602
  name: "ClaudeInk",
25475
- version: "2.1.0"
25603
+ version: "2.2.0"
25476
25604
  });
25477
25605
  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) => {
25478
25606
  const result = await workflowInit(input);
@@ -25482,7 +25610,11 @@ server.tool("ink.sync", "\u4ECE\u4E91\u7AEF\u540C\u6B65\u77E5\u8BC6\u5143\u6570\
25482
25610
  const result = await sync(input);
25483
25611
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
25484
25612
  });
25485
- 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) => {
25613
+ 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) => {
25614
+ const result = await inkSave(input);
25615
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
25616
+ });
25617
+ 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) => {
25486
25618
  const result = await inkWrite(input);
25487
25619
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
25488
25620
  });