@keyou007/agent-bot 0.1.21 → 0.1.23

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 (53) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +16 -2
  3. package/README.zh.md +16 -2
  4. package/config.example.yaml +5 -0
  5. package/dist/config/loadConfig.js +4 -0
  6. package/dist/config/loadConfig.js.map +1 -1
  7. package/dist/config/schema.js +1 -0
  8. package/dist/config/schema.js.map +1 -1
  9. package/dist/feishu/CardRenderer.js +32 -3
  10. package/dist/feishu/CardRenderer.js.map +1 -1
  11. package/dist/feishu/FeishuMessageClient.js +2 -2
  12. package/dist/feishu/FeishuMessageClient.js.map +1 -1
  13. package/dist/index.js +44 -0
  14. package/dist/index.js.map +1 -1
  15. package/dist/local-files/LocalFileViewerServer.js +24 -10
  16. package/dist/local-files/LocalFileViewerServer.js.map +1 -1
  17. package/dist/local-files/MarkdownFileLinks.js +12 -5
  18. package/dist/local-files/MarkdownFileLinks.js.map +1 -1
  19. package/dist/local-files/TurnPreviewPage.js +133 -87
  20. package/dist/local-files/TurnPreviewPage.js.map +1 -1
  21. package/dist/proxy/ProxySessionController.js +12 -2
  22. package/dist/proxy/ProxySessionController.js.map +1 -1
  23. package/dist/state/StateStore.js +25 -0
  24. package/dist/state/StateStore.js.map +1 -1
  25. package/dist/state/migrations.js +12 -0
  26. package/dist/state/migrations.js.map +1 -1
  27. package/dist/updates/AutomaticUpdatePreparer.js +66 -0
  28. package/dist/updates/AutomaticUpdatePreparer.js.map +1 -0
  29. package/dist/updates/DailyUpdateMonitor.js +261 -0
  30. package/dist/updates/DailyUpdateMonitor.js.map +1 -0
  31. package/dist/updates/PublishedRelease.js +43 -0
  32. package/dist/updates/PublishedRelease.js.map +1 -0
  33. package/dist/updates/types.js +2 -0
  34. package/dist/updates/types.js.map +1 -0
  35. package/npm-shrinkwrap.json +2 -2
  36. package/package.json +1 -1
  37. package/skills/agent-bot/SKILL.md +2 -0
  38. package/src/config/loadConfig.ts +4 -0
  39. package/src/config/schema.ts +4 -1
  40. package/src/feishu/CardRenderer.ts +35 -3
  41. package/src/feishu/FeishuMessageClient.ts +2 -1
  42. package/src/feishu/types.ts +1 -1
  43. package/src/index.ts +40 -0
  44. package/src/local-files/LocalFileViewerServer.ts +23 -11
  45. package/src/local-files/MarkdownFileLinks.ts +12 -7
  46. package/src/local-files/TurnPreviewPage.ts +134 -88
  47. package/src/proxy/ProxySessionController.ts +14 -2
  48. package/src/state/StateStore.ts +31 -0
  49. package/src/state/migrations.ts +12 -0
  50. package/src/updates/AutomaticUpdatePreparer.ts +76 -0
  51. package/src/updates/DailyUpdateMonitor.ts +252 -0
  52. package/src/updates/PublishedRelease.ts +44 -0
  53. package/src/updates/types.ts +19 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DailyUpdateMonitor.js","sourceRoot":"","sources":["../../src/updates/DailyUpdateMonitor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import { z } from "zod";
