@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.
- package/dist/cli.js +461 -327
- package/dist/index.js +416 -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,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
|
-
|
|
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 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\
|
|
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:
|
|
25008
|
-
|
|
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
|
-
|
|
25040
|
-
|
|
25041
|
-
|
|
25042
|
-
|
|
25043
|
-
|
|
25044
|
-
|
|
25045
|
-
|
|
25046
|
-
|
|
25047
|
-
|
|
25048
|
-
|
|
25049
|
-
|
|
25050
|
-
|
|
25051
|
-
|
|
25052
|
-
|
|
25053
|
-
|
|
25054
|
-
|
|
25055
|
-
|
|
25056
|
-
|
|
25057
|
-
|
|
25058
|
-
|
|
25059
|
-
|
|
25060
|
-
|
|
25061
|
-
|
|
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\
|
|
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
|
|
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 =
|
|
25276
|
-
const configPath =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
25375
|
-
import { join as
|
|
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 =
|
|
25405
|
-
await
|
|
25406
|
-
const configPath =
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
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
|
});
|