@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.
- package/dist/cli.js +462 -327
- package/dist/index.js +417 -284
- 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
|
|
24481
|
-
import { join as
|
|
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
|
-
|
|
24600
|
-
|
|
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
|
|
24732
|
-
import { join as
|
|
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
|
|
24743
|
-
return
|
|
24596
|
+
function getStoreDir(store = "knowledge") {
|
|
24597
|
+
return join2(getWorkDir(), ".claudeink", store);
|
|
24744
24598
|
}
|
|
24745
|
-
function getIndexPath() {
|
|
24746
|
-
return
|
|
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 =
|
|
24779
|
-
await
|
|
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 =
|
|
24786
|
-
await
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
24748
|
+
const filePath = join2(getStoreDir(store), entry.file_path);
|
|
24894
24749
|
try {
|
|
24895
|
-
await
|
|
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 =
|
|
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 =
|
|
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,311 @@ 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
|
-
|
|
24976
|
-
|
|
24977
|
-
|
|
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 now = (/* @__PURE__ */ new Date()).toISOString();
|
|
25097
|
+
fireAndForgetPush({
|
|
25098
|
+
knowledge: [{
|
|
25099
|
+
id: localId,
|
|
25100
|
+
title: input.title,
|
|
25101
|
+
tags: input.tags || [],
|
|
25102
|
+
category: input.category || "reference",
|
|
25103
|
+
source_type: input.source_type || "conversation",
|
|
25104
|
+
url: input.url,
|
|
25105
|
+
created_at: now,
|
|
25106
|
+
updated_at: now
|
|
25107
|
+
}],
|
|
25108
|
+
crawlerSources: []
|
|
25109
|
+
});
|
|
25110
|
+
}
|
|
25111
|
+
await log("INFO", "ink.save", `saved source id=${localId} title="${input.title}"`);
|
|
25112
|
+
return {
|
|
25113
|
+
success: true,
|
|
25114
|
+
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"),
|
|
25115
|
+
data: { id: localId }
|
|
25116
|
+
};
|
|
25117
|
+
} catch (err) {
|
|
25118
|
+
await log("ERROR", "ink.save", `failed: ${err.message}`);
|
|
25119
|
+
return { success: false, message: `\u4FDD\u5B58\u7D20\u6750\u5931\u8D25: ${err.message}` };
|
|
25120
|
+
}
|
|
25121
|
+
}
|
|
25122
|
+
var inkWriteSchema = external_exports.object({
|
|
25123
|
+
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"),
|
|
25124
|
+
title: external_exports.string().describe("\u6587\u7AE0\u6807\u9898"),
|
|
25125
|
+
content: external_exports.string().describe("Markdown \u5168\u6587"),
|
|
25126
|
+
tags: external_exports.array(external_exports.string()).optional().default([]).describe("\u6807\u7B7E"),
|
|
25127
|
+
category: external_exports.enum(["insight", "decision", "analysis", "idea", "reference", "action"]).optional().default("reference").describe("\u5206\u7C7B"),
|
|
24983
25128
|
cover: external_exports.string().optional().describe("\u5C01\u9762\u56FE\uFF08\u672C\u5730\u8DEF\u5F84\u6216 URL\uFF0C\u81EA\u52A8\u4E0A\u4F20\uFF09"),
|
|
24984
25129
|
excerpt: external_exports.string().optional().describe("\u6458\u8981\uFF08\u4E0D\u586B\u81EA\u52A8\u622A\u53D6\u524D 200 \u5B57\uFF09"),
|
|
24985
25130
|
source_ids: external_exports.array(external_exports.string()).optional().describe("\u5173\u8054\u7684\u7D20\u6750 ID\uFF08\u6EAF\u6E90\uFF09")
|
|
@@ -24993,9 +25138,9 @@ async function inkWrite(input) {
|
|
|
24993
25138
|
content: input.content,
|
|
24994
25139
|
tags: input.tags,
|
|
24995
25140
|
category: input.category
|
|
24996
|
-
});
|
|
25141
|
+
}, "drafts");
|
|
24997
25142
|
if (!result) {
|
|
24998
|
-
return { success: false, message: `\u672A\u627E\u5230 ID \u4E3A ${input.id} \u7684\
|
|
25143
|
+
return { success: false, message: `\u672A\u627E\u5230 ID \u4E3A ${input.id} \u7684\u8349\u7A3F` };
|
|
24999
25144
|
}
|
|
25000
25145
|
localId = input.id;
|
|
25001
25146
|
} else {
|
|
@@ -25004,17 +25149,17 @@ async function inkWrite(input) {
|
|
|
25004
25149
|
title: input.title,
|
|
25005
25150
|
tags: input.tags,
|
|
25006
25151
|
category: input.category,
|
|
25007
|
-
source_type:
|
|
25008
|
-
|
|
25152
|
+
source_type: "conversation",
|
|
25153
|
+
store: "drafts"
|
|
25009
25154
|
});
|
|
25010
25155
|
localId = id;
|
|
25011
25156
|
}
|
|
25012
25157
|
const creds = await getCredentials();
|
|
25013
25158
|
if (!creds?.token) {
|
|
25014
|
-
await log("INFO", "ink.write", `saved locally id=${localId} title="${input.title}" (no cloud auth)`);
|
|
25159
|
+
await log("INFO", "ink.write", `saved draft locally id=${localId} title="${input.title}" (no cloud auth)`);
|
|
25015
25160
|
return {
|
|
25016
25161
|
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`,
|
|
25162
|
+
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
25163
|
data: { id: localId }
|
|
25019
25164
|
};
|
|
25020
25165
|
}
|
|
@@ -25036,55 +25181,69 @@ async function inkWrite(input) {
|
|
|
25036
25181
|
}
|
|
25037
25182
|
const slug = `${Date.now().toString(36)}-${input.title.toLowerCase().replace(/[^a-z0-9\u4e00-\u9fff]+/g, "-").replace(/^-|-$/g, "").slice(0, 60)}`;
|
|
25038
25183
|
const excerpt = input.excerpt || input.content.replace(/^#+\s.+$/gm, "").replace(/\n+/g, " ").trim().slice(0, 200);
|
|
25039
|
-
|
|
25040
|
-
|
|
25041
|
-
|
|
25042
|
-
|
|
25043
|
-
|
|
25044
|
-
|
|
25045
|
-
|
|
25046
|
-
|
|
25047
|
-
|
|
25048
|
-
|
|
25049
|
-
|
|
25050
|
-
|
|
25051
|
-
|
|
25052
|
-
|
|
25053
|
-
|
|
25054
|
-
|
|
25055
|
-
|
|
25056
|
-
|
|
25057
|
-
|
|
25058
|
-
|
|
25059
|
-
|
|
25060
|
-
|
|
25061
|
-
|
|
25184
|
+
try {
|
|
25185
|
+
const controller = new AbortController();
|
|
25186
|
+
const timeout = setTimeout(() => controller.abort(), 1e4);
|
|
25187
|
+
const res = await fetch(`${config2.apiBaseUrl}/api/blog/manage`, {
|
|
25188
|
+
method: "POST",
|
|
25189
|
+
signal: controller.signal,
|
|
25190
|
+
headers: {
|
|
25191
|
+
"Content-Type": "application/json",
|
|
25192
|
+
Authorization: `Bearer ${creds.token}`
|
|
25193
|
+
},
|
|
25194
|
+
body: JSON.stringify({
|
|
25195
|
+
title: input.title,
|
|
25196
|
+
slug,
|
|
25197
|
+
content: input.content,
|
|
25198
|
+
cover_url: coverUrl,
|
|
25199
|
+
tags: input.tags,
|
|
25200
|
+
category: input.category,
|
|
25201
|
+
excerpt,
|
|
25202
|
+
source_type: "conversation",
|
|
25203
|
+
source_ids: input.source_ids,
|
|
25204
|
+
local_id: localId
|
|
25205
|
+
})
|
|
25206
|
+
});
|
|
25207
|
+
clearTimeout(timeout);
|
|
25208
|
+
if (!res.ok) {
|
|
25209
|
+
const err = await res.text();
|
|
25210
|
+
await log("ERROR", "ink.write", `cloud save failed: ${err}`);
|
|
25211
|
+
return {
|
|
25212
|
+
success: true,
|
|
25213
|
+
message: `\u5DF2\u4FDD\u5B58\u8349\u7A3F\u300C${input.title}\u300D\u5230\u672C\u5730\uFF0C\u4F46\u4E91\u7AEF\u540C\u6B65\u5931\u8D25: ${err}`,
|
|
25214
|
+
data: { id: localId }
|
|
25215
|
+
};
|
|
25216
|
+
}
|
|
25217
|
+
const data = await res.json();
|
|
25218
|
+
await log("INFO", "ink.write", `saved draft id=${localId} cloud_id=${data.id} title="${input.title}"`);
|
|
25062
25219
|
return {
|
|
25063
25220
|
success: true,
|
|
25064
|
-
message: `\u5DF2\u4FDD\u5B58\u300C${input.title}\u300D\
|
|
25221
|
+
message: `\u5DF2\u4FDD\u5B58\u8349\u7A3F\u300C${input.title}\u300D\uFF08\u672C\u5730 + \u4E91\u7AEF\uFF09`,
|
|
25222
|
+
data: { id: localId, cloud_id: data.id, slug: data.slug, status: data.status }
|
|
25223
|
+
};
|
|
25224
|
+
} catch (cloudErr) {
|
|
25225
|
+
await log("WARN", "ink.write", `cloud upload failed (local saved): ${cloudErr.message}`);
|
|
25226
|
+
return {
|
|
25227
|
+
success: true,
|
|
25228
|
+
message: `\u5DF2\u4FDD\u5B58\u8349\u7A3F\u300C${input.title}\u300D\u5230\u672C\u5730\uFF0C\u4F46\u4E91\u7AEF\u540C\u6B65\u5931\u8D25: ${cloudErr.message}`,
|
|
25065
25229
|
data: { id: localId }
|
|
25066
25230
|
};
|
|
25067
25231
|
}
|
|
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
25232
|
} catch (err) {
|
|
25076
25233
|
await log("ERROR", "ink.write", `failed: ${err.message}`);
|
|
25077
|
-
return { success: false, message: `\u4FDD\u5B58\u5931\u8D25: ${err.message}` };
|
|
25234
|
+
return { success: false, message: `\u4FDD\u5B58\u8349\u7A3F\u5931\u8D25: ${err.message}` };
|
|
25078
25235
|
}
|
|
25079
25236
|
}
|
|
25080
25237
|
var inkDeleteSchema = external_exports.object({
|
|
25081
25238
|
id: external_exports.string().describe("\u6761\u76EE ID"),
|
|
25239
|
+
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
25240
|
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
25241
|
});
|
|
25084
25242
|
async function inkDelete(input) {
|
|
25085
25243
|
try {
|
|
25244
|
+
const store = input.store;
|
|
25086
25245
|
if (!input.confirm) {
|
|
25087
|
-
const index = await readIndex();
|
|
25246
|
+
const index = await readIndex(store);
|
|
25088
25247
|
const entry = index.entries[input.id];
|
|
25089
25248
|
if (!entry) {
|
|
25090
25249
|
return { success: false, message: `\u672A\u627E\u5230 ID \u4E3A ${input.id} \u7684\u6761\u76EE` };
|
|
@@ -25092,10 +25251,10 @@ async function inkDelete(input) {
|
|
|
25092
25251
|
return {
|
|
25093
25252
|
success: false,
|
|
25094
25253
|
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 }
|
|
25254
|
+
data: { id: entry.id, title: entry.title, store, category: entry.category, tags: entry.tags }
|
|
25096
25255
|
};
|
|
25097
25256
|
}
|
|
25098
|
-
const deleted = await deleteKnowledgeFile(input.id);
|
|
25257
|
+
const deleted = await deleteKnowledgeFile(input.id, store);
|
|
25099
25258
|
if (!deleted) {
|
|
25100
25259
|
return { success: false, message: `\u672A\u627E\u5230 ID \u4E3A ${input.id} \u7684\u6761\u76EE` };
|
|
25101
25260
|
}
|
|
@@ -25114,7 +25273,7 @@ async function inkDelete(input) {
|
|
|
25114
25273
|
}
|
|
25115
25274
|
} catch {
|
|
25116
25275
|
}
|
|
25117
|
-
await log("INFO", "ink.delete", `deleted id=${input.id}`);
|
|
25276
|
+
await log("INFO", "ink.delete", `deleted id=${input.id} store=${store}`);
|
|
25118
25277
|
return { success: true, message: `\u5DF2\u5220\u9664 ${input.id}`, data: { id: input.id } };
|
|
25119
25278
|
} catch (err) {
|
|
25120
25279
|
await log("ERROR", "ink.delete", `failed: ${err.message}`);
|
|
@@ -25129,7 +25288,7 @@ var inkTagsSchema = external_exports.object({
|
|
|
25129
25288
|
});
|
|
25130
25289
|
async function inkTags(input) {
|
|
25131
25290
|
try {
|
|
25132
|
-
const index = await readIndex();
|
|
25291
|
+
const index = await readIndex("knowledge");
|
|
25133
25292
|
switch (input.action) {
|
|
25134
25293
|
case "list": {
|
|
25135
25294
|
const tags = getAllTags(index);
|
|
@@ -25143,7 +25302,7 @@ async function inkTags(input) {
|
|
|
25143
25302
|
if (!input.tag || !input.new_tag) {
|
|
25144
25303
|
return { success: false, message: "rename \u9700\u8981 tag\uFF08\u539F\u6807\u7B7E\uFF09\u548C new_tag\uFF08\u65B0\u6807\u7B7E\u540D\uFF09" };
|
|
25145
25304
|
}
|
|
25146
|
-
const count = await renameTag(input.tag, input.new_tag);
|
|
25305
|
+
const count = await renameTag(input.tag, input.new_tag, "knowledge");
|
|
25147
25306
|
if (count === 0) {
|
|
25148
25307
|
return { success: false, message: `\u672A\u627E\u5230\u4F7F\u7528\u6807\u7B7E\u300C${input.tag}\u300D\u7684\u6761\u76EE` };
|
|
25149
25308
|
}
|
|
@@ -25158,7 +25317,7 @@ async function inkTags(input) {
|
|
|
25158
25317
|
if (!input.source_tags || input.source_tags.length === 0 || !input.new_tag) {
|
|
25159
25318
|
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
25319
|
}
|
|
25161
|
-
const count = await mergeTags(input.source_tags, input.new_tag);
|
|
25320
|
+
const count = await mergeTags(input.source_tags, input.new_tag, "knowledge");
|
|
25162
25321
|
if (count === 0) {
|
|
25163
25322
|
return { success: false, message: "\u672A\u627E\u5230\u4F7F\u7528\u8FD9\u4E9B\u6807\u7B7E\u7684\u6761\u76EE" };
|
|
25164
25323
|
}
|
|
@@ -25234,46 +25393,16 @@ async function uploadImageFromUrl(imageUrl, type, token, apiBase) {
|
|
|
25234
25393
|
// src/tools/source.ts
|
|
25235
25394
|
var import_gray_matter2 = __toESM(require_gray_matter(), 1);
|
|
25236
25395
|
import { readFile as readFile4 } from "fs/promises";
|
|
25237
|
-
import { join as
|
|
25396
|
+
import { join as join6 } from "path";
|
|
25238
25397
|
import { readdirSync } from "fs";
|
|
25239
25398
|
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
25399
|
var sourceCrawlSchema = external_exports.object({
|
|
25271
25400
|
sourceId: external_exports.string().optional().describe("\u6307\u5B9A\u722C\u866B\u6E90\u540D\u79F0\uFF0C\u4E0D\u4F20\u5219\u5168\u91CF")
|
|
25272
25401
|
});
|
|
25273
25402
|
async function sourceCrawl(input) {
|
|
25274
25403
|
const config2 = await getConfig();
|
|
25275
|
-
const crawlerDir =
|
|
25276
|
-
const configPath =
|
|
25404
|
+
const crawlerDir = join6(config2.workflowDir || process.cwd(), "tools", "crawler");
|
|
25405
|
+
const configPath = join6(crawlerDir, "config.json");
|
|
25277
25406
|
let crawlerConfig;
|
|
25278
25407
|
try {
|
|
25279
25408
|
crawlerConfig = JSON.parse(await readFile4(configPath, "utf-8"));
|
|
@@ -25290,7 +25419,7 @@ async function sourceCrawl(input) {
|
|
|
25290
25419
|
message: input.sourceId ? `\u672A\u627E\u5230\u722C\u866B\u6E90: ${input.sourceId}` : "\u6CA1\u6709\u5DF2\u542F\u7528\u7684\u722C\u866B\u6E90"
|
|
25291
25420
|
};
|
|
25292
25421
|
}
|
|
25293
|
-
const crawlScript =
|
|
25422
|
+
const crawlScript = join6(crawlerDir, "crawl.mjs");
|
|
25294
25423
|
const args = input.sourceId ? `--source ${input.sourceId}` : "";
|
|
25295
25424
|
try {
|
|
25296
25425
|
execSync(`node "${crawlScript}" ${args}`, {
|
|
@@ -25302,7 +25431,7 @@ async function sourceCrawl(input) {
|
|
|
25302
25431
|
let saved = 0;
|
|
25303
25432
|
let queued = 0;
|
|
25304
25433
|
for (const target of targets) {
|
|
25305
|
-
const sourceDir =
|
|
25434
|
+
const sourceDir = join6(config2.workflowDir, "sources", "articles", target.id);
|
|
25306
25435
|
let files;
|
|
25307
25436
|
try {
|
|
25308
25437
|
files = readdirSync(sourceDir).filter((f) => f.endsWith(".md"));
|
|
@@ -25310,7 +25439,7 @@ async function sourceCrawl(input) {
|
|
|
25310
25439
|
continue;
|
|
25311
25440
|
}
|
|
25312
25441
|
for (const f of files) {
|
|
25313
|
-
const filePath =
|
|
25442
|
+
const filePath = join6(sourceDir, f);
|
|
25314
25443
|
try {
|
|
25315
25444
|
const raw = await readFile4(filePath, "utf-8");
|
|
25316
25445
|
const { data, content } = (0, import_gray_matter2.default)(raw);
|
|
@@ -25371,8 +25500,8 @@ async function sourceCrawl(input) {
|
|
|
25371
25500
|
}
|
|
25372
25501
|
|
|
25373
25502
|
// src/tools/subscribe.ts
|
|
25374
|
-
import { readFile as readFile5, writeFile as
|
|
25375
|
-
import { join as
|
|
25503
|
+
import { readFile as readFile5, writeFile as writeFile4, mkdir as mkdir6 } from "fs/promises";
|
|
25504
|
+
import { join as join7 } from "path";
|
|
25376
25505
|
var sourceSubscribeSchema = external_exports.object({
|
|
25377
25506
|
action: external_exports.enum(["add", "remove", "list"]).describe("\u64CD\u4F5C\u7C7B\u578B"),
|
|
25378
25507
|
id: external_exports.string().optional().describe("\u8BA2\u9605\u6E90 ID"),
|
|
@@ -25401,9 +25530,9 @@ async function readCrawlerConfig(configPath) {
|
|
|
25401
25530
|
}
|
|
25402
25531
|
async function sourceSubscribe(input) {
|
|
25403
25532
|
const config2 = await getConfig();
|
|
25404
|
-
const crawlerDir =
|
|
25405
|
-
await
|
|
25406
|
-
const configPath =
|
|
25533
|
+
const crawlerDir = join7(config2.workflowDir || process.cwd(), "tools", "crawler");
|
|
25534
|
+
await mkdir6(crawlerDir, { recursive: true });
|
|
25535
|
+
const configPath = join7(crawlerDir, "config.json");
|
|
25407
25536
|
const crawlerConfig = await readCrawlerConfig(configPath);
|
|
25408
25537
|
if (input.action === "list") {
|
|
25409
25538
|
return {
|
|
@@ -25435,7 +25564,7 @@ async function sourceSubscribe(input) {
|
|
|
25435
25564
|
if (input.crawlConfig.maxArticles) newSource.maxArticles = input.crawlConfig.maxArticles;
|
|
25436
25565
|
}
|
|
25437
25566
|
crawlerConfig.sources.push(newSource);
|
|
25438
|
-
await
|
|
25567
|
+
await writeFile4(configPath, JSON.stringify(crawlerConfig, null, 2));
|
|
25439
25568
|
fireAndForgetPush({
|
|
25440
25569
|
crawlerSources: crawlerConfig.sources.map((s) => ({
|
|
25441
25570
|
id: s.id,
|
|
@@ -25453,7 +25582,7 @@ async function sourceSubscribe(input) {
|
|
|
25453
25582
|
return { success: false, message: "\u5220\u9664\u8BA2\u9605\u6E90\u9700\u8981 id \u53C2\u6570" };
|
|
25454
25583
|
}
|
|
25455
25584
|
crawlerConfig.sources = crawlerConfig.sources.filter((s) => s.id !== input.id);
|
|
25456
|
-
await
|
|
25585
|
+
await writeFile4(configPath, JSON.stringify(crawlerConfig, null, 2));
|
|
25457
25586
|
fireAndForgetPush({
|
|
25458
25587
|
crawlerSources: crawlerConfig.sources.map((s) => ({
|
|
25459
25588
|
id: s.id,
|
|
@@ -25472,7 +25601,7 @@ async function sourceSubscribe(input) {
|
|
|
25472
25601
|
// src/index.ts
|
|
25473
25602
|
var server = new McpServer({
|
|
25474
25603
|
name: "ClaudeInk",
|
|
25475
|
-
version: "2.
|
|
25604
|
+
version: "2.2.0"
|
|
25476
25605
|
});
|
|
25477
25606
|
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
25607
|
const result = await workflowInit(input);
|
|
@@ -25482,7 +25611,11 @@ server.tool("ink.sync", "\u4ECE\u4E91\u7AEF\u540C\u6B65\u77E5\u8BC6\u5143\u6570\
|
|
|
25482
25611
|
const result = await sync(input);
|
|
25483
25612
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
25484
25613
|
});
|
|
25485
|
-
server.tool("ink.
|
|
25614
|
+
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) => {
|
|
25615
|
+
const result = await inkSave(input);
|
|
25616
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
25617
|
+
});
|
|
25618
|
+
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
25619
|
const result = await inkWrite(input);
|
|
25487
25620
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
25488
25621
|
});
|