2
+ import { AGENT_BOT_PACKAGE_NAME } from "../cli/SelfUpdater.js";
3
+ export const stableVersionSchema = z.string().regex(/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/u);
4
+ export async function readLatestStableVersion() {
5
+ const text = await fetchText(`https://registry.npmjs.org/${encodeURIComponent(AGENT_BOT_PACKAGE_NAME)}/latest`, 256_000);
6
+ return z.object({ version: stableVersionSchema }).parse(JSON.parse(text)).version;
7
+ }
8
+ export async function readReleaseNotes(version) {
9
+ stableVersionSchema.parse(version);
10
+ const changelog = await fetchText(`https://raw.githubusercontent.com/keyou/agent-bot/v${version}/CHANGELOG.md`, 2_000_000);
11
+ return extractReleaseNotes(changelog, version);
12
+ }
13
+ export function extractReleaseNotes(changelog, version) {
14
+ const sections = changelog.split(/^## /mu).slice(1);
15
+ const section = sections.find((value) => value.split(/\r?\n/u, 1)[0]?.startsWith(`[${version}]`));
16
+ const notes = section?.includes("\n") ? section.slice(section.indexOf("\n") + 1).trim() : undefined;
17
+ if (!notes)
18
+ throw new Error(`Release notes are unavailable for Agent Bot ${version}.`);
19
+ return notes.length > 4_000 ? `${notes.slice(0, 3_900)}\n\n[完整更新日志](https://github.com/keyou/agent-bot/releases/tag/v${version})` : notes;
20
+ }
21
+ async function fetchText(url, maxBytes) {
22
+ const response = await fetch(url, { signal: AbortSignal.timeout(15_000) });
23
+ if (!response.ok || !response.body)
24
+ throw new Error(`Release request failed: HTTP ${response.status}.`);
25
+ const reader = response.body.getReader();
26
+ const chunks = [];
27
+ let size = 0;
28
+ try {
29
+ while (true) {
30
+ const { done, value } = await reader.read();
31
+ if (done)
32
+ return Buffer.concat(chunks).toString("utf8");
33
+ size += value.byteLength;
34
+ if (size > maxBytes)
35
+ throw new Error("Release response exceeds the size limit.");
36
+ chunks.push(value);
37
+ }
38
+ }
39
+ finally {
40
+ await reader.cancel();
41
+ }
42
+ }
43
+ //# sourceMappingURL=PublishedRelease.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PublishedRelease.js","sourceRoot":"","sources":["../../src/updates/PublishedRelease.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/updates/types.ts"],"names":[],"mappings":""}
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@keyou007/agent-bot",
3
- "version": "0.1.21",
3
+ "version": "0.1.23",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@keyou007/agent-bot",
9
- "version": "0.1.21",
9
+ "version": "0.1.23",
10
10
  "license": "GPL-3.0-only",
11
11
  "dependencies": {
12
12
  "@agentclientprotocol/sdk": "1.2.1",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keyou007/agent-bot",
3
- "version": "0.1.21",
3
+ "version": "0.1.23",
4
4
  "type": "module",
5
5
  "description": "Use Codex, TraeX, and compatible coding agents from Lark/Feishu.",
6
6
  "license": "GPL-3.0-only",
@@ -158,6 +158,8 @@ agentbot server stop
158
158
 
159
159
  `update` is only for npm-installed Agent Bot packages. It verifies the new package, sends a safe-restart card, waits for active tasks, and restarts immediately when the service is already idle. It automatically restores the prior version if activation fails. It refuses source checkouts and `npm link` installations.
160
160
 
161
+ The Feishu service also checks stable npm `latest` once daily at a persisted random time between 10:00 and 17:00 (server local time). A new version sends the owner a private release-notes card with 60 seconds to cancel. If not cancelled, preparation runs in the background and activation waits for tasks, final deliveries, and the quiet inbound window before restarting. Each version is notified once per Profile; cancellation survives restarts. An interrupted countdown resumes with a fresh minute on the same card. No private recipient, unconfirmed notification delivery, or missing release notes means no automatic installation. Source/npm-link protections still apply. Set `updates.enabled: false` in the Profile config and safely restart to disable checks. Do not bypass the countdown or idle gate.
162
+
161
163
  Autostart is Profile-specific. Use `server autostart enable` for login startup, `server autostart enable --linger` on Linux only when the user explicitly requests startup before login, and `server autostart disable` to remove registration without stopping the current Server. Disabling Agent Bot autostart must not disable Linux user lingering because other services may use it.
162
164
 
163
165
  Use safe restart by default. Prefer `agentbot task restart` when hosted so the current task is resolved automatically. Use `--immediate` or `task restart --force` only when the user explicitly accepts interruption.
@@ -26,6 +26,10 @@ const DEFAULT_CONFIG = `feishu:
26
26
  console:
27
27
  enabled: true
28
28
 
29
+ updates:
30
+ # Daily stable update check, private 60-second cancellation window, then safe update.
31
+ enabled: true
32
+
29
33
  fileViewer:
30
34
  enabled: true
31
35
  # Use 0.0.0.0 to accept LAN connections and automatically prefer
@@ -57,6 +57,7 @@ export const agentConfigSchema = z.object({
57
57
  });
58
58
 
59
59
  export const appConfigSchema = z.object({
60
+ updates: z.object({ enabled: z.boolean().default(true) }).default({ enabled: true }),
60
61
  console: z
61
62
  .object({
62
63
  enabled: z.boolean().default(true),
@@ -107,4 +108,6 @@ export type AgentConfig = Omit<ParsedAgentConfig, "defaults"> & {
107
108
  defaults?: AgentExecutionDefaults;
108
109
  };
109
110
  export type GroupNameFormatConfig = z.infer<typeof groupNameFormatSchema>;
110
- export type AppConfig = z.infer<typeof appConfigSchema>;
111
+ export type AppConfig = Omit<z.infer<typeof appConfigSchema>, "updates"> & {
112
+ updates?: { enabled: boolean };
113
+ };
@@ -12,6 +12,7 @@ import type {
12
12
  } from "../runtime/types.js";
13
13
  import type { TurnActivity, TurnViewState, TurnViewStatus } from "../presentation/turnViewTypes.js";
14
14
  import { truncateMiddle, truncateText } from "../utils/markdown.js";
15
+ import type { UpdateNotice } from "../updates/types.js";
15
16
  import { localCardImage } from "./LocalCardImage.js";
16
17
 
17
18
  export interface StartupStatusView {
@@ -953,6 +954,33 @@ export class CardRenderer {
953
954
  };
954
955
  }
955
956
 
957
+ renderUpdateNotice(view: UpdateNotice, now = Date.now()): Record<string, unknown> {
958
+ const cancellable = view.status === "announcing" || view.status === "countdown";
959
+ const status = cancellable
960
+ ? `**自动更新倒计时:${Math.max(0, Math.ceil(((view.deadline ?? now + 60_000) - now) / 1_000))} 秒**`
961
+ : view.status === "cancelled" ? "已取消本版本自动更新,不再提醒。"
962
+ : view.status === "preparing" ? "正在下载并校验更新;任务结束后自动安装并重启。"
963
+ : view.status === "scheduled" ? "更新已就绪,等待任务和结果投递完成后自动重启。"
964
+ : view.status === "completed" ? "更新已完成。"
965
+ : "自动更新未完成,当前版本继续运行。";
966
+ const elements = [
967
+ markdown(`**Agent Bot** ${inlineCode(view.currentVersion)} → ${inlineCode(view.version)}`),
968
+ markdown(`**本版更新**\n${truncateText(view.notes, 4_000)}`),
969
+ { tag: "hr" },
970
+ markdown(status),
971
+ ];
972
+ if (view.error) elements.push(markdown(inlineCode(truncateText(view.error, 600))));
973
+ if (cancellable) {
974
+ elements.push(markdown("> 1 分钟内未取消将自动更新;不会中断正在执行的任务。"));
975
+ elements.push(taskActionRow([{
976
+ text: "取消本次更新",
977
+ value: { action: "agentbot_update_cancel", version: view.version, token: view.token },
978
+ }]));
979
+ }
980
+ return sectionCard("Agent Bot 更新提醒", elements,
981
+ view.status === "completed" ? "green" : view.status === "cancelled" ? "grey" : "blue");
982
+ }
983
+
956
984
  renderSafeRestartStatus(view: SafeRestartStatusView): Record<string, unknown> {
957
985
  const countdown = view.phase === "countdown"
958
986
  ? `${Math.max(0, Math.ceil((view.remainingMs ?? 0) / 1_000))}s`
@@ -2370,7 +2398,7 @@ function truncateToolResult(result: string): string {
2370
2398
  return `${result.slice(0, headLength)}${marker}${result.slice(-tailLength)}`;
2371
2399
  }
2372
2400
 
2373
- function displayFilePath(filePath: string, projectCwd?: string): string {
2401
+ export function displayFilePath(filePath: string, projectCwd?: string): string {
2374
2402
  if (!projectCwd) return filePath;
2375
2403
  const pathApi = usesWindowsPaths(projectCwd, filePath) ? path.win32 : path;
2376
2404
  const normalizedCwd = pathApi.resolve(projectCwd);
@@ -2386,15 +2414,19 @@ function displayFilePath(filePath: string, projectCwd?: string): string {
2386
2414
  }
2387
2415
 
2388
2416
  function escapeMarkdownFilePath(filePath: string): string {
2389
- return filePath.replaceAll("\\.", "\\\\.");
2417
+ return filePath.replace(/[\\`*_[\]]/g, "\\$&");
2390
2418
  }
