@claudeink/mcp-server 1.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/cli.js +728 -940
  2. package/dist/index.js +523 -745
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -24510,11 +24510,11 @@ var require_core = __commonJS({
24510
24510
  Ajv2.ValidationError = validation_error_1.default;
24511
24511
  Ajv2.MissingRefError = ref_error_1.default;
24512
24512
  exports2.default = Ajv2;
24513
- function checkOptions(checkOpts, options2, msg, log = "error") {
24513
+ function checkOptions(checkOpts, options2, msg, log2 = "error") {
24514
24514
  for (const key in checkOpts) {
24515
24515
  const opt = key;
24516
24516
  if (opt in options2)
24517
- this.logger[log](`${msg}: option ${key}. ${checkOpts[opt]}`);
24517
+ this.logger[log2](`${msg}: option ${key}. ${checkOpts[opt]}`);
24518
24518
  }
24519
24519
  }
24520
24520
  function getSchEnv(keyRef) {
@@ -27350,8 +27350,8 @@ var init_server2 = __esm({
27350
27350
  this._loggingLevels = /* @__PURE__ */ new Map();
27351
27351
  this.LOG_LEVEL_SEVERITY = new Map(LoggingLevelSchema.options.map((level, index) => [level, index]));
27352
27352
  this.isMessageIgnored = (level, sessionId) => {
27353
- const currentLevel = this._loggingLevels.get(sessionId);
27354
- return currentLevel ? this.LOG_LEVEL_SEVERITY.get(level) < this.LOG_LEVEL_SEVERITY.get(currentLevel) : false;
27353
+ const currentLevel2 = this._loggingLevels.get(sessionId);
27354
+ return currentLevel2 ? this.LOG_LEVEL_SEVERITY.get(level) < this.LOG_LEVEL_SEVERITY.get(currentLevel2) : false;
27355
27355
  };
27356
27356
  this._capabilities = options2?.capabilities ?? {};
27357
27357
  this._instructions = options2?.instructions;
@@ -28746,6 +28746,281 @@ var init_stdio2 = __esm({
28746
28746
  }
28747
28747
  });
28748
28748
 
28749
+ // src/lib/state.ts
28750
+ import { readFile, writeFile, mkdir, chmod } from "fs/promises";
28751
+ import { join } from "path";
28752
+ function setWorkDir(dir) {
28753
+ _workDirCache = dir;
28754
+ }
28755
+ function getWorkDir() {
28756
+ return _workDirCache || process.env.CLAUDEINK_WORK_DIR || process.cwd();
28757
+ }
28758
+ function getClaudeinkDir() {
28759
+ return join(getWorkDir(), ".claudeink");
28760
+ }
28761
+ function getStatePath() {
28762
+ return join(getClaudeinkDir(), "state.json");
28763
+ }
28764
+ async function ensureDir() {
28765
+ await mkdir(getClaudeinkDir(), { recursive: true });
28766
+ }
28767
+ async function readState() {
28768
+ const statePath = getStatePath();
28769
+ let raw;
28770
+ try {
28771
+ raw = await readFile(statePath, "utf-8");
28772
+ } catch {
28773
+ const state = { ...DEFAULT_STATE };
28774
+ state.config.workflowDir = getWorkDir();
28775
+ return state;
28776
+ }
28777
+ try {
28778
+ const parsed = JSON.parse(raw);
28779
+ const state = {
28780
+ credentials: parsed.credentials ?? null,
28781
+ config: { ...DEFAULT_STATE.config, ...parsed.config },
28782
+ tagQueue: parsed.tagQueue ?? { ...DEFAULT_STATE.tagQueue },
28783
+ lastSyncAt: parsed.lastSyncAt ?? ""
28784
+ };
28785
+ state.config.workflowDir = getWorkDir();
28786
+ return state;
28787
+ } catch {
28788
+ const backupPath = statePath + ".corrupted." + Date.now();
28789
+ try {
28790
+ await writeFile(backupPath, raw, "utf-8");
28791
+ } catch {
28792
+ }
28793
+ console.error(`[ClaudeInk] state.json corrupted, backed up to ${backupPath}`);
28794
+ const state = { ...DEFAULT_STATE };
28795
+ state.config.workflowDir = getWorkDir();
28796
+ return state;
28797
+ }
28798
+ }
28799
+ async function writeState(state) {
28800
+ await ensureDir();
28801
+ await writeFile(getStatePath(), JSON.stringify(state, null, 2), "utf-8");
28802
+ await chmod(getStatePath(), 384);
28803
+ }
28804
+ async function getCredentials() {
28805
+ const state = await readState();
28806
+ if (!state.credentials) return null;
28807
+ return {
28808
+ licenseKey: state.credentials.licenseKey,
28809
+ token: state.credentials.token,
28810
+ userId: state.credentials.userId,
28811
+ plan: state.credentials.plan,
28812
+ expiresAt: state.credentials.expiresAt
28813
+ };
28814
+ }
28815
+ async function getConfig() {
28816
+ const state = await readState();
28817
+ return state.config;
28818
+ }
28819
+ async function updateLastSyncAt() {
28820
+ const state = await readState();
28821
+ state.lastSyncAt = (/* @__PURE__ */ new Date()).toISOString();
28822
+ await writeState(state);
28823
+ }
28824
+ async function addToTagQueue(item) {
28825
+ const state = await readState();
28826
+ if (state.tagQueue.queue.some((q) => q.knowledgeId === item.knowledgeId)) return;
28827
+ state.tagQueue.queue.push(item);
28828
+ await writeState(state);
28829
+ }
28830
+ var _workDirCache, DEFAULT_STATE;
28831
+ var init_state = __esm({
28832
+ "src/lib/state.ts"() {
28833
+ "use strict";
28834
+ _workDirCache = null;
28835
+ DEFAULT_STATE = {
28836
+ credentials: null,
28837
+ config: {
28838
+ apiBaseUrl: "https://app.claudeink.com",
28839
+ workflowDir: "",
28840
+ logLevel: "INFO"
28841
+ },
28842
+ tagQueue: {
28843
+ queue: [],
28844
+ failed: []
28845
+ },
28846
+ lastSyncAt: ""
28847
+ };
28848
+ }
28849
+ });
28850
+
28851
+ // src/lib/logger.ts
28852
+ import { appendFile, mkdir as mkdir2 } from "fs/promises";
28853
+ import { join as join2 } from "path";
28854
+ function setLogLevel(level) {
28855
+ currentLevel = level;
28856
+ }
28857
+ async function log(level, scope, message) {
28858
+ if (LEVELS[level] > LEVELS[currentLevel]) return;
28859
+ const dir = join2(getClaudeinkDir(), "logs");
28860
+ await mkdir2(dir, { recursive: true });
28861
+ const date3 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
28862
+ const line = `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${scope} | ${message}
28863
+ `;
28864
+ await appendFile(join2(dir, `mcp-${date3}.log`), line);
28865
+ console.error(`[ClaudeInk] ${line.trim()}`);
28866
+ }
28867
+ var currentLevel, LEVELS;
28868
+ var init_logger = __esm({
28869
+ "src/lib/logger.ts"() {
28870
+ "use strict";
28871
+ init_state();
28872
+ currentLevel = "INFO";
28873
+ LEVELS = { ERROR: 0, WARN: 1, INFO: 2, DEBUG: 3 };
28874
+ }
28875
+ });
28876
+
28877
+ // src/tools/sync.ts
28878
+ async function sync2(input) {
28879
+ if (input.workDir) setWorkDir(input.workDir);
28880
+ const creds = await getCredentials();
28881
+ if (!creds?.token) {
28882
+ return { success: false, message: "\u672A\u6FC0\u6D3B\uFF0C\u8BF7\u5148\u4F7F\u7528 workflow.init \u6FC0\u6D3B License" };
28883
+ }
28884
+ return doPull(creds.token);
28885
+ }
28886
+ async function doPull(token) {
28887
+ const config2 = await getConfig();
28888
+ try {
28889
+ const res = await fetch(`${config2.apiBaseUrl}/api/sync/pull`, {
28890
+ headers: { Authorization: `Bearer ${token}` }
28891
+ });
28892
+ if (!res.ok) {
28893
+ if (res.status === 404) {
28894
+ return { success: true, message: "\u4E91\u7AEF\u65E0\u6570\u636E" };
28895
+ }
28896
+ await log("ERROR", "ink.sync", `pull failed: HTTP ${res.status}`);
28897
+ return { success: false, message: `\u62C9\u53D6\u5931\u8D25: HTTP ${res.status}` };
28898
+ }
28899
+ await updateLastSyncAt();
28900
+ await log("INFO", "ink.sync", "pull completed");
28901
+ return {
28902
+ success: true,
28903
+ message: "\u2705 \u540C\u6B65\u5B8C\u6210"
28904
+ };
28905
+ } catch (err) {
28906
+ return { success: false, message: `\u540C\u6B65\u5931\u8D25: ${err instanceof Error ? err.message : err}` };
28907
+ }
28908
+ }
28909
+ async function syncPull(input) {
28910
+ if (input.workDir) setWorkDir(input.workDir);
28911
+ const creds = await getCredentials();
28912
+ if (!creds?.token) {
28913
+ return { success: false, message: "\u672A\u6FC0\u6D3B" };
28914
+ }
28915
+ return doPull(creds.token);
28916
+ }
28917
+ var syncSchema;
28918
+ var init_sync = __esm({
28919
+ "src/tools/sync.ts"() {
28920
+ "use strict";
28921
+ init_zod();
28922
+ init_state();
28923
+ init_logger();
28924
+ syncSchema = external_exports.object({
28925
+ workDir: external_exports.string().optional().describe("\u5DE5\u4F5C\u76EE\u5F55\uFF08\u9ED8\u8BA4\u4F7F\u7528\u914D\u7F6E\u4E2D\u7684 workflowDir\uFF09")
28926
+ });
28927
+ }
28928
+ });
28929
+
28930
+ // src/tools/workflow.ts
28931
+ import { mkdir as mkdir3, access, unlink } from "fs/promises";
28932
+ import { join as join3 } from "path";
28933
+ async function workflowInit(input) {
28934
+ const cwd = input.workDir;
28935
+ const results = [];
28936
+ try {
28937
+ setWorkDir(cwd);
28938
+ const claudeinkDir = join3(cwd, ".claudeink");
28939
+ await mkdir3(join3(claudeinkDir, "knowledge"), { recursive: true });
28940
+ results.push("\u2705 \u77E5\u8BC6\u5E93\u76EE\u5F55\u5DF2\u521B\u5EFA");
28941
+ const state = await readState();
28942
+ state.config.workflowDir = cwd;
28943
+ const oldCredsPath = join3(claudeinkDir, "credentials.json");
28944
+ try {
28945
+ await access(oldCredsPath);
28946
+ await unlink(oldCredsPath);
28947
+ results.push("\u{1F9F9} \u5DF2\u6E05\u7406\u65E7\u7248 credentials.json");
28948
+ } catch {
28949
+ }
28950
+ let activated = false;
28951
+ if (input.licenseKey) {
28952
+ try {
28953
+ const res = await fetch(`${DEFAULT_API_BASE_URL}/api/auth/activate`, {
28954
+ method: "POST",
28955
+ headers: { "Content-Type": "application/json" },
28956
+ body: JSON.stringify({ key: input.licenseKey })
28957
+ });
28958
+ const data = await res.json();
28959
+ if (data.userId) {
28960
+ state.credentials = {
28961
+ licenseKey: input.licenseKey,
28962
+ token: data.token,
28963
+ userId: data.userId,
28964
+ plan: data.plan,
28965
+ expiresAt: data.expiresAt
28966
+ };
28967
+ results.push(`\u2705 License \u6FC0\u6D3B\u6210\u529F\uFF08\u5957\u9910: ${data.plan}\uFF09`);
28968
+ activated = true;
28969
+ } else {
28970
+ results.push(`\u26A0\uFE0F License \u6FC0\u6D3B\u5931\u8D25: ${JSON.stringify(data)}`);
28971
+ }
28972
+ } catch (err) {
28973
+ results.push(`\u26A0\uFE0F \u6FC0\u6D3B\u7F51\u7EDC\u9519\u8BEF: ${err instanceof Error ? err.message : err}`);
28974
+ }
28975
+ }
28976
+ await writeState(state);
28977
+ results.push("\u2705 state.json");
28978
+ if (activated) {
28979
+ try {
28980
+ const pullResult = await syncPull({ workDir: cwd });
28981
+ if (pullResult.success) {
28982
+ results.push("\u2705 \u5DF2\u4ECE\u4E91\u7AEF\u540C\u6B65\u6570\u636E");
28983
+ } else {
28984
+ results.push("\u2139\uFE0F \u4E91\u7AEF\u65E0\u5DF2\u6709\u6570\u636E");
28985
+ }
28986
+ } catch {
28987
+ results.push("\u2139\uFE0F \u4E91\u7AEF\u540C\u6B65\u8DF3\u8FC7");
28988
+ }
28989
+ }
28990
+ return {
28991
+ success: true,
28992
+ message: [
28993
+ "\u{1F389} ClaudeInk \u77E5\u8BC6\u5E93\u521D\u59CB\u5316\u5B8C\u6210\uFF01",
28994
+ "",
28995
+ ...results,
28996
+ "",
28997
+ "\u{1F3AF} \u4E0B\u4E00\u6B65\uFF1A",
28998
+ "1. \u5728\u5BF9\u8BDD\u4E2D\u8BF4\u300C\u5E2E\u6211\u5B58\u4E00\u4E0B\u300D\u4FDD\u5B58\u6709\u4EF7\u503C\u5185\u5BB9",
28999
+ "2. \u7528\u300C\u627E\u4E00\u4E0B\u5173\u4E8E XX \u7684\u300D\u68C0\u7D22\u77E5\u8BC6\u5E93"
29000
+ ].join("\n")
29001
+ };
29002
+ } catch (err) {
29003
+ return {
29004
+ success: false,
29005
+ message: `\u521D\u59CB\u5316\u5931\u8D25: ${err instanceof Error ? err.message : err}`
29006
+ };
29007
+ }
29008
+ }
29009
+ var DEFAULT_API_BASE_URL, workflowInitSchema;
29010
+ var init_workflow = __esm({
29011
+ "src/tools/workflow.ts"() {
29012
+ "use strict";
29013
+ init_zod();
29014
+ init_state();
29015
+ init_sync();
29016
+ DEFAULT_API_BASE_URL = "https://app.claudeink.com";
29017
+ workflowInitSchema = external_exports.object({
29018
+ workDir: external_exports.string().describe("\u5DE5\u4F5C\u6D41\u521D\u59CB\u5316\u76EE\u6807\u76EE\u5F55\uFF08\u7EDD\u5BF9\u8DEF\u5F84\uFF09"),
29019
+ licenseKey: external_exports.string().optional().describe("License Key\uFF08\u53EF\u9009\uFF0C\u4F20\u5165\u5219\u81EA\u52A8\u6FC0\u6D3B\uFF09")
29020
+ });
29021
+ }
29022
+ });
29023
+
28749
29024
  // ../node_modules/kind-of/index.js
28750
29025
  var require_kind_of = __commonJS({
28751
29026
  "../node_modules/kind-of/index.js"(exports2, module2) {
@@ -32230,110 +32505,9 @@ var require_gray_matter = __commonJS({
32230
32505
  }
32231
32506
  });
32232
32507
 
32233
- // src/lib/state.ts
32234
- import { readFile, writeFile, mkdir, chmod } from "fs/promises";
32235
- import { join } from "path";
32236
- function setWorkDir(dir) {
32237
- _workDirCache = dir;
32238
- }
32239
- function getWorkDir() {
32240
- return _workDirCache || process.env.CLAUDEINK_WORK_DIR || process.cwd();
32241
- }
32242
- function getClaudeinkDir() {
32243
- return join(getWorkDir(), ".claudeink");
32244
- }
32245
- function getStatePath() {
32246
- return join(getClaudeinkDir(), "state.json");
32247
- }
32248
- async function ensureDir() {
32249
- await mkdir(getClaudeinkDir(), { recursive: true });
32250
- }
32251
- async function readState() {
32252
- const statePath = getStatePath();
32253
- let raw;
32254
- try {
32255
- raw = await readFile(statePath, "utf-8");
32256
- } catch {
32257
- const state = { ...DEFAULT_STATE };
32258
- state.config.workflowDir = getWorkDir();
32259
- return state;
32260
- }
32261
- try {
32262
- const parsed = JSON.parse(raw);
32263
- const state = {
32264
- credentials: parsed.credentials ?? null,
32265
- config: { ...DEFAULT_STATE.config, ...parsed.config },
32266
- tagQueue: parsed.tagQueue ?? { ...DEFAULT_STATE.tagQueue },
32267
- lastSyncAt: parsed.lastSyncAt ?? ""
32268
- };
32269
- state.config.workflowDir = getWorkDir();
32270
- return state;
32271
- } catch {
32272
- const backupPath = statePath + ".corrupted." + Date.now();
32273
- try {
32274
- await writeFile(backupPath, raw, "utf-8");
32275
- } catch {
32276
- }
32277
- console.error(`[ClaudeInk] state.json corrupted, backed up to ${backupPath}`);
32278
- const state = { ...DEFAULT_STATE };
32279
- state.config.workflowDir = getWorkDir();
32280
- return state;
32281
- }
32282
- }
32283
- async function writeState(state) {
32284
- await ensureDir();
32285
- await writeFile(getStatePath(), JSON.stringify(state, null, 2), "utf-8");
32286
- await chmod(getStatePath(), 384);
32287
- }
32288
- async function getCredentials() {
32289
- const state = await readState();
32290
- if (!state.credentials) return null;
32291
- return {
32292
- licenseKey: state.credentials.licenseKey,
32293
- token: state.credentials.token,
32294
- userId: state.credentials.userId,
32295
- plan: state.credentials.plan,
32296
- expiresAt: state.credentials.expiresAt
32297
- };
32298
- }
32299
- async function getConfig() {
32300
- const state = await readState();
32301
- return state.config;
32302
- }
32303
- async function updateLastSyncAt() {
32304
- const state = await readState();
32305
- state.lastSyncAt = (/* @__PURE__ */ new Date()).toISOString();
32306
- await writeState(state);
32307
- }
32308
- async function addToTagQueue(item) {
32309
- const state = await readState();
32310
- if (state.tagQueue.queue.some((q) => q.knowledgeId === item.knowledgeId)) return;
32311
- state.tagQueue.queue.push(item);
32312
- await writeState(state);
32313
- }
32314
- var _workDirCache, DEFAULT_STATE;
32315
- var init_state = __esm({
32316
- "src/lib/state.ts"() {
32317
- "use strict";
32318
- _workDirCache = null;
32319
- DEFAULT_STATE = {
32320
- credentials: null,
32321
- config: {
32322
- apiBaseUrl: "https://app.claudeink.com",
32323
- workflowDir: ""
32324
- },
32325
- tagQueue: {
32326
- queue: [],
32327
- failed: []
32328
- },
32329
- lastSyncAt: ""
32330
- };
32331
- }
32332
- });
32333
-
32334
32508
  // src/lib/knowledge.ts
32335
- import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, unlink } from "fs/promises";
32336
- import { join as join2 } from "path";
32509
+ import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir4, unlink as unlink2 } from "fs/promises";
32510
+ import { join as join4 } from "path";
32337
32511
  function withIndexLock(fn) {
32338
32512
  const prev = _lockPromise;
32339
32513
  let resolve;
@@ -32343,10 +32517,10 @@ function withIndexLock(fn) {
32343
32517
  return prev.then(fn).finally(() => resolve());
32344
32518
  }
32345
32519
  function getKnowledgeDir() {
32346
- return join2(getWorkDir(), ".claudeink", "knowledge");
32520
+ return join4(getWorkDir(), ".claudeink", "knowledge");
32347
32521
  }
32348
32522
  function getIndexPath() {
32349
- return join2(getWorkDir(), ".claudeink", "knowledge", "index.json");
32523
+ return join4(getWorkDir(), ".claudeink", "knowledge", "index.json");
32350
32524
  }
32351
32525
  async function generateIdInternal(index) {
32352
32526
  const now = /* @__PURE__ */ new Date();
@@ -32379,17 +32553,17 @@ async function readIndex() {
32379
32553
  async function saveIndex(index) {
32380
32554
  index.updated_at = (/* @__PURE__ */ new Date()).toISOString();
32381
32555
  const dir = getKnowledgeDir();
32382
- await mkdir2(dir, { recursive: true });
32556
+ await mkdir4(dir, { recursive: true });
32383
32557
  await writeFile2(getIndexPath(), JSON.stringify(index, null, 2), "utf-8");
32384
32558
  }
32385
32559
  async function writeKnowledgeFile(meta, content) {
32386
32560
  const now = /* @__PURE__ */ new Date();
32387
32561
  const monthDir = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}`;
32388
- const dir = join2(getKnowledgeDir(), monthDir);
32389
- await mkdir2(dir, { recursive: true });
32562
+ const dir = join4(getKnowledgeDir(), monthDir);
32563
+ await mkdir4(dir, { recursive: true });
32390
32564
  const slug = toSlug(meta.title) || meta.id;
32391
32565
  const filename = `${now.toISOString().slice(0, 10)}-${slug}.md`;
32392
- const filePath = join2(dir, filename);
32566
+ const filePath = join4(dir, filename);
32393
32567
  const frontmatter = {
32394
32568
  id: meta.id,
32395
32569
  title: meta.title,
@@ -32402,13 +32576,13 @@ async function writeKnowledgeFile(meta, content) {
32402
32576
  if (meta.url) frontmatter.url = meta.url;
32403
32577
  const output = import_gray_matter.default.stringify(content, frontmatter);
32404
32578
  await writeFile2(filePath, output, "utf-8");
32405
- return join2(monthDir, filename);
32579
+ return join4(monthDir, filename);
32406
32580
  }
32407
32581
  async function readKnowledgeFile(id) {
32408
32582
  const index = await readIndex();
32409
32583
  const entry = index.entries[id];
32410
32584
  if (!entry) return null;
32411
- const filePath = join2(getKnowledgeDir(), entry.file_path);
32585
+ const filePath = join4(getKnowledgeDir(), entry.file_path);
32412
32586
  try {
32413
32587
  const raw = await readFile2(filePath, "utf-8");
32414
32588
  const { data, content } = (0, import_gray_matter.default)(raw);
@@ -32493,9 +32667,9 @@ async function deleteKnowledgeFile(id) {
32493
32667
  const index = await readIndex();
32494
32668
  const entry = index.entries[id];
32495
32669
  if (!entry) return false;
32496
- const filePath = join2(getKnowledgeDir(), entry.file_path);
32670
+ const filePath = join4(getKnowledgeDir(), entry.file_path);
32497
32671
  try {
32498
- await unlink(filePath);
32672
+ await unlink2(filePath);
32499
32673
  } catch {
32500
32674
  }
32501
32675
  delete index.entries[id];
@@ -32503,55 +32677,6 @@ async function deleteKnowledgeFile(id) {
32503
32677
  return true;
32504
32678
  });
32505
32679
  }
32506
- function searchKnowledge(index, filters) {
32507
- let entries = Object.values(index.entries);
32508
- if (filters.tags && filters.tags.length > 0) {
32509
- const filterTags = filters.tags.map((t) => t.toLowerCase());
32510
- entries = entries.filter(
32511
- (e) => e.tags.some((t) => filterTags.includes(t.toLowerCase()))
32512
- );
32513
- }
32514
- if (filters.category) {
32515
- entries = entries.filter((e) => e.category === filters.category);
32516
- }
32517
- if (filters.date_from) {
32518
- entries = entries.filter((e) => e.created_at >= filters.date_from);
32519
- }
32520
- if (filters.date_to) {
32521
- entries = entries.filter((e) => e.created_at <= filters.date_to);
32522
- }
32523
- if (filters.query) {
32524
- const q = filters.query.toLowerCase();
32525
- entries = entries.map((e) => {
32526
- let score = 0;
32527
- if (e.title.toLowerCase().includes(q)) score += 10;
32528
- if (e.preview.toLowerCase().includes(q)) score += 5;
32529
- if (e.tags.some((t) => t.toLowerCase().includes(q))) score += 3;
32530
- return { ...e, _score: score };
32531
- }).filter((e) => e._score > 0).sort((a, b) => b._score - a._score);
32532
- } else {
32533
- entries.sort((a, b) => b.created_at.localeCompare(a.created_at));
32534
- }
32535
- const total = entries.length;
32536
- const limit = filters.limit || 10;
32537
- const results = entries.slice(0, limit).map((e) => ({
32538
- id: e.id,
32539
- title: e.title,
32540
- tags: e.tags,
32541
- category: e.category,
32542
- created_at: e.created_at,
32543
- preview: e.preview
32544
- }));
32545
- return { results, total };
32546
- }
32547
- async function readMultipleKnowledgeFiles(ids) {
32548
- const results = [];
32549
- for (const id of ids) {
32550
- const file = await readKnowledgeFile(id);
32551
- if (file) results.push(file);
32552
- }
32553
- return results;
32554
- }
32555
32680
  function getAllTags(index) {
32556
32681
  const tagCounts = {};
32557
32682
  for (const entry of Object.values(index.entries)) {
@@ -32570,7 +32695,7 @@ async function renameTag(oldTag, newTag) {
32570
32695
  if (idx !== -1) {
32571
32696
  entry.tags[idx] = newTag;
32572
32697
  count++;
32573
- const filePath = join2(getKnowledgeDir(), entry.file_path);
32698
+ const filePath = join4(getKnowledgeDir(), entry.file_path);
32574
32699
  try {
32575
32700
  const raw = await readFile2(filePath, "utf-8");
32576
32701
  const { data, content } = (0, import_gray_matter.default)(raw);
@@ -32605,7 +32730,7 @@ async function mergeTags(sourceTags, targetTag) {
32605
32730
  }
32606
32731
  entry.tags = newTags;
32607
32732
  count++;
32608
- const filePath = join2(getKnowledgeDir(), entry.file_path);
32733
+ const filePath = join4(getKnowledgeDir(), entry.file_path);
32609
32734
  try {
32610
32735
  const raw = await readFile2(filePath, "utf-8");
32611
32736
  const { data, content } = (0, import_gray_matter.default)(raw);
@@ -32645,6 +32770,7 @@ async function doPush(partial2) {
32645
32770
  knowledge: partial2.knowledge || [],
32646
32771
  crawlerSources: partial2.crawlerSources || []
32647
32772
  };
32773
+ await log("DEBUG", "push", `payload: ${partial2.knowledge?.length || 0} knowledge, ${partial2.crawlerSources?.length || 0} sources`);
32648
32774
  try {
32649
32775
  await fetch(`${config2.apiBaseUrl}/api/sync/batch`, {
32650
32776
  method: "POST",
@@ -32655,107 +32781,408 @@ async function doPush(partial2) {
32655
32781
  body: JSON.stringify(payload)
32656
32782
  });
32657
32783
  } catch (err) {
32658
- console.error("[ClaudeInk] auto-push failed:", err instanceof Error ? err.message : err);
32784
+ await log("WARN", "push", `failed: ${err instanceof Error ? err.message : err}`);
32659
32785
  }
32660
32786
  }
32661
32787
  var init_push = __esm({
32662
32788
  "src/lib/push.ts"() {
32663
32789
  "use strict";
32664
32790
  init_state();
32791
+ init_logger();
32665
32792
  }
32666
32793
  });
32667
32794
 
32668
- // src/tools/source.ts
32795
+ // src/tools/ink.ts
32669
32796
  import { readFile as readFile3 } from "fs/promises";
32670
- import { join as join3 } from "path";
32671
- import { readdirSync as readdirSync2 } from "fs";
32672
- import { execSync } from "child_process";
32673
- async function sourceCrawl(input) {
32674
- const config2 = await getConfig();
32675
- const crawlerDir = join3(config2.workflowDir || process.cwd(), "tools", "crawler");
32676
- const configPath = join3(crawlerDir, "config.json");
32677
- let crawlerConfig;
32797
+ import { extname } from "path";
32798
+ async function inkSave(input) {
32678
32799
  try {
32679
- crawlerConfig = JSON.parse(await readFile3(configPath, "utf-8"));
32680
- } catch {
32681
- crawlerConfig = { sources: [] };
32682
- }
32683
- if (crawlerConfig.sources.length === 0) {
32684
- return { success: false, message: "\u6682\u65E0\u914D\u7F6E\u722C\u866B\u6E90\u3002\u8BF7\u5148\u7528 source.subscribe \u6DFB\u52A0\u3002" };
32685
- }
32686
- const targets = input.sourceId ? crawlerConfig.sources.filter((s) => s.id === input.sourceId) : crawlerConfig.sources.filter((s) => s.enabled !== false);
32687
- if (targets.length === 0) {
32800
+ if (input.id) {
32801
+ const result = await updateKnowledgeFile(input.id, {
32802
+ title: input.title,
32803
+ content: input.content,
32804
+ tags: input.tags,
32805
+ category: input.category
32806
+ });
32807
+ if (!result) {
32808
+ return { success: false, message: `\u672A\u627E\u5230 ID \u4E3A ${input.id} \u7684\u77E5\u8BC6\u7247\u6BB5` };
32809
+ }
32810
+ fireAndForgetPush({
32811
+ knowledge: [{
32812
+ id: result.meta.id,
32813
+ title: result.meta.title,
32814
+ tags: result.meta.tags,
32815
+ category: result.meta.category,
32816
+ source_type: result.meta.source_type,
32817
+ url: result.meta.url,
32818
+ created_at: result.meta.created_at,
32819
+ updated_at: result.meta.updated_at
32820
+ }]
32821
+ });
32822
+ await log("INFO", "ink.save", `updated id=${input.id} title="${input.title}"`);
32823
+ return {
32824
+ success: true,
32825
+ message: `\u5DF2\u66F4\u65B0\u300C${result.meta.title}\u300D`,
32826
+ data: { id: result.meta.id }
32827
+ };
32828
+ }
32829
+ const { id } = await saveKnowledge({
32830
+ content: input.content,
32831
+ title: input.title,
32832
+ tags: input.tags,
32833
+ category: input.category,
32834
+ source_type: input.source_type,
32835
+ url: input.url
32836
+ });
32837
+ fireAndForgetPush({
32838
+ knowledge: [{
32839
+ id,
32840
+ title: input.title,
32841
+ tags: input.tags,
32842
+ category: input.category,
32843
+ source_type: input.source_type,
32844
+ url: input.url,
32845
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
32846
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
32847
+ }]
32848
+ });
32849
+ await log("INFO", "ink.save", `created id=${id} title="${input.title}" tags=${JSON.stringify(input.tags)}`);
32688
32850
  return {
32689
- success: false,
32690
- message: input.sourceId ? `\u672A\u627E\u5230\u722C\u866B\u6E90: ${input.sourceId}` : "\u6CA1\u6709\u5DF2\u542F\u7528\u7684\u722C\u866B\u6E90"
32851
+ success: true,
32852
+ message: `\u5DF2\u4FDD\u5B58\u300C${input.title}\u300D`,
32853
+ data: { id }
32691
32854
  };
32855
+ } catch (err) {
32856
+ await log("ERROR", "ink.save", `failed: ${err.message}`);
32857
+ return { success: false, message: `\u4FDD\u5B58\u5931\u8D25\uFF1A${err.message}` };
32692
32858
  }
32693
- const crawlScript = join3(crawlerDir, "crawl.mjs");
32694
- const args2 = input.sourceId ? `--source ${input.sourceId}` : "";
32859
+ }
32860
+ async function inkDelete(input) {
32695
32861
  try {
32696
- execSync(`node "${crawlScript}" ${args2}`, {
32697
- cwd: crawlerDir,
32698
- encoding: "utf-8",
32699
- timeout: 5 * 60 * 1e3,
32700
- stdio: ["pipe", "pipe", "pipe"]
32701
- });
32702
- let saved = 0;
32703
- let queued = 0;
32704
- for (const target of targets) {
32705
- const sourceDir = join3(config2.workflowDir, "sources", "articles", target.id);
32706
- let files;
32707
- try {
32708
- files = readdirSync2(sourceDir).filter((f) => f.endsWith(".md"));
32709
- } catch {
32710
- continue;
32862
+ if (!input.confirm) {
32863
+ const index = await readIndex();
32864
+ const entry = index.entries[input.id];
32865
+ if (!entry) {
32866
+ return { success: false, message: `\u672A\u627E\u5230 ID \u4E3A ${input.id} \u7684\u77E5\u8BC6\u7247\u6BB5` };
32711
32867
  }
32712
- for (const f of files) {
32713
- const filePath = join3(sourceDir, f);
32714
- try {
32715
- const raw = await readFile3(filePath, "utf-8");
32716
- const { data, content } = (0, import_gray_matter2.default)(raw);
32717
- const title = data.title || f.replace(/^\d{4}-\d{2}-\d{2}-/, "").replace(/\.md$/, "").replace(/-/g, " ");
32718
- const url = data.url || "";
32719
- const { id } = await saveKnowledge({
32720
- content: content.trim(),
32721
- title,
32722
- tags: data.tags || [],
32723
- category: "reference",
32724
- source_type: "url",
32725
- url
32726
- });
32727
- saved++;
32728
- if (!data.tags || data.tags.length === 0) {
32729
- await addToTagQueue({
32730
- knowledgeId: id,
32731
- title,
32732
- addedAt: (/* @__PURE__ */ new Date()).toISOString(),
32733
- source: "crawl",
32734
- retryCount: 0
32735
- });
32736
- queued++;
32737
- }
32738
- fireAndForgetPush({
32739
- knowledge: [{
32740
- id,
32741
- title,
32742
- tags: data.tags || [],
32743
- category: "reference",
32744
- source_type: "url",
32745
- url,
32746
- created_at: (/* @__PURE__ */ new Date()).toISOString(),
32747
- updated_at: (/* @__PURE__ */ new Date()).toISOString()
32748
- }]
32749
- });
32750
- } catch {
32868
+ return {
32869
+ success: false,
32870
+ message: `\u786E\u8BA4\u5220\u9664\u300C${entry.title}\u300D\uFF1F\u8BF7\u5C06 confirm \u8BBE\u4E3A true \u4EE5\u786E\u8BA4\u5220\u9664\u3002`,
32871
+ data: { id: entry.id, title: entry.title, category: entry.category, tags: entry.tags }
32872
+ };
32873
+ }
32874
+ const deleted = await deleteKnowledgeFile(input.id);
32875
+ if (!deleted) {
32876
+ return { success: false, message: `\u672A\u627E\u5230 ID \u4E3A ${input.id} \u7684\u77E5\u8BC6\u7247\u6BB5` };
32877
+ }
32878
+ fireAndForgetPush({
32879
+ knowledge: [{
32880
+ id: input.id,
32881
+ title: "",
32882
+ tags: [],
32883
+ category: "reference",
32884
+ source_type: "conversation",
32885
+ created_at: "",
32886
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
32887
+ }]
32888
+ });
32889
+ await log("INFO", "ink.delete", `deleted id=${input.id}`);
32890
+ return { success: true, message: `\u5DF2\u5220\u9664\u77E5\u8BC6\u7247\u6BB5 ${input.id}`, data: { id: input.id } };
32891
+ } catch (err) {
32892
+ await log("ERROR", "ink.delete", `failed: ${err.message}`);
32893
+ return { success: false, message: `\u5220\u9664\u5931\u8D25\uFF1A${err.message}` };
32894
+ }
32895
+ }
32896
+ async function inkWrite(input) {
32897
+ const creds = await getCredentials();
32898
+ if (!creds?.token) return { success: false, message: "\u672A\u8BA4\u8BC1\uFF0C\u8BF7\u5148\u8FD0\u884C ink.init" };
32899
+ const config2 = await getConfig();
32900
+ try {
32901
+ let coverUrl = input.cover || null;
32902
+ if (coverUrl) {
32903
+ if (coverUrl.startsWith("http://") || coverUrl.startsWith("https://")) {
32904
+ const uploadResult = await uploadImageFromUrl(coverUrl, "cover", creds.token, config2.apiBaseUrl);
32905
+ if (uploadResult.success) coverUrl = uploadResult.url;
32906
+ } else {
32907
+ const uploadResult = await uploadImage(coverUrl, "cover", creds.token, config2.apiBaseUrl);
32908
+ if (uploadResult.success) {
32909
+ coverUrl = uploadResult.url;
32910
+ } else {
32911
+ await log("WARN", "ink.write", `cover upload failed: ${uploadResult.error}`);
32912
+ coverUrl = null;
32751
32913
  }
32752
32914
  }
32753
32915
  }
32916
+ const slug = `${Date.now().toString(36)}-${input.title.toLowerCase().replace(/[^a-z0-9\u4e00-\u9fff]+/g, "-").replace(/^-|-$/g, "").slice(0, 60)}`;
32917
+ const excerpt = input.excerpt || input.content.replace(/^#+\s.+$/gm, "").replace(/\n+/g, " ").trim().slice(0, 200);
32918
+ const res = await fetch(`${config2.apiBaseUrl}/api/blog/manage`, {
32919
+ method: "POST",
32920
+ headers: {
32921
+ "Content-Type": "application/json",
32922
+ Authorization: `Bearer ${creds.token}`
32923
+ },
32924
+ body: JSON.stringify({
32925
+ title: input.title,
32926
+ slug,
32927
+ content: input.content,
32928
+ cover_url: coverUrl,
32929
+ tags: input.tags,
32930
+ category: input.category,
32931
+ excerpt,
32932
+ source_ids: input.source_ids
32933
+ })
32934
+ });
32935
+ if (!res.ok) {
32936
+ const err = await res.text();
32937
+ await log("ERROR", "ink.write", `save failed: ${err}`);
32938
+ return { success: false, message: `\u4FDD\u5B58\u5931\u8D25: ${err}` };
32939
+ }
32940
+ const data = await res.json();
32941
+ await log("INFO", "ink.write", `saved article="${input.title}" id=${data.id} slug=${data.slug}`);
32754
32942
  return {
32755
32943
  success: true,
32756
- message: [
32757
- `\u2705 \u722C\u53D6\u5B8C\u6210`,
32758
- ` \u76EE\u6807\u6E90: ${targets.map((t) => t.name).join(", ")}`,
32944
+ message: `\u6587\u7AE0\u300C${input.title}\u300D\u5DF2\u4FDD\u5B58\u4E3A\u8349\u7A3F\uFF0C\u8BF7\u5230 Dashboard \u53D1\u5E03`,
32945
+ data: { id: data.id, slug: data.slug, status: data.status }
32946
+ };
32947
+ } catch (err) {
32948
+ await log("ERROR", "ink.write", `failed: ${err.message}`);
32949
+ return { success: false, message: `\u5199\u6587\u7AE0\u5931\u8D25: ${err.message}` };
32950
+ }
32951
+ }
32952
+ async function inkTags(input) {
32953
+ try {
32954
+ const index = await readIndex();
32955
+ switch (input.action) {
32956
+ case "list": {
32957
+ const tags = getAllTags(index);
32958
+ return {
32959
+ success: true,
32960
+ message: tags.length > 0 ? `\u5171 ${tags.length} \u4E2A\u6807\u7B7E` : "\u6682\u65E0\u6807\u7B7E",
32961
+ data: { tags }
32962
+ };
32963
+ }
32964
+ case "rename": {
32965
+ if (!input.tag || !input.new_tag) {
32966
+ return { success: false, message: "rename \u9700\u8981 tag\uFF08\u539F\u6807\u7B7E\uFF09\u548C new_tag\uFF08\u65B0\u6807\u7B7E\u540D\uFF09" };
32967
+ }
32968
+ const count = await renameTag(input.tag, input.new_tag);
32969
+ if (count === 0) {
32970
+ return { success: false, message: `\u672A\u627E\u5230\u4F7F\u7528\u6807\u7B7E\u300C${input.tag}\u300D\u7684\u77E5\u8BC6\u7247\u6BB5` };
32971
+ }
32972
+ await log("INFO", "ink.tags", `renamed "${input.tag}" \u2192 "${input.new_tag}", affected=${count}`);
32973
+ return {
32974
+ success: true,
32975
+ message: `\u5DF2\u5C06 ${count} \u6761\u77E5\u8BC6\u7247\u6BB5\u7684\u6807\u7B7E\u300C${input.tag}\u300D\u91CD\u547D\u540D\u4E3A\u300C${input.new_tag}\u300D`,
32976
+ data: { old_tag: input.tag, new_tag: input.new_tag, affected: count }
32977
+ };
32978
+ }
32979
+ case "merge": {
32980
+ if (!input.source_tags || input.source_tags.length === 0 || !input.new_tag) {
32981
+ 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" };
32982
+ }
32983
+ const count = await mergeTags(input.source_tags, input.new_tag);
32984
+ if (count === 0) {
32985
+ return { success: false, message: "\u672A\u627E\u5230\u4F7F\u7528\u8FD9\u4E9B\u6807\u7B7E\u7684\u77E5\u8BC6\u7247\u6BB5" };
32986
+ }
32987
+ await log("INFO", "ink.tags", `merged [${input.source_tags.join(",")}] \u2192 "${input.new_tag}", affected=${count}`);
32988
+ return {
32989
+ success: true,
32990
+ message: `\u5DF2\u5C06 ${count} \u6761\u77E5\u8BC6\u7247\u6BB5\u7684\u6807\u7B7E\u5408\u5E76\u4E3A\u300C${input.new_tag}\u300D`,
32991
+ data: { source_tags: input.source_tags, target_tag: input.new_tag, affected: count }
32992
+ };
32993
+ }
32994
+ }
32995
+ } catch (err) {
32996
+ await log("ERROR", "ink.tags", `failed: ${err.message}`);
32997
+ return { success: false, message: `\u6807\u7B7E\u64CD\u4F5C\u5931\u8D25\uFF1A${err.message}` };
32998
+ }
32999
+ }
33000
+ async function uploadImage(localPath, type, token, apiBase) {
33001
+ try {
33002
+ const fileBuffer = await readFile3(localPath);
33003
+ const ext2 = extname(localPath) || ".jpg";
33004
+ const extMap = {
33005
+ ".jpg": "image/jpeg",
33006
+ ".jpeg": "image/jpeg",
33007
+ ".png": "image/png",
33008
+ ".webp": "image/webp",
33009
+ ".gif": "image/gif"
33010
+ };
33011
+ const contentType = extMap[ext2.toLowerCase()] || "application/octet-stream";
33012
+ const filename = `${type}-${Date.now()}${ext2}`;
33013
+ const res = await fetch(`${apiBase}/api/blog/upload-image`, {
33014
+ method: "POST",
33015
+ headers: {
33016
+ Authorization: `Bearer ${token}`,
33017
+ "Content-Type": contentType,
33018
+ "X-Filename": filename,
33019
+ "X-Image-Type": type
33020
+ },
33021
+ body: fileBuffer
33022
+ });
33023
+ if (!res.ok) return { success: false, error: await res.text() };
33024
+ const { url } = await res.json();
33025
+ return { success: true, url };
33026
+ } catch (err) {
33027
+ return { success: false, error: err.message };
33028
+ }
33029
+ }
33030
+ async function uploadImageFromUrl(imageUrl, type, token, apiBase) {
33031
+ try {
33032
+ const res = await fetch(imageUrl);
33033
+ if (!res.ok) return { success: false, error: `download failed: HTTP ${res.status}` };
33034
+ const fileBuffer = Buffer.from(await res.arrayBuffer());
33035
+ const ext2 = extname(new URL(imageUrl).pathname) || ".jpg";
33036
+ const contentType = res.headers.get("content-type") || "image/jpeg";
33037
+ const filename = `${type}-${Date.now()}${ext2}`;
33038
+ const uploadRes = await fetch(`${apiBase}/api/blog/upload-image`, {
33039
+ method: "POST",
33040
+ headers: {
33041
+ Authorization: `Bearer ${token}`,
33042
+ "Content-Type": contentType,
33043
+ "X-Filename": filename,
33044
+ "X-Image-Type": type
33045
+ },
33046
+ body: fileBuffer
33047
+ });
33048
+ if (!uploadRes.ok) return { success: false, error: await uploadRes.text() };
33049
+ const { url } = await uploadRes.json();
33050
+ return { success: true, url };
33051
+ } catch (err) {
33052
+ return { success: false, error: err.message };
33053
+ }
33054
+ }
33055
+ var inkSaveSchema, inkDeleteSchema, inkWriteSchema, inkTagsSchema;
33056
+ var init_ink = __esm({
33057
+ "src/tools/ink.ts"() {
33058
+ "use strict";
33059
+ init_zod();
33060
+ init_knowledge();
33061
+ init_push();
33062
+ init_state();
33063
+ init_logger();
33064
+ inkSaveSchema = external_exports.object({
33065
+ id: external_exports.string().optional().describe("\u77E5\u8BC6\u7247\u6BB5 ID\uFF08\u63D0\u4F9B\u5219\u66F4\u65B0\uFF0C\u4E0D\u63D0\u4F9B\u5219\u65B0\u5EFA\uFF09"),
33066
+ content: external_exports.string().describe("\u8981\u4FDD\u5B58\u7684\u5185\u5BB9\uFF08\u5FC5\u586B\uFF09"),
33067
+ title: external_exports.string().describe("\u6807\u9898\uFF08Claude \u81EA\u52A8\u751F\u6210\uFF09"),
33068
+ tags: external_exports.array(external_exports.string()).optional().default([]).describe("\u6807\u7B7E"),
33069
+ category: external_exports.enum(["insight", "decision", "analysis", "idea", "reference", "action"]).optional().default("reference").describe("\u5206\u7C7B"),
33070
+ source_type: external_exports.enum(["conversation", "url", "manual"]).optional().default("conversation").describe("\u6765\u6E90\u7C7B\u578B"),
33071
+ url: external_exports.string().optional().describe("\u6765\u6E90 URL")
33072
+ });
33073
+ inkDeleteSchema = external_exports.object({
33074
+ id: external_exports.string().describe("\u77E5\u8BC6\u7247\u6BB5 ID"),
33075
+ confirm: external_exports.boolean().optional().default(false).describe("\u786E\u8BA4\u5220\u9664\uFF08\u5FC5\u987B\u4E3A true \u624D\u4F1A\u6267\u884C\u5220\u9664\uFF09")
33076
+ });
33077
+ inkWriteSchema = external_exports.object({
33078
+ title: external_exports.string().describe("\u6587\u7AE0\u6807\u9898"),
33079
+ content: external_exports.string().describe("Markdown \u5168\u6587"),
33080
+ cover: external_exports.string().optional().describe("\u5C01\u9762\u56FE\uFF08\u672C\u5730\u8DEF\u5F84\u6216 URL\uFF0C\u81EA\u52A8\u4E0A\u4F20\uFF09"),
33081
+ tags: external_exports.array(external_exports.string()).optional().default([]).describe("\u6587\u7AE0\u6807\u7B7E"),
33082
+ category: external_exports.string().optional().describe("\u6587\u7AE0\u5206\u7C7B"),
33083
+ excerpt: external_exports.string().optional().describe("\u6458\u8981\uFF08\u4E0D\u586B\u81EA\u52A8\u622A\u53D6\u524D 200 \u5B57\uFF09"),
33084
+ source_ids: external_exports.array(external_exports.string()).optional().describe("\u5173\u8054\u7684\u7D20\u6750 ink ID\uFF08\u6EAF\u6E90\uFF09")
33085
+ });
33086
+ inkTagsSchema = external_exports.object({
33087
+ action: external_exports.enum(["list", "rename", "merge"]).describe("\u64CD\u4F5C\uFF1Alist\uFF08\u5217\u51FA\u6240\u6709\u6807\u7B7E\uFF09/ rename\uFF08\u91CD\u547D\u540D\uFF09/ merge\uFF08\u5408\u5E76\uFF09"),
33088
+ tag: external_exports.string().optional().describe("\u76EE\u6807\u6807\u7B7E\uFF08rename/merge \u65F6\u4F7F\u7528\uFF09"),
33089
+ new_tag: external_exports.string().optional().describe("\u65B0\u6807\u7B7E\u540D\uFF08rename \u65F6\u4F7F\u7528\uFF09"),
33090
+ source_tags: external_exports.array(external_exports.string()).optional().describe("\u8981\u5408\u5E76\u7684\u6E90\u6807\u7B7E\u5217\u8868\uFF08merge \u65F6\u4F7F\u7528\uFF09")
33091
+ });
33092
+ }
33093
+ });
33094
+
33095
+ // src/tools/source.ts
33096
+ import { readFile as readFile4 } from "fs/promises";
33097
+ import { join as join5 } from "path";
33098
+ import { readdirSync as readdirSync2 } from "fs";
33099
+ import { execSync } from "child_process";
33100
+ async function sourceCrawl(input) {
33101
+ const config2 = await getConfig();
33102
+ const crawlerDir = join5(config2.workflowDir || process.cwd(), "tools", "crawler");
33103
+ const configPath = join5(crawlerDir, "config.json");
33104
+ let crawlerConfig;
33105
+ try {
33106
+ crawlerConfig = JSON.parse(await readFile4(configPath, "utf-8"));
33107
+ } catch {
33108
+ crawlerConfig = { sources: [] };
33109
+ }
33110
+ if (crawlerConfig.sources.length === 0) {
33111
+ return { success: false, message: "\u6682\u65E0\u914D\u7F6E\u722C\u866B\u6E90\u3002\u8BF7\u5148\u7528 source.subscribe \u6DFB\u52A0\u3002" };
33112
+ }
33113
+ const targets = input.sourceId ? crawlerConfig.sources.filter((s) => s.id === input.sourceId) : crawlerConfig.sources.filter((s) => s.enabled !== false);
33114
+ if (targets.length === 0) {
33115
+ return {
33116
+ success: false,
33117
+ message: input.sourceId ? `\u672A\u627E\u5230\u722C\u866B\u6E90: ${input.sourceId}` : "\u6CA1\u6709\u5DF2\u542F\u7528\u7684\u722C\u866B\u6E90"
33118
+ };
33119
+ }
33120
+ const crawlScript = join5(crawlerDir, "crawl.mjs");
33121
+ const args2 = input.sourceId ? `--source ${input.sourceId}` : "";
33122
+ try {
33123
+ execSync(`node "${crawlScript}" ${args2}`, {
33124
+ cwd: crawlerDir,
33125
+ encoding: "utf-8",
33126
+ timeout: 5 * 60 * 1e3,
33127
+ stdio: ["pipe", "pipe", "pipe"]
33128
+ });
33129
+ let saved = 0;
33130
+ let queued = 0;
33131
+ for (const target of targets) {
33132
+ const sourceDir = join5(config2.workflowDir, "sources", "articles", target.id);
33133
+ let files;
33134
+ try {
33135
+ files = readdirSync2(sourceDir).filter((f) => f.endsWith(".md"));
33136
+ } catch {
33137
+ continue;
33138
+ }
33139
+ for (const f of files) {
33140
+ const filePath = join5(sourceDir, f);
33141
+ try {
33142
+ const raw = await readFile4(filePath, "utf-8");
33143
+ const { data, content } = (0, import_gray_matter2.default)(raw);
33144
+ const title = data.title || f.replace(/^\d{4}-\d{2}-\d{2}-/, "").replace(/\.md$/, "").replace(/-/g, " ");
33145
+ const url = data.url || "";
33146
+ const { id } = await saveKnowledge({
33147
+ content: content.trim(),
33148
+ title,
33149
+ tags: data.tags || [],
33150
+ category: "reference",
33151
+ source_type: "url",
33152
+ url
33153
+ });
33154
+ saved++;
33155
+ if (!data.tags || data.tags.length === 0) {
33156
+ await addToTagQueue({
33157
+ knowledgeId: id,
33158
+ title,
33159
+ addedAt: (/* @__PURE__ */ new Date()).toISOString(),
33160
+ source: "crawl",
33161
+ retryCount: 0
33162
+ });
33163
+ queued++;
33164
+ }
33165
+ fireAndForgetPush({
33166
+ knowledge: [{
33167
+ id,
33168
+ title,
33169
+ tags: data.tags || [],
33170
+ category: "reference",
33171
+ source_type: "url",
33172
+ url,
33173
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
33174
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
33175
+ }]
33176
+ });
33177
+ } catch {
33178
+ }
33179
+ }
33180
+ }
33181
+ return {
33182
+ success: true,
33183
+ message: [
33184
+ `\u2705 \u722C\u53D6\u5B8C\u6210`,
33185
+ ` \u76EE\u6807\u6E90: ${targets.map((t) => t.name).join(", ")}`,
32759
33186
  ` \u4FDD\u5B58\u5230\u77E5\u8BC6\u5E93: ${saved} \u7BC7`,
32760
33187
  queued > 0 ? ` \u52A0\u5165\u6807\u7B7E\u961F\u5217: ${queued} \u7BC7\uFF08\u7B49\u5F85 AI \u6253\u6807\u7B7E\uFF09` : ""
32761
33188
  ].filter(Boolean).join("\n"),
@@ -32785,20 +33212,20 @@ var init_source = __esm({
32785
33212
  });
32786
33213
 
32787
33214
  // src/tools/subscribe.ts
32788
- import { readFile as readFile4, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
32789
- import { join as join4 } from "path";
33215
+ import { readFile as readFile5, writeFile as writeFile3, mkdir as mkdir5 } from "fs/promises";
33216
+ import { join as join6 } from "path";
32790
33217
  async function readCrawlerConfig(configPath) {
32791
33218
  try {
32792
- return JSON.parse(await readFile4(configPath, "utf-8"));
33219
+ return JSON.parse(await readFile5(configPath, "utf-8"));
32793
33220
  } catch {
32794
33221
  return { sources: [] };
32795
33222
  }
32796
33223
  }
32797
33224
  async function sourceSubscribe(input) {
32798
33225
  const config2 = await getConfig();
32799
- const crawlerDir = join4(config2.workflowDir || process.cwd(), "tools", "crawler");
32800
- await mkdir3(crawlerDir, { recursive: true });
32801
- const configPath = join4(crawlerDir, "config.json");
33226
+ const crawlerDir = join6(config2.workflowDir || process.cwd(), "tools", "crawler");
33227
+ await mkdir5(crawlerDir, { recursive: true });
33228
+ const configPath = join6(crawlerDir, "config.json");
32802
33229
  const crawlerConfig = await readCrawlerConfig(configPath);
32803
33230
  if (input.action === "list") {
32804
33231
  return {
@@ -32892,725 +33319,86 @@ var init_subscribe = __esm({
32892
33319
  }
32893
33320
  });
32894
33321
 
32895
- // src/tools/sync.ts
32896
- async function sync2(input) {
32897
- if (input.workDir) setWorkDir(input.workDir);
32898
- const creds = await getCredentials();
32899
- if (!creds?.token) {
32900
- return { success: false, message: "\u672A\u6FC0\u6D3B\uFF0C\u8BF7\u5148\u4F7F\u7528 workflow.init \u6FC0\u6D3B License" };
32901
- }
32902
- return doPull(creds.token);
32903
- }
32904
- async function doPull(token) {
32905
- const config2 = await getConfig();
33322
+ // src/index.ts
33323
+ var index_exports = {};
33324
+ async function main() {
32906
33325
  try {
32907
- const res = await fetch(`${config2.apiBaseUrl}/api/sync/pull`, {
32908
- headers: { Authorization: `Bearer ${token}` }
32909
- });
32910
- if (!res.ok) {
32911
- if (res.status === 404) {
32912
- return { success: true, message: "\u4E91\u7AEF\u65E0\u6570\u636E" };
32913
- }
32914
- return { success: false, message: `\u62C9\u53D6\u5931\u8D25: HTTP ${res.status}` };
33326
+ const state = await readState();
33327
+ if (state.config.workflowDir) {
33328
+ setWorkDir(state.config.workflowDir);
32915
33329
  }
32916
- await updateLastSyncAt();
32917
- return {
32918
- success: true,
32919
- message: "\u2705 \u540C\u6B65\u5B8C\u6210"
32920
- };
32921
- } catch (err) {
32922
- return { success: false, message: `\u540C\u6B65\u5931\u8D25: ${err instanceof Error ? err.message : err}` };
32923
- }
32924
- }
32925
- async function syncPull(input) {
32926
- if (input.workDir) setWorkDir(input.workDir);
32927
- const creds = await getCredentials();
32928
- if (!creds?.token) {
32929
- return { success: false, message: "\u672A\u6FC0\u6D3B" };
33330
+ setLogLevel(state.config.logLevel || "INFO");
33331
+ } catch {
32930
33332
  }
32931
- return doPull(creds.token);
33333
+ const transport = new StdioServerTransport();
33334
+ await server.connect(transport);
33335
+ await log("INFO", "server", "started (8 tools)");
32932
33336
  }
32933
- var syncSchema;
32934
- var init_sync = __esm({
32935
- "src/tools/sync.ts"() {
33337
+ var server;
33338
+ var init_index = __esm({
33339
+ "src/index.ts"() {
32936
33340
  "use strict";
32937
- init_zod();
33341
+ init_mcp();
33342
+ init_stdio2();
33343
+ init_workflow();
33344
+ init_sync();
33345
+ init_ink();
33346
+ init_source();
33347
+ init_subscribe();
32938
33348
  init_state();
32939
- syncSchema = external_exports.object({
32940
- workDir: external_exports.string().optional().describe("\u5DE5\u4F5C\u76EE\u5F55\uFF08\u9ED8\u8BA4\u4F7F\u7528\u914D\u7F6E\u4E2D\u7684 workflowDir\uFF09")
33349
+ init_logger();
33350
+ server = new McpServer({
33351
+ name: "ClaudeInk",
33352
+ version: "2.0.1"
32941
33353
  });
32942
- }
32943
- });
32944
-
32945
- // src/tools/workflow.ts
32946
- import { mkdir as mkdir4, access, unlink as unlink2 } from "fs/promises";
32947
- import { join as join5 } from "path";
32948
- async function workflowInit(input) {
32949
- const cwd = input.workDir;
32950
- const results = [];
32951
- try {
32952
- setWorkDir(cwd);
32953
- const claudeinkDir = join5(cwd, ".claudeink");
32954
- await mkdir4(join5(claudeinkDir, "knowledge"), { recursive: true });
32955
- results.push("\u2705 \u77E5\u8BC6\u5E93\u76EE\u5F55\u5DF2\u521B\u5EFA");
32956
- const state = await readState();
32957
- state.config.workflowDir = cwd;
32958
- const oldCredsPath = join5(claudeinkDir, "credentials.json");
32959
- try {
32960
- await access(oldCredsPath);
32961
- await unlink2(oldCredsPath);
32962
- results.push("\u{1F9F9} \u5DF2\u6E05\u7406\u65E7\u7248 credentials.json");
32963
- } catch {
32964
- }
32965
- let activated = false;
32966
- if (input.licenseKey) {
32967
- try {
32968
- const res = await fetch(`${DEFAULT_API_BASE_URL}/api/auth/activate`, {
32969
- method: "POST",
32970
- headers: { "Content-Type": "application/json" },
32971
- body: JSON.stringify({ key: input.licenseKey })
32972
- });
32973
- const data = await res.json();
32974
- if (data.userId) {
32975
- state.credentials = {
32976
- licenseKey: input.licenseKey,
32977
- token: data.token,
32978
- userId: data.userId,
32979
- plan: data.plan,
32980
- expiresAt: data.expiresAt
32981
- };
32982
- results.push(`\u2705 License \u6FC0\u6D3B\u6210\u529F\uFF08\u5957\u9910: ${data.plan}\uFF09`);
32983
- activated = true;
32984
- } else {
32985
- results.push(`\u26A0\uFE0F License \u6FC0\u6D3B\u5931\u8D25: ${JSON.stringify(data)}`);
32986
- }
32987
- } catch (err) {
32988
- results.push(`\u26A0\uFE0F \u6FC0\u6D3B\u7F51\u7EDC\u9519\u8BEF: ${err instanceof Error ? err.message : err}`);
32989
- }
32990
- }
32991
- await writeState(state);
32992
- results.push("\u2705 state.json");
32993
- if (activated) {
32994
- try {
32995
- const pullResult = await syncPull({ workDir: cwd });
32996
- if (pullResult.success) {
32997
- results.push("\u2705 \u5DF2\u4ECE\u4E91\u7AEF\u540C\u6B65\u6570\u636E");
32998
- } else {
32999
- results.push("\u2139\uFE0F \u4E91\u7AEF\u65E0\u5DF2\u6709\u6570\u636E");
33000
- }
33001
- } catch {
33002
- results.push("\u2139\uFE0F \u4E91\u7AEF\u540C\u6B65\u8DF3\u8FC7");
33003
- }
33004
- }
33005
- return {
33006
- success: true,
33007
- message: [
33008
- "\u{1F389} ClaudeInk \u77E5\u8BC6\u5E93\u521D\u59CB\u5316\u5B8C\u6210\uFF01",
33009
- "",
33010
- ...results,
33011
- "",
33012
- "\u{1F3AF} \u4E0B\u4E00\u6B65\uFF1A",
33013
- "1. \u5728\u5BF9\u8BDD\u4E2D\u8BF4\u300C\u5E2E\u6211\u5B58\u4E00\u4E0B\u300D\u4FDD\u5B58\u6709\u4EF7\u503C\u5185\u5BB9",
33014
- "2. \u7528\u300C\u627E\u4E00\u4E0B\u5173\u4E8E XX \u7684\u300D\u68C0\u7D22\u77E5\u8BC6\u5E93"
33015
- ].join("\n")
33016
- };
33017
- } catch (err) {
33018
- return {
33019
- success: false,
33020
- message: `\u521D\u59CB\u5316\u5931\u8D25: ${err instanceof Error ? err.message : err}`
33021
- };
33022
- }
33023
- }
33024
- var DEFAULT_API_BASE_URL, workflowInitSchema;
33025
- var init_workflow = __esm({
33026
- "src/tools/workflow.ts"() {
33027
- "use strict";
33028
- init_zod();
33029
- init_state();
33030
- init_sync();
33031
- DEFAULT_API_BASE_URL = "https://app.claudeink.com";
33032
- workflowInitSchema = external_exports.object({
33033
- workDir: external_exports.string().describe("\u5DE5\u4F5C\u6D41\u521D\u59CB\u5316\u76EE\u6807\u76EE\u5F55\uFF08\u7EDD\u5BF9\u8DEF\u5F84\uFF09"),
33034
- licenseKey: external_exports.string().optional().describe("License Key\uFF08\u53EF\u9009\uFF0C\u4F20\u5165\u5219\u81EA\u52A8\u6FC0\u6D3B\uFF09")
33035
- });
33036
- }
33037
- });
33038
-
33039
- // src/tools/ink.ts
33040
- async function inkSave(input) {
33041
- try {
33042
- const { id } = await saveKnowledge({
33043
- content: input.content,
33044
- title: input.title,
33045
- tags: input.tags,
33046
- category: input.category,
33047
- source_type: input.source_type,
33048
- url: input.url
33049
- });
33050
- const categoryNames = {
33051
- insight: "\u6D1E\u5BDF",
33052
- decision: "\u51B3\u7B56",
33053
- analysis: "\u5206\u6790",
33054
- idea: "\u60F3\u6CD5",
33055
- reference: "\u53C2\u8003",
33056
- action: "\u884C\u52A8"
33057
- };
33058
- const catName = categoryNames[input.category] || input.category;
33059
- const tagStr = input.tags.length > 0 ? input.tags.join("\u3001") : "\u65E0\u6807\u7B7E";
33060
- fireAndForgetPush({
33061
- knowledge: [{
33062
- id,
33063
- title: input.title,
33064
- tags: input.tags,
33065
- category: input.category,
33066
- source_type: input.source_type,
33067
- url: input.url,
33068
- created_at: (/* @__PURE__ */ new Date()).toISOString(),
33069
- updated_at: (/* @__PURE__ */ new Date()).toISOString()
33070
- }]
33071
- });
33072
- return {
33073
- success: true,
33074
- message: `\u5DF2\u4FDD\u5B58\u5230\u300C${catName}\u300D\uFF0C\u6807\u7B7E\uFF1A${tagStr}`,
33075
- data: { id }
33076
- };
33077
- } catch (err) {
33078
- return {
33079
- success: false,
33080
- message: `\u4FDD\u5B58\u5931\u8D25\uFF1A${err.message}`
33081
- };
33082
- }
33083
- }
33084
- async function inkSearch(input) {
33085
- try {
33086
- const index = await readIndex();
33087
- const { results, total } = searchKnowledge(index, {
33088
- query: input.query,
33089
- tags: input.tags,
33090
- category: input.category,
33091
- date_from: input.date_from,
33092
- date_to: input.date_to,
33093
- limit: input.limit
33094
- });
33095
- if (total === 0) {
33096
- return {
33097
- success: true,
33098
- message: "\u6CA1\u6709\u627E\u5230\u5339\u914D\u7684\u77E5\u8BC6\u7247\u6BB5",
33099
- data: { results: [], total: 0 }
33100
- };
33101
- }
33102
- return {
33103
- success: true,
33104
- message: `\u627E\u5230 ${total} \u6761\u76F8\u5173\u8BB0\u5F55${total > results.length ? `\uFF0C\u663E\u793A\u524D ${results.length} \u6761` : ""}`,
33105
- data: { results, total }
33106
- };
33107
- } catch (err) {
33108
- return {
33109
- success: false,
33110
- message: `\u641C\u7D22\u5931\u8D25\uFF1A${err.message}`
33111
- };
33112
- }
33113
- }
33114
- async function inkGet(input) {
33115
- try {
33116
- const file = await readKnowledgeFile(input.id);
33117
- if (!file) {
33118
- return {
33119
- success: false,
33120
- message: `\u672A\u627E\u5230 ID \u4E3A ${input.id} \u7684\u77E5\u8BC6\u7247\u6BB5`
33121
- };
33122
- }
33123
- return {
33124
- success: true,
33125
- message: file.meta.title,
33126
- data: {
33127
- id: file.meta.id,
33128
- title: file.meta.title,
33129
- content: file.content,
33130
- tags: file.meta.tags,
33131
- category: file.meta.category,
33132
- source_type: file.meta.source_type,
33133
- url: file.meta.url,
33134
- created_at: file.meta.created_at,
33135
- updated_at: file.meta.updated_at
33136
- }
33137
- };
33138
- } catch (err) {
33139
- return {
33140
- success: false,
33141
- message: `\u83B7\u53D6\u5931\u8D25\uFF1A${err.message}`
33142
- };
33143
- }
33144
- }
33145
- async function inkReview(input) {
33146
- try {
33147
- const index = await readIndex();
33148
- const entries = Object.values(index.entries);
33149
- const now = /* @__PURE__ */ new Date();
33150
- let dateFrom;
33151
- let dateTo = now.toISOString();
33152
- switch (input.period) {
33153
- case "today":
33154
- dateFrom = new Date(now.getFullYear(), now.getMonth(), now.getDate()).toISOString();
33155
- break;
33156
- case "week": {
33157
- const weekAgo = new Date(now);
33158
- weekAgo.setDate(weekAgo.getDate() - 7);
33159
- dateFrom = weekAgo.toISOString();
33160
- break;
33161
- }
33162
- case "month": {
33163
- const monthAgo = new Date(now);
33164
- monthAgo.setMonth(monthAgo.getMonth() - 1);
33165
- dateFrom = monthAgo.toISOString();
33166
- break;
33167
- }
33168
- case "custom":
33169
- dateFrom = input.date_from || (/* @__PURE__ */ new Date(0)).toISOString();
33170
- dateTo = input.date_to || now.toISOString();
33171
- break;
33172
- }
33173
- let filtered = entries.filter(
33174
- (e) => e.created_at >= dateFrom && e.created_at <= dateTo
33175
- );
33176
- if (input.category) {
33177
- filtered = filtered.filter((e) => e.category === input.category);
33178
- }
33179
- filtered.sort((a, b) => b.created_at.localeCompare(a.created_at));
33180
- const byCategory = {};
33181
- for (const e of filtered) {
33182
- byCategory[e.category] = (byCategory[e.category] || 0) + 1;
33183
- }
33184
- const tagCounts = {};
33185
- for (const e of filtered) {
33186
- for (const t of e.tags) {
33187
- tagCounts[t] = (tagCounts[t] || 0) + 1;
33188
- }
33189
- }
33190
- const topTags = Object.entries(tagCounts).sort((a, b) => b[1] - a[1]).slice(0, 10).map(([tag, count]) => ({ tag, count }));
33191
- const categoryNames = {
33192
- insight: "\u6D1E\u5BDF",
33193
- decision: "\u51B3\u7B56",
33194
- analysis: "\u5206\u6790",
33195
- idea: "\u60F3\u6CD5",
33196
- reference: "\u53C2\u8003",
33197
- action: "\u884C\u52A8"
33198
- };
33199
- const periodNames = {
33200
- today: "\u4ECA\u65E5",
33201
- week: "\u672C\u5468",
33202
- month: "\u672C\u6708",
33203
- custom: "\u81EA\u5B9A\u4E49\u65F6\u6BB5"
33204
- };
33205
- return {
33206
- success: true,
33207
- message: `${periodNames[input.period]}\u77E5\u8BC6\u56DE\u987E\uFF1A\u5171 ${filtered.length} \u6761\u8BB0\u5F55`,
33208
- data: {
33209
- period: input.period,
33210
- date_from: dateFrom,
33211
- date_to: dateTo,
33212
- total: filtered.length,
33213
- by_category: Object.entries(byCategory).map(([cat, count]) => ({
33214
- category: cat,
33215
- label: categoryNames[cat] || cat,
33216
- count
33217
- })),
33218
- top_tags: topTags,
33219
- items: filtered.map((e) => ({
33220
- id: e.id,
33221
- title: e.title,
33222
- category: e.category,
33223
- tags: e.tags,
33224
- created_at: e.created_at,
33225
- preview: e.preview
33226
- }))
33227
- }
33228
- };
33229
- } catch (err) {
33230
- return {
33231
- success: false,
33232
- message: `\u56DE\u987E\u5931\u8D25\uFF1A${err.message}`
33233
- };
33234
- }
33235
- }
33236
- async function inkUpdate(input) {
33237
- try {
33238
- const { id, ...updates } = input;
33239
- if (!updates.title && !updates.content && !updates.tags && !updates.category) {
33240
- return {
33241
- success: false,
33242
- message: "\u8BF7\u81F3\u5C11\u63D0\u4F9B\u4E00\u4E2A\u8981\u66F4\u65B0\u7684\u5B57\u6BB5\uFF08title / content / tags / category\uFF09"
33243
- };
33244
- }
33245
- const result = await updateKnowledgeFile(id, updates);
33246
- if (!result) {
33247
- return {
33248
- success: false,
33249
- message: `\u672A\u627E\u5230 ID \u4E3A ${id} \u7684\u77E5\u8BC6\u7247\u6BB5`
33250
- };
33251
- }
33252
- const changed = Object.keys(updates).filter(
33253
- (k) => updates[k] !== void 0
33254
- );
33255
- fireAndForgetPush({
33256
- knowledge: [{
33257
- id: result.meta.id,
33258
- title: result.meta.title,
33259
- tags: result.meta.tags,
33260
- category: result.meta.category,
33261
- source_type: result.meta.source_type,
33262
- url: result.meta.url,
33263
- created_at: result.meta.created_at,
33264
- updated_at: result.meta.updated_at
33265
- }]
33266
- });
33267
- return {
33268
- success: true,
33269
- message: `\u5DF2\u66F4\u65B0\u300C${result.meta.title}\u300D\u7684 ${changed.join("\u3001")}`,
33270
- data: {
33271
- id: result.meta.id,
33272
- title: result.meta.title,
33273
- tags: result.meta.tags,
33274
- category: result.meta.category,
33275
- updated_at: result.meta.updated_at
33276
- }
33277
- };
33278
- } catch (err) {
33279
- return {
33280
- success: false,
33281
- message: `\u66F4\u65B0\u5931\u8D25\uFF1A${err.message}`
33282
- };
33283
- }
33284
- }
33285
- async function inkDelete(input) {
33286
- try {
33287
- if (!input.confirm) {
33288
- const index = await readIndex();
33289
- const entry = index.entries[input.id];
33290
- if (!entry) {
33291
- return {
33292
- success: false,
33293
- message: `\u672A\u627E\u5230 ID \u4E3A ${input.id} \u7684\u77E5\u8BC6\u7247\u6BB5`
33294
- };
33295
- }
33296
- return {
33297
- success: false,
33298
- message: `\u786E\u8BA4\u5220\u9664\u300C${entry.title}\u300D\uFF1F\u8BF7\u5C06 confirm \u8BBE\u4E3A true \u4EE5\u786E\u8BA4\u5220\u9664\u3002`,
33299
- data: {
33300
- id: entry.id,
33301
- title: entry.title,
33302
- category: entry.category,
33303
- tags: entry.tags,
33304
- created_at: entry.created_at
33305
- }
33306
- };
33307
- }
33308
- const deleted = await deleteKnowledgeFile(input.id);
33309
- if (!deleted) {
33310
- return {
33311
- success: false,
33312
- message: `\u672A\u627E\u5230 ID \u4E3A ${input.id} \u7684\u77E5\u8BC6\u7247\u6BB5`
33313
- };
33314
- }
33315
- fireAndForgetPush({
33316
- knowledge: [{
33317
- id: input.id,
33318
- title: "",
33319
- tags: [],
33320
- category: "reference",
33321
- source_type: "conversation",
33322
- created_at: "",
33323
- updated_at: (/* @__PURE__ */ new Date()).toISOString()
33324
- }]
33325
- });
33326
- return {
33327
- success: true,
33328
- message: `\u5DF2\u5220\u9664\u77E5\u8BC6\u7247\u6BB5 ${input.id}`,
33329
- data: { id: input.id }
33330
- };
33331
- } catch (err) {
33332
- return {
33333
- success: false,
33334
- message: `\u5220\u9664\u5931\u8D25\uFF1A${err.message}`
33335
- };
33336
- }
33337
- }
33338
- async function inkCompile(input) {
33339
- try {
33340
- let ids = [];
33341
- if (input.ids && input.ids.length > 0) {
33342
- ids = input.ids;
33343
- } else if (input.query || input.tags && input.tags.length > 0) {
33344
- const index = await readIndex();
33345
- const { results } = searchKnowledge(index, {
33346
- query: input.query,
33347
- tags: input.tags,
33348
- limit: 20
33349
- });
33350
- ids = results.map((r) => r.id);
33351
- }
33352
- if (ids.length === 0) {
33353
- return {
33354
- success: false,
33355
- message: "\u6CA1\u6709\u627E\u5230\u8981\u6574\u5408\u7684\u77E5\u8BC6\u7247\u6BB5\uFF0C\u8BF7\u6307\u5B9A ids \u6216\u63D0\u4F9B\u641C\u7D22\u6761\u4EF6"
33356
- };
33357
- }
33358
- const files = await readMultipleKnowledgeFiles(ids);
33359
- if (files.length === 0) {
33360
- return {
33361
- success: false,
33362
- message: "\u672A\u80FD\u8BFB\u53D6\u4EFB\u4F55\u77E5\u8BC6\u7247\u6BB5\u5185\u5BB9"
33363
- };
33364
- }
33365
- const sections = files.map((f, i) => {
33366
- const tagStr = f.meta.tags.length > 0 ? ` [${f.meta.tags.join(", ")}]` : "";
33367
- return `### ${i + 1}. ${f.meta.title}${tagStr}
33368
- > ${f.meta.category} | ${f.meta.created_at.slice(0, 10)}
33369
-
33370
- ${f.content}`;
33371
- });
33372
- const formatLabels = {
33373
- outline: "\u5927\u7EB2",
33374
- article: "\u6587\u7AE0",
33375
- summary: "\u6458\u8981"
33376
- };
33377
- const compiled = sections.join("\n\n---\n\n");
33378
- return {
33379
- success: true,
33380
- message: `\u5DF2\u6574\u5408 ${files.length} \u6761\u77E5\u8BC6\u7247\u6BB5\uFF0C\u683C\u5F0F\uFF1A${formatLabels[input.format]}`,
33381
- data: {
33382
- source_count: files.length,
33383
- source_ids: files.map((f) => f.meta.id),
33384
- format: input.format,
33385
- instruction: input.instruction || null,
33386
- compiled_content: compiled
33387
- }
33388
- };
33389
- } catch (err) {
33390
- return {
33391
- success: false,
33392
- message: `\u6574\u5408\u5931\u8D25\uFF1A${err.message}`
33393
- };
33394
- }
33395
- }
33396
- async function inkTags(input) {
33397
- try {
33398
- const index = await readIndex();
33399
- switch (input.action) {
33400
- case "list": {
33401
- const tags = getAllTags(index);
33402
- return {
33403
- success: true,
33404
- message: tags.length > 0 ? `\u5171 ${tags.length} \u4E2A\u6807\u7B7E` : "\u6682\u65E0\u6807\u7B7E",
33405
- data: { tags }
33406
- };
33407
- }
33408
- case "rename": {
33409
- if (!input.tag || !input.new_tag) {
33410
- return {
33411
- success: false,
33412
- message: "rename \u64CD\u4F5C\u9700\u8981\u63D0\u4F9B tag\uFF08\u539F\u6807\u7B7E\uFF09\u548C new_tag\uFF08\u65B0\u6807\u7B7E\u540D\uFF09"
33413
- };
33414
- }
33415
- const count = await renameTag(input.tag, input.new_tag);
33416
- if (count === 0) {
33417
- return {
33418
- success: false,
33419
- message: `\u672A\u627E\u5230\u4F7F\u7528\u6807\u7B7E\u300C${input.tag}\u300D\u7684\u77E5\u8BC6\u7247\u6BB5`
33420
- };
33421
- }
33422
- return {
33423
- success: true,
33424
- message: `\u5DF2\u5C06 ${count} \u6761\u77E5\u8BC6\u7247\u6BB5\u7684\u6807\u7B7E\u300C${input.tag}\u300D\u91CD\u547D\u540D\u4E3A\u300C${input.new_tag}\u300D`,
33425
- data: { old_tag: input.tag, new_tag: input.new_tag, affected: count }
33426
- };
33427
- }
33428
- case "merge": {
33429
- if (!input.source_tags || input.source_tags.length === 0 || !input.new_tag) {
33430
- return {
33431
- success: false,
33432
- message: "merge \u64CD\u4F5C\u9700\u8981\u63D0\u4F9B source_tags\uFF08\u6E90\u6807\u7B7E\u5217\u8868\uFF09\u548C new_tag\uFF08\u76EE\u6807\u6807\u7B7E\uFF09"
33433
- };
33434
- }
33435
- const count = await mergeTags(input.source_tags, input.new_tag);
33436
- if (count === 0) {
33437
- return {
33438
- success: false,
33439
- message: `\u672A\u627E\u5230\u4F7F\u7528\u8FD9\u4E9B\u6807\u7B7E\u7684\u77E5\u8BC6\u7247\u6BB5`
33440
- };
33441
- }
33442
- return {
33443
- success: true,
33444
- message: `\u5DF2\u5C06 ${count} \u6761\u77E5\u8BC6\u7247\u6BB5\u7684\u6807\u7B7E\u5408\u5E76\u4E3A\u300C${input.new_tag}\u300D`,
33445
- data: {
33446
- source_tags: input.source_tags,
33447
- target_tag: input.new_tag,
33448
- affected: count
33449
- }
33450
- };
33451
- }
33452
- }
33453
- } catch (err) {
33454
- return {
33455
- success: false,
33456
- message: `\u6807\u7B7E\u64CD\u4F5C\u5931\u8D25\uFF1A${err.message}`
33457
- };
33458
- }
33459
- }
33460
- var inkSaveSchema, inkSearchSchema, inkGetSchema, inkReviewSchema, inkUpdateSchema, inkDeleteSchema, inkCompileSchema, inkTagsSchema;
33461
- var init_ink = __esm({
33462
- "src/tools/ink.ts"() {
33463
- "use strict";
33464
- init_zod();
33465
- init_knowledge();
33466
- init_push();
33467
- inkSaveSchema = external_exports.object({
33468
- content: external_exports.string().describe("\u8981\u4FDD\u5B58\u7684\u5185\u5BB9\uFF08\u5FC5\u586B\uFF09"),
33469
- title: external_exports.string().describe("\u6807\u9898\uFF08Claude \u81EA\u52A8\u751F\u6210\uFF09"),
33470
- tags: external_exports.array(external_exports.string()).optional().default([]).describe("\u6807\u7B7E\uFF08Claude \u81EA\u52A8\u751F\u6210\uFF0C\u7528\u6237\u53EF\u6307\u5B9A\uFF09"),
33471
- category: external_exports.enum(["insight", "decision", "analysis", "idea", "reference", "action"]).optional().default("reference").describe("\u5206\u7C7B\uFF1Ainsight / decision / analysis / idea / reference / action"),
33472
- source_type: external_exports.enum(["conversation", "url", "manual"]).optional().default("conversation").describe("\u6765\u6E90\u7C7B\u578B\uFF1Aconversation / url / manual"),
33473
- url: external_exports.string().optional().describe("\u6765\u6E90 URL\uFF08\u5982\u679C\u662F\u5916\u90E8\u7D20\u6750\uFF09")
33474
- });
33475
- inkSearchSchema = external_exports.object({
33476
- query: external_exports.string().optional().describe("\u641C\u7D22\u5173\u952E\u8BCD"),
33477
- tags: external_exports.array(external_exports.string()).optional().describe("\u6309\u6807\u7B7E\u8FC7\u6EE4"),
33478
- category: external_exports.enum(["insight", "decision", "analysis", "idea", "reference", "action"]).optional().describe("\u6309\u5206\u7C7B\u8FC7\u6EE4"),
33479
- date_from: external_exports.string().optional().describe("\u8D77\u59CB\u65E5\u671F\uFF08ISO \u683C\u5F0F\uFF09"),
33480
- date_to: external_exports.string().optional().describe("\u622A\u6B62\u65E5\u671F\uFF08ISO \u683C\u5F0F\uFF09"),
33481
- limit: external_exports.number().optional().default(10).describe("\u8FD4\u56DE\u6570\u91CF\uFF0C\u9ED8\u8BA4 10")
33482
- });
33483
- inkGetSchema = external_exports.object({
33484
- id: external_exports.string().describe("\u77E5\u8BC6\u7247\u6BB5 ID")
33485
- });
33486
- inkReviewSchema = external_exports.object({
33487
- period: external_exports.enum(["today", "week", "month", "custom"]).optional().default("week").describe("\u56DE\u987E\u65F6\u95F4\u6BB5\uFF1Atoday / week / month / custom"),
33488
- date_from: external_exports.string().optional().describe("\u81EA\u5B9A\u4E49\u8D77\u59CB\u65E5\u671F\uFF08ISO \u683C\u5F0F\uFF0Cperiod=custom \u65F6\u4F7F\u7528\uFF09"),
33489
- date_to: external_exports.string().optional().describe("\u81EA\u5B9A\u4E49\u622A\u6B62\u65E5\u671F\uFF08ISO \u683C\u5F0F\uFF0Cperiod=custom \u65F6\u4F7F\u7528\uFF09"),
33490
- category: external_exports.enum(["insight", "decision", "analysis", "idea", "reference", "action"]).optional().describe("\u6309\u5206\u7C7B\u8FC7\u6EE4")
33491
- });
33492
- inkUpdateSchema = external_exports.object({
33493
- id: external_exports.string().describe("\u77E5\u8BC6\u7247\u6BB5 ID"),
33494
- title: external_exports.string().optional().describe("\u65B0\u6807\u9898"),
33495
- content: external_exports.string().optional().describe("\u65B0\u5185\u5BB9"),
33496
- tags: external_exports.array(external_exports.string()).optional().describe("\u65B0\u6807\u7B7E\uFF08\u5B8C\u6574\u66FF\u6362\uFF09"),
33497
- category: external_exports.enum(["insight", "decision", "analysis", "idea", "reference", "action"]).optional().describe("\u65B0\u5206\u7C7B")
33498
- });
33499
- inkDeleteSchema = external_exports.object({
33500
- id: external_exports.string().describe("\u77E5\u8BC6\u7247\u6BB5 ID"),
33501
- confirm: external_exports.boolean().optional().default(false).describe("\u786E\u8BA4\u5220\u9664\uFF08\u5FC5\u987B\u4E3A true \u624D\u4F1A\u6267\u884C\u5220\u9664\uFF09")
33502
- });
33503
- inkCompileSchema = external_exports.object({
33504
- ids: external_exports.array(external_exports.string()).optional().describe("\u6307\u5B9A\u8981\u6574\u5408\u7684\u77E5\u8BC6\u7247\u6BB5 ID \u5217\u8868"),
33505
- query: external_exports.string().optional().describe("\u641C\u7D22\u6761\u4EF6\uFF08\u4E0E ids \u4E8C\u9009\u4E00\uFF09"),
33506
- tags: external_exports.array(external_exports.string()).optional().describe("\u6309\u6807\u7B7E\u7B5B\u9009\uFF08\u4E0E query \u642D\u914D\uFF09"),
33507
- format: external_exports.enum(["outline", "article", "summary"]).optional().default("summary").describe("\u8F93\u51FA\u683C\u5F0F\uFF1Aoutline\uFF08\u5927\u7EB2\uFF09/ article\uFF08\u6587\u7AE0\uFF09/ summary\uFF08\u6458\u8981\uFF09"),
33508
- instruction: external_exports.string().optional().describe("\u989D\u5916\u6574\u5408\u6307\u4EE4")
33509
- });
33510
- inkTagsSchema = external_exports.object({
33511
- action: external_exports.enum(["list", "rename", "merge"]).describe("\u64CD\u4F5C\uFF1Alist\uFF08\u5217\u51FA\u6240\u6709\u6807\u7B7E\uFF09/ rename\uFF08\u91CD\u547D\u540D\uFF09/ merge\uFF08\u5408\u5E76\uFF09"),
33512
- tag: external_exports.string().optional().describe("\u76EE\u6807\u6807\u7B7E\uFF08rename/merge \u65F6\u4F7F\u7528\uFF09"),
33513
- new_tag: external_exports.string().optional().describe("\u65B0\u6807\u7B7E\u540D\uFF08rename \u65F6\u4F7F\u7528\uFF09"),
33514
- source_tags: external_exports.array(external_exports.string()).optional().describe("\u8981\u5408\u5E76\u7684\u6E90\u6807\u7B7E\u5217\u8868\uFF08merge \u65F6\u4F7F\u7528\uFF09")
33515
- });
33516
- }
33517
- });
33518
-
33519
- // src/index.ts
33520
- var index_exports = {};
33521
- async function main() {
33522
- try {
33523
- const state = await readState();
33524
- if (state.config.workflowDir) {
33525
- setWorkDir(state.config.workflowDir);
33526
- console.error(`[ClaudeInk MCP] workDir restored: ${state.config.workflowDir}`);
33527
- }
33528
- } catch {
33529
- }
33530
- const transport = new StdioServerTransport();
33531
- await server.connect(transport);
33532
- console.error("[ClaudeInk MCP] Server started on stdio (12 tools)");
33533
- }
33534
- var server;
33535
- var init_index = __esm({
33536
- "src/index.ts"() {
33537
- "use strict";
33538
- init_mcp();
33539
- init_stdio2();
33540
- init_source();
33541
- init_subscribe();
33542
- init_sync();
33543
- init_workflow();
33544
- init_ink();
33545
- init_state();
33546
- server = new McpServer({
33547
- name: "ClaudeInk",
33548
- version: "1.0.0"
33549
- });
33550
- server.tool("workflow.init", "\u521D\u59CB\u5316\u77E5\u8BC6\u5E93\uFF08\u521B\u5EFA\u76EE\u5F55 + \u6FC0\u6D3B License + \u540C\u6B65\u4E91\u7AEF\uFF09", workflowInitSchema.shape, async (input) => {
33354
+ 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) => {
33551
33355
  const result = await workflowInit(input);
33552
33356
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
33553
33357
  });
33554
- server.tool("sync", "\u4ECE\u4E91\u7AEF\u540C\u6B65\u77E5\u8BC6\u5143\u6570\u636E", syncSchema.shape, async (input) => {
33358
+ server.tool("ink.sync", "\u4ECE\u4E91\u7AEF\u540C\u6B65\u77E5\u8BC6\u5143\u6570\u636E", syncSchema.shape, async (input) => {
33555
33359
  const result = await sync2(input);
33556
33360
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
33557
33361
  });
33558
- server.tool("ink.save", "\u4FDD\u5B58\u77E5\u8BC6\u7247\u6BB5\u5230\u672C\u5730\u77E5\u8BC6\u5E93\uFF08\u5BF9\u8BDD\u6D1E\u5BDF\u3001\u51B3\u7B56\u3001\u5206\u6790\u7B49\uFF09", inkSaveSchema.shape, async (input) => {
33362
+ server.tool("ink.save", "\u4FDD\u5B58\u6216\u66F4\u65B0\u77E5\u8BC6\u7D20\u6750\uFF08\u6709 id \u66F4\u65B0\uFF0C\u65E0 id \u65B0\u5EFA\uFF09", inkSaveSchema.shape, async (input) => {
33559
33363
  const result = await inkSave(input);
33560
33364
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
33561
33365
  });
33562
- server.tool("ink.search", "\u641C\u7D22\u77E5\u8BC6\u5E93\uFF08\u652F\u6301\u5173\u952E\u8BCD\u3001\u6807\u7B7E\u3001\u5206\u7C7B\u3001\u65F6\u95F4\u8303\u56F4\u8FC7\u6EE4\uFF09", inkSearchSchema.shape, async (input) => {
33563
- const result = await inkSearch(input);
33564
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
33565
- });
33566
- server.tool("ink.get", "\u83B7\u53D6\u77E5\u8BC6\u7247\u6BB5\u5B8C\u6574\u5185\u5BB9", inkGetSchema.shape, async (input) => {
33567
- const result = await inkGet(input);
33568
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
33569
- });
33570
- server.tool("ink.review", "\u6309\u65F6\u95F4\u6BB5\u56DE\u987E\u77E5\u8BC6\u5E93\uFF08\u7EDF\u8BA1 + \u5217\u8868\uFF09", inkReviewSchema.shape, async (input) => {
33571
- const result = await inkReview(input);
33572
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
33573
- });
33574
- server.tool("ink.update", "\u66F4\u65B0\u5DF2\u4FDD\u5B58\u7684\u77E5\u8BC6\u7247\u6BB5\uFF08\u6807\u9898/\u5185\u5BB9/\u6807\u7B7E/\u5206\u7C7B\uFF09", inkUpdateSchema.shape, async (input) => {
33575
- const result = await inkUpdate(input);
33576
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
33577
- });
33578
33366
  server.tool("ink.delete", "\u5220\u9664\u77E5\u8BC6\u7247\u6BB5\uFF08\u9700\u786E\u8BA4\uFF09", inkDeleteSchema.shape, async (input) => {
33579
33367
  const result = await inkDelete(input);
33580
33368
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
33581
33369
  });
33582
- server.tool("ink.compile", "\u6574\u5408\u591A\u6761\u77E5\u8BC6\u7247\u6BB5\u4E3A\u7ED3\u6784\u5316\u5185\u5BB9\uFF08\u6309 ID \u6216\u641C\u7D22\u6761\u4EF6\uFF09", inkCompileSchema.shape, async (input) => {
33583
- const result = await inkCompile(input);
33370
+ server.tool("ink.write", "\u5199\u6587\u7AE0\u4FDD\u5B58\u4E3A\u8349\u7A3F\u3002Claude \u5199\u5B8C\u535A\u5BA2\u6587\u7AE0\u540E\u81EA\u52A8\u8C03\u7528\uFF0C\u63D0\u4F9B\u6807\u9898\u3001Markdown \u5185\u5BB9\u3001\u5C01\u9762\u56FE\u548C\u6807\u7B7E\u3002", inkWriteSchema.shape, async (input) => {
33371
+ const result = await inkWrite(input);
33584
33372
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
33585
33373
  });
33586
33374
  server.tool("ink.tags", "\u6807\u7B7E\u7BA1\u7406\uFF08\u5217\u51FA / \u91CD\u547D\u540D / \u5408\u5E76\u6807\u7B7E\uFF09", inkTagsSchema.shape, async (input) => {
33587
33375
  const result = await inkTags(input);
33588
33376
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
33589
33377
  });
33590
- server.tool("source.crawl", "\u89E6\u53D1\u722C\u866B\u6293\u53D6\uFF08\u5185\u5BB9\u81EA\u52A8\u5B58\u5165\u77E5\u8BC6\u5E93\uFF09", sourceCrawlSchema.shape, async (input) => {
33378
+ server.tool("ink.crawl", "\u89E6\u53D1\u722C\u866B\u6293\u53D6\uFF08\u5185\u5BB9\u81EA\u52A8\u5B58\u5165\u77E5\u8BC6\u5E93\uFF09", sourceCrawlSchema.shape, async (input) => {
33591
33379
  const result = await sourceCrawl(input);
33592
33380
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
33593
33381
  });
33594
- server.tool("source.subscribe", "\u7BA1\u7406\u8BA2\u9605\u6E90\uFF08\u6DFB\u52A0/\u5220\u9664/\u5217\u51FA\u722C\u866B\u6E90\uFF09", sourceSubscribeSchema.shape, async (input) => {
33382
+ server.tool("ink.subscribe", "\u7BA1\u7406\u8BA2\u9605\u6E90\uFF08\u6DFB\u52A0/\u5220\u9664/\u5217\u51FA\u722C\u866B\u6E90\uFF09", sourceSubscribeSchema.shape, async (input) => {
33595
33383
  const result = await sourceSubscribe(input);
33596
33384
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
33597
33385
  });
33598
- main().catch((err) => {
33599
- console.error("[ClaudeInk MCP] Fatal error:", err);
33386
+ main().catch(async (err) => {
33387
+ await log("ERROR", "server", `fatal: ${err.message || err}`);
33600
33388
  process.exit(1);
33601
33389
  });
33602
33390
  }
33603
33391
  });
33604
33392
 
33605
33393
  // src/cli.ts
33606
- import { writeFile as writeFile4, readFile as readFile5, mkdir as mkdir5, cp, access as access2 } from "fs/promises";
33607
- import { join as join6, dirname } from "path";
33394
+ import { writeFile as writeFile4, readFile as readFile6, mkdir as mkdir6, cp, access as access2 } from "fs/promises";
33395
+ import { join as join7, dirname } from "path";
33608
33396
  import { fileURLToPath as fileURLToPath3 } from "url";
33609
33397
  var args = process.argv.slice(2);
33610
33398
  var command = args[0];
33611
33399
  var __filename = fileURLToPath3(import.meta.url);
33612
33400
  var __dirname = dirname(__filename);
33613
- var WORKFLOW_SRC = join6(__dirname, "..", "workflow");
33401
+ var WORKFLOW_SRC = join7(__dirname, "..", "workflow");
33614
33402
  async function init() {
33615
33403
  const keyIdx = args.indexOf("--key");
33616
33404
  const key = keyIdx >= 0 ? args[keyIdx + 1] : void 0;
@@ -33626,8 +33414,8 @@ async function init() {
33626
33414
  console.log("\u{1F4E6} \u91CA\u653E\u5DE5\u4F5C\u6D41\u6A21\u677F...");
33627
33415
  const items = ["CLAUDE.md", "base-rules.md", "platforms", "accounts", "tools"];
33628
33416
  for (const item of items) {
33629
- const src = join6(WORKFLOW_SRC, item);
33630
- const dest = join6(cwd, item);
33417
+ const src = join7(WORKFLOW_SRC, item);
33418
+ const dest = join7(cwd, item);
33631
33419
  try {
33632
33420
  await access2(dest);
33633
33421
  console.log(` \u23ED\uFE0F ${item} \u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7`);
@@ -33647,14 +33435,14 @@ async function init() {
33647
33435
  ".claudeink"
33648
33436
  ];
33649
33437
  for (const dir of dirs) {
33650
- await mkdir5(join6(cwd, dir), { recursive: true });
33438
+ await mkdir6(join7(cwd, dir), { recursive: true });
33651
33439
  }
33652
33440
  console.log(" \u2705 sources/, templates/, .claudeink/");
33653
33441
  const { glob: glob2 } = await Promise.resolve().then(() => (init_esm5(), esm_exports));
33654
33442
  const yamlFiles = await glob2("accounts/*.yaml", { cwd, ignore: "accounts/_template.yaml" });
33655
33443
  for (const yamlFile of yamlFiles) {
33656
33444
  try {
33657
- const content = await readFile5(join6(cwd, yamlFile), "utf-8");
33445
+ const content = await readFile6(join7(cwd, yamlFile), "utf-8");
33658
33446
  const idMatch = content.match(/^id:\s*"?([^"\n]+)"?/m);
33659
33447
  if (idMatch) {
33660
33448
  const id = idMatch[1].trim();
@@ -33664,9 +33452,9 @@ async function init() {
33664
33452
  const drafts = (draftsMatch?.[1] || `accounts/${id}/drafts/`).replace("{id}", id).trim();
33665
33453
  const published = (publishedMatch?.[1] || `accounts/${id}/published/`).replace("{id}", id).trim();
33666
33454
  const assets = (assetsMatch?.[1] || `accounts/${id}/assets/`).replace("{id}", id).trim();
33667
- await mkdir5(join6(cwd, drafts), { recursive: true });
33668
- await mkdir5(join6(cwd, published), { recursive: true });
33669
- await mkdir5(join6(cwd, assets), { recursive: true });
33455
+ await mkdir6(join7(cwd, drafts), { recursive: true });
33456
+ await mkdir6(join7(cwd, published), { recursive: true });
33457
+ await mkdir6(join7(cwd, assets), { recursive: true });
33670
33458
  console.log(` \u2705 \u8D26\u53F7 ${id}: ${drafts}, ${published}, ${assets}`);
33671
33459
  }
33672
33460
  } catch {
@@ -33682,7 +33470,7 @@ async function init() {
33682
33470
  const data = await res.json();
33683
33471
  if (data.userId) {
33684
33472
  await writeFile4(
33685
- join6(cwd, ".claudeink", "credentials.json"),
33473
+ join7(cwd, ".claudeink", "credentials.json"),
33686
33474
  JSON.stringify(data, null, 2),
33687
33475
  { mode: 384 }
33688
33476
  );
@@ -33696,11 +33484,11 @@ async function init() {
33696
33484
  console.log(" \u53EF\u7A0D\u540E\u624B\u52A8\u6FC0\u6D3B\u3002");
33697
33485
  }
33698
33486
  try {
33699
- await access2(join6(cwd, "tools", "crawler", "package.json"));
33487
+ await access2(join7(cwd, "tools", "crawler", "package.json"));
33700
33488
  console.log("\n\u{1F4E6} \u5B89\u88C5\u722C\u866B\u4F9D\u8D56...");
33701
33489
  const { execSync: execSync2 } = await import("child_process");
33702
33490
  execSync2("npm install --silent", {
33703
- cwd: join6(cwd, "tools", "crawler"),
33491
+ cwd: join7(cwd, "tools", "crawler"),
33704
33492
  stdio: "pipe"
33705
33493
  });
33706
33494
  console.log(" \u2705 \u722C\u866B\u4F9D\u8D56\u5DF2\u5B89\u88C5");