2391
2419
 
2392
2420
  function usesWindowsPaths(...values: string[]): boolean {
2393
2421
  return values.some((value) => /^[A-Za-z]:[\\/]/.test(value) || /^\\\\/.test(value));
2394
2422
  }
2395
2423
 
2424
+ export function toolStatusIcon(status: ToolState["status"]): string {
2425
+ return status === "failed" ? "❌" : status === "running" ? "⏳" : "✅";
2426
+ }
2427
+
2396
2428
  function toolPanelTitle(tool: ToolState): string {
2397
- const icon = tool.status === "failed" ? "❌" : tool.status === "running" ? "⏳" : "✅";
2429
+ const icon = toolStatusIcon(tool.status);
2398
2430
  const command = stripAnsi(tool.command ?? tool.title).trim();
2399
2431
  const meaningfulCommand = tool.kind === "web_search"
2400
2432
  ? tool.title
@@ -303,8 +303,9 @@ export class FeishuMessageClient implements FeishuOutbound {
303
303
  async sendInteractiveCard(
304
304
  contextKey: string,
305
305
  card: Record<string, unknown>,
306
+ idempotencyKey?: string,
306
307
  ): Promise<string | undefined> {
307
- return this.sendMessage(contextKey, "interactive", await this.prepareInteractiveCard(card));
308
+ return this.sendMessage(contextKey, "interactive", await this.prepareInteractiveCard(card), idempotencyKey);
308
309
  }
309
310
 
310
311
  async replyText(
@@ -72,7 +72,7 @@ export interface FeishuOutbound {
72
72
  sendText(contextKey: string, text: string): Promise<string | undefined>;
73
73
  sendFile?(contextKey: string, filePath: string): Promise<string | undefined>;
74
74
  sendMarkdown(contextKey: string, markdown: string, idempotencyKey?: string): Promise<string | undefined>;
75
- sendInteractiveCard(contextKey: string, card: Record<string, unknown>): Promise<string | undefined>;
75
+ sendInteractiveCard(contextKey: string, card: Record<string, unknown>, idempotencyKey?: string): Promise<string | undefined>;
76
76
  replyText?(
77
77
  contextKey: string,
78
78
  target: MessageReplyTarget,
package/src/index.ts CHANGED
@@ -29,6 +29,9 @@ import { ProxySessionController } from "./proxy/ProxySessionController.js";
29
29
  import type { AgentEnvironmentContext } from "./runtime/agentEnvironment.js";
30
30
  import { createAgentRuntimeRegistry } from "./runtime/createAgentRuntimeRegistry.js";
31
31
  import { StateStore } from "./state/StateStore.js";
32
+ import { DailyUpdateMonitor } from "./updates/DailyUpdateMonitor.js";
33
+ import { readLatestStableVersion, readReleaseNotes } from "./updates/PublishedRelease.js";
34
+ import { checkAutomaticUpdateSupport, prepareAutomaticUpdate } from "./updates/AutomaticUpdatePreparer.js";
32
35
  import { StartupNotifier } from "./startup/StartupNotifier.js";
33
36
  import { SessionMetadataHydrator } from "./startup/SessionMetadataHydrator.js";
34
37
  import { startFeishu } from "./startup/startFeishu.js";
@@ -106,6 +109,7 @@ let feishuConnector: FeishuConnector | undefined;
106
109
  let consoleConnector: ConsoleConnector | undefined;
107
110
  let startupNotifier: StartupNotifier | undefined;
108
111
  let safeRestartNotifier: SafeRestartNotifier | undefined;
112
+ let dailyUpdateMonitor: DailyUpdateMonitor | undefined;
109
113
  let controlServer: LocalControlServer | undefined;
110
114
  let serverReady = false;
111
115
 
@@ -157,14 +161,48 @@ const safeRestart = new SafeRestartScheduler({
157
161
  onStatus: (status) => safeRestartNotifier?.update(status),
158
162
  onStatusError: (error) => logger.warn({ error }, "Failed to publish safe restart status."),
159
163
  });
164
+ if (feishuOutbound && config.updates?.enabled !== false) {
165
+ dailyUpdateMonitor = new DailyUpdateMonitor({
166
+ store, outbound: feishuOutbound, logger, currentVersion: agentBotVersion,
167
+ userOpenId: () => config.feishu.userOpenId,
168
+ readLatest: readLatestStableVersion,
169
+ readNotes: readReleaseNotes,
170
+ checkSupport: () => checkAutomaticUpdateSupport({ home: agentBotHome(), configPath: activeConfigPath }),
171
+ hasPendingUpdate: () => shuttingDown || restartRequested || !!pendingSelfUpdatePlanPath || safeRestart.scheduled,
172
+ pendingVersion: () => pendingSelfUpdatePlanPath ? readPendingSelfUpdate(agentBotHome())?.plan.toVersion : undefined,
173
+ applyUpdate: async (version) => {
174
+ const prepared = await prepareAutomaticUpdate(version, { home: agentBotHome(), configPath: activeConfigPath });
175
+ try {
176
+ if (shuttingDown || restartRequested || pendingSelfUpdatePlanPath || safeRestart.scheduled) {
177
+ throw new Error("服务正在停止或已有更新/重启等待执行,本次自动更新已停止。");
178
+ }
179
+ const target = privateRestartNotificationTarget(config.feishu.userOpenId);
180
+ if (prepared.status === "prepared") {
181
+ assertSelfUpdatePlanPath(prepared.planPath, agentBotHome());
182
+ pendingSelfUpdatePlanPath = prepared.planPath;
183
+ }
184
+ safeRestart.schedule(`Agent Bot 自动更新到 ${version}`, target);
185
+ } catch (error) {
186
+ if (prepared.status === "prepared") releaseSelfUpdatePlan(prepared.planPath);
187
+ throw error;
188
+ }
189
+ },
190
+ });
191
+ }
160
192
  const controller = new ProxySessionController(config, store, runtimes, outbound, logger, {
161
193
  supervised,
162
194
  restart: requestRestart,
195
+ cancelAutomaticUpdate: async (action) => {
196
+ if (!dailyUpdateMonitor) throw new Error("自动更新功能未启用。");
197
+ await dailyUpdateMonitor.cancel(action);
198
+ },
163
199
  cancelSafeRestart: async (scheduleId) => {
164
200
  const cancelled = await safeRestart.cancelScheduled(scheduleId);
165
201
  if (cancelled && pendingSelfUpdatePlanPath) {
202
+ const version = readPendingSelfUpdate(agentBotHome())?.plan.toVersion;
166
203
  releaseSelfUpdatePlan(pendingSelfUpdatePlanPath);
167
204
  pendingSelfUpdatePlanPath = undefined;
205
+ if (version) await dailyUpdateMonitor?.cancelPreparedUpdate(version);
168
206
  }
169
207
  return cancelled;
170
208
  },
@@ -229,6 +267,7 @@ await controller.recoverInterruptedTasks().catch((error: unknown) => {
229
267
  });
230
268
  consoleConnector?.start();
231
269
  recoverPendingSelfUpdate();
270
+ await dailyUpdateMonitor?.start();
232
271
 
233
272
  function recoverPendingSelfUpdate(): void {
234
273
  const pending = readPendingSelfUpdate(agentBotHome());
@@ -530,6 +569,7 @@ async function shutdown(
530
569
  ): Promise<void> {
531
570
  if (shuttingDown) return;
532
571
  shuttingDown = true;
572
+ await dailyUpdateMonitor?.stop();
533
573
  if (pendingSelfUpdatePlanPath) {
534
574
  releaseSelfUpdatePlan(pendingSelfUpdatePlanPath);
535
575
  pendingSelfUpdatePlanPath = undefined;
@@ -622,10 +622,12 @@ export class LocalFileViewerServer {
622
622
 
623
623
  let closed = false;
624
624
  let pendingUpdate: NodeJS.Timeout | undefined;
625
+ let previousStat: fs.Stats | undefined;
625
626
  const sendSnapshot = () => {
626
627
  if (closed || response.destroyed) return;
627
628
  try {
628
629
  const stat = fs.statSync(filePath);
630
+ previousStat = stat;
629
631
  if (!stat.isFile()) throw new Error("Path is no longer a file");
630
632
  const snapshot = this.renderFileSnapshot(filePath, stat);
631
633
  writeServerSentEvent(response, "update", JSON.stringify({
@@ -644,17 +646,27 @@ export class LocalFileViewerServer {
644
646
  pendingUpdate = setTimeout(sendSnapshot, 100);
645
647
  pendingUpdate.unref();
646
648
  };
647
- const watcher = (current: fs.Stats, previous: fs.Stats) => {
648
- if (
649
- current.mtimeMs === previous.mtimeMs
650
- && current.ctimeMs === previous.ctimeMs
651
- && current.size === previous.size
652
- && current.nlink === previous.nlink
653
- ) return;
654
- scheduleSnapshot();
655
- };
656
- fs.watchFile(filePath, { interval: 1_000, persistent: false }, watcher);
657
649
  sendSnapshot();
650
+ // Compare against the sent snapshot so edits during watcher startup cannot be missed.
651
+ let checking = false;
652
+ const poller = setInterval(() => {
653
+ if (closed || checking) return;
654
+ checking = true;
655
+ fs.stat(filePath, (error, stat) => {
656
+ checking = false;
657
+ if (closed) return;
658
+ const current = error ? undefined : stat;
659
+ if (
660
+ current?.mtimeMs === previousStat?.mtimeMs
661
+ && current?.ctimeMs === previousStat?.ctimeMs
662
+ && current?.size === previousStat?.size
663
+ && current?.nlink === previousStat?.nlink
664
+ ) return;
665
+ previousStat = current;
666
+ scheduleSnapshot();
667
+ });
668
+ }, 1_000);
669
+ poller.unref();
658
670
  const keepAlive = setInterval(() => {
659
671
  if (!closed && !response.destroyed) response.write(": keep-alive\n\n");
660
672
  }, 15_000);
@@ -665,7 +677,7 @@ export class LocalFileViewerServer {
665
677
  closed = true;
666
678
  if (pendingUpdate) clearTimeout(pendingUpdate);
667
679
  clearInterval(keepAlive);
668
- fs.unwatchFile(filePath, watcher);
680
+ clearInterval(poller);
669
681
  };
670
682
  request.once("aborted", cleanup);
671
683
  response.once("close", cleanup);
@@ -8,8 +8,8 @@ export function isFileUrl(value: string): boolean {
8
8
 
9
9
  export function rewriteMarkdownFileLinks(
10
10
  tokens: Token[],
11
- markdownPath: string,
12
- createPreviewUrl: (filePath: string) => URL,
11
+ markdownPath: string | undefined,
12
+ createPreviewUrl: (filePath: string) => URL | undefined,
13
13
  ): void {
14
14
  for (const token of tokens) {
15
15
  const attribute = token.type === "link_open" ? "href" : token.type === "image" ? "src" : undefined;
@@ -18,9 +18,13 @@ export function rewriteMarkdownFileLinks(
18
18
  const local = resolveLocalTarget(target, markdownPath);
19
19
  if (local) {
20
20
  const url = createPreviewUrl(local.filePath);
21
- url.hash = local.hash;
22
- if (token.type === "image") url.searchParams.set("raw", "1");
23
- token.attrSet(attribute, url.toString());
21
+ if (url) {
22
+ url.hash = local.hash;
23
+ if (token.type === "image") url.searchParams.set("raw", "1");
24
+ token.attrSet(attribute, url.toString());
25
+ } else {
26
+ token.attrs = token.attrs?.filter(([name]) => name !== attribute) ?? null;
27
+ }
24
28
  } else if (isFileUrl(target)) {
25
29
  // File URLs are accepted by the parser only to convert them to signed HTTP URLs.
26
30
  token.attrs = token.attrs?.filter(([name]) => name !== attribute) ?? null;
@@ -30,7 +34,7 @@ export function rewriteMarkdownFileLinks(
30
34
  }
31
35
  }
32
36
 
33
- function resolveLocalTarget(target: string, markdownPath: string): { filePath: string; hash: string } | undefined {
37
+ function resolveLocalTarget(target: string, markdownPath: string | undefined): { filePath: string; hash: string } | undefined {
34
38
  if (/^(?:#|\?|\/\/)/u.test(target)) return undefined;
35
39
  const windows = process.platform === "win32";
36
40
  const normalized = windows ? target.replace(/%5c/giu, "/").replaceAll("\\", "/") : target;
@@ -44,11 +48,12 @@ function resolveLocalTarget(target: string, markdownPath: string): { filePath: s
44
48
  ? normalized.slice(0, reference.index) + normalized.slice(reference.index + reference[0].length)
45
49
  : normalized;
46
50
  if (drivePath && !windows) return undefined;
51
+ if (!markdownPath && !drivePath && !isFileUrl(normalized) && !path.isAbsolute(normalized)) return undefined;
47
52
 
48
53
  try {
49
54
  const url = drivePath
50
55
  ? new URL(`file:///${withoutReference.replace(/^\//u, "")}`)
51
- : new URL(withoutReference, pathToFileURL(markdownPath));
56
+ : new URL(withoutReference, markdownPath ? pathToFileURL(markdownPath) : "file:///");
52
57
  if (url.protocol !== "file:") return undefined;
53
58
  const filePath = fileURLToPath(url);
54
59
  if (!path.isAbsolute(filePath) || /[\x00-\x1f\x7f]/u.test(filePath)) return undefined;