cclawd 1.0.7 → 1.0.8

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 (168) hide show
  1. package/dist/{active-listener-DYmI7imH.js → active-listener-Dkhmfuwx.js} +2 -2
  2. package/dist/{api-key-rotation-DLU4jvSu.js → api-key-rotation-BOfI3cG3.js} +1 -1
  3. package/dist/{audio-preflight-C9TMbRb4.js → audio-preflight-CtkZ5SAs.js} +15 -15
  4. package/dist/{audio-transcription-runner-Q5zG_hYd.js → audio-transcription-runner-CbPqoiHX.js} +10 -10
  5. package/dist/{audit-membership-runtime-DhxSwFnF.js → audit-membership-runtime-hXUuer4x.js} +6 -6
  6. package/dist/build-info.json +3 -3
  7. package/dist/bundled/boot-md/handler.js +35 -35
  8. package/dist/bundled/bootstrap-extra-files/handler.js +5 -5
  9. package/dist/bundled/command-logger/handler.js +2 -2
  10. package/dist/bundled/session-memory/handler.js +35 -35
  11. package/dist/{channel-activity-Bx08UTAg.js → channel-activity-DWAER4wd.js} +2 -2
  12. package/dist/{commands-registry-llLVCTH9.js → commands-registry-BUyiA7nE.js} +2 -2
  13. package/dist/compact.runtime-DpcZpcTl.js +39 -0
  14. package/dist/{deliver-DJf2ZBpe.js → deliver-aHOaRbkt.js} +19 -19
  15. package/dist/deliver-runtime-D4bCsr6d.js +19 -0
  16. package/dist/deps-send-discord.runtime-BziKU-pE.js +19 -0
  17. package/dist/deps-send-imessage.runtime-CFRnDTqp.js +18 -0
  18. package/dist/deps-send-signal.runtime-BuOtABJm.js +17 -0
  19. package/dist/deps-send-slack.runtime-BOLqvMxW.js +17 -0
  20. package/dist/deps-send-telegram.runtime-DeEoFLv5.js +20 -0
  21. package/dist/deps-send-whatsapp.runtime-CG1uXYLY.js +43 -0
  22. package/dist/{diagnostic-BCCMF3O_.js → diagnostic-BdcXX9iJ.js} +2 -2
  23. package/dist/{env-aYXLHjfZ.js → env-lw2hsIUY.js} +1 -1
  24. package/dist/{fetch-bvgIiupu.js → fetch-C0iyt-Iz.js} +3 -3
  25. package/dist/{fetch-DCTUdr1U.js → fetch-D9NUULbj.js} +5 -5
  26. package/dist/{fetch-guard-CqpEmMQ2.js → fetch-guard-B5ZMnGaN.js} +2 -2
  27. package/dist/{frontmatter-DjZuS525.js → frontmatter-C_obXuTp.js} +3 -3
  28. package/dist/{github-copilot-token-CQmATy5E.js → github-copilot-token-8N63GdbE.js} +7 -7
  29. package/dist/{image-Q8E1-lZn.js → image-4x07m4Jl.js} +4 -4
  30. package/dist/image-runtime-smkMrIol.js +12 -0
  31. package/dist/{ir-CzM3SxId.js → ir-CsgNUpOU.js} +6 -6
  32. package/dist/llm-slug-generator.js +35 -35
  33. package/dist/{logger-ChbX1G7s.js → logger-CbUVl62f.js} +7 -7
  34. package/dist/{login-B0mtU11X.js → login-p_O59TVQ.js} +4 -4
  35. package/dist/{login-qr-DY_i60f5.js → login-qr-BCJpDsAy.js} +10 -10
  36. package/dist/{manager-FAQPC0uO.js → manager-CwYv8O3T.js} +12 -12
  37. package/dist/manager-runtime-D_jEoBr9.js +15 -0
  38. package/dist/{model-selection-wf3OY5DX.js → model-selection-Cv2Puf5z.js} +122 -122
  39. package/dist/{outbound-Bw0dOVS7.js → outbound-Chpiwybe.js} +6 -6
  40. package/dist/{outbound-attachment-1R6r9Pg_.js → outbound-attachment-BnAVJDLe.js} +2 -2
  41. package/dist/{paths-C0HLtPu0.js → paths-CehYKFsO.js} +7 -7
  42. package/dist/{paths-hfkBoC7i.js → paths-DkxwiA8g.js} +5 -5
  43. package/dist/{pi-embedded-BAHaY-Oh.js → pi-embedded-CJVNBk0y.js} +150 -150
  44. package/dist/pi-model-discovery-7IzK0Uc3.js +131 -0
  45. package/dist/pi-model-discovery-runtime-DABef3qy.js +12 -0
  46. package/dist/{pi-tools.before-tool-call.runtime-D_mthvtC.js → pi-tools.before-tool-call.runtime-BP2UvGJb.js} +10 -10
  47. package/dist/plugin-sdk/active-listener-CN-tMEvN.js +35 -0
  48. package/dist/plugin-sdk/api-key-rotation-CimGYMBc.js +176 -0
  49. package/dist/plugin-sdk/audio-preflight-C-xXBoE2.js +51 -0
  50. package/dist/plugin-sdk/audio-transcription-runner-CTIHpebA.js +2173 -0
  51. package/dist/plugin-sdk/audit-membership-runtime-BFatB2LJ.js +58 -0
  52. package/dist/plugin-sdk/channel-activity-DO0FEzyj.js +95 -0
  53. package/dist/plugin-sdk/channel-web-Da-__nUF.js +2238 -0
  54. package/dist/plugin-sdk/commands-registry-6no2NNrY.js +1118 -0
  55. package/dist/plugin-sdk/compact.runtime-CCoclu5e.js +35 -0
  56. package/dist/plugin-sdk/compat.js +35 -35
  57. package/dist/plugin-sdk/config-B9ODwgpz.js +37426 -0
  58. package/dist/plugin-sdk/deliver-B1fFpKjV.js +1757 -0
  59. package/dist/plugin-sdk/deliver-runtime-DB-VRMe1.js +15 -0
  60. package/dist/plugin-sdk/deps-send-discord.runtime-DklqycYG.js +15 -0
  61. package/dist/plugin-sdk/deps-send-imessage.runtime-Chs8zeon.js +14 -0
  62. package/dist/plugin-sdk/deps-send-signal.runtime-clW9aSJP.js +13 -0
  63. package/dist/plugin-sdk/deps-send-slack.runtime-BUx0LYY1.js +13 -0
  64. package/dist/plugin-sdk/deps-send-telegram.runtime-LECSHgMG.js +16 -0
  65. package/dist/plugin-sdk/deps-send-whatsapp.runtime-D2d65fw0.js +40 -0
  66. package/dist/plugin-sdk/diagnostic-CxIvS-C2.js +315 -0
  67. package/dist/plugin-sdk/dispatch-BqlR4dPx.js +105863 -0
  68. package/dist/plugin-sdk/env-b9k1PHMI.js +34 -0
  69. package/dist/plugin-sdk/fetch-PoxzAANT.js +326 -0
  70. package/dist/plugin-sdk/fetch-guard-4UVSZ0uS.js +164 -0
  71. package/dist/plugin-sdk/image-Ch6M4tnJ.js +2420 -0
  72. package/dist/plugin-sdk/image-runtime-CSh2o5wY.js +8 -0
  73. package/dist/plugin-sdk/ir-CugsqGH8.js +1312 -0
  74. package/dist/plugin-sdk/local-roots-adnEg9zb.js +217 -0
  75. package/dist/plugin-sdk/logger-D6zRubj0.js +1164 -0
  76. package/dist/plugin-sdk/login-CYvkQ0At.js +54 -0
  77. package/dist/plugin-sdk/login-qr-ll4NtaT5.js +316 -0
  78. package/dist/plugin-sdk/manager-CHy8IclH.js +3959 -0
  79. package/dist/plugin-sdk/manager-runtime-C70EkEr7.js +11 -0
  80. package/dist/plugin-sdk/outbound-Wzs2iN7X.js +216 -0
  81. package/dist/plugin-sdk/outbound-attachment-khXJwucX.js +17 -0
  82. package/dist/plugin-sdk/paths-BtVqCdw4.js +3063 -0
  83. package/dist/{pi-model-discovery-ItS07aJB.js → plugin-sdk/pi-model-discovery-Dh4ziodY.js} +2 -2
  84. package/dist/plugin-sdk/pi-model-discovery-runtime-b83Xe-HT.js +8 -0
  85. package/dist/plugin-sdk/pi-tools.before-tool-call.runtime-C1z5CDBF.js +349 -0
  86. package/dist/{proxy-fetch-c1ZUFFcO.js → plugin-sdk/proxy-fetch-CJEmoBxi.js} +1 -1
  87. package/dist/plugin-sdk/pw-ai-Dj3Cvlzl.js +1990 -0
  88. package/dist/plugin-sdk/qmd-manager-egHUAseQ.js +1581 -0
  89. package/dist/plugin-sdk/resolve-outbound-target-BiICvIKs.js +38 -0
  90. package/dist/plugin-sdk/runtime-whatsapp-login.runtime-DNApufzW.js +9 -0
  91. package/dist/plugin-sdk/runtime-whatsapp-outbound.runtime-CBmtfIQ8.js +13 -0
  92. package/dist/plugin-sdk/send-CScblaI4.js +532 -0
  93. package/dist/plugin-sdk/send-CeHhnld6.js +407 -0
  94. package/dist/plugin-sdk/send-DP_c8JfR.js +3277 -0
  95. package/dist/plugin-sdk/send-Dc5fI6e8.js +495 -0
  96. package/dist/plugin-sdk/send-l-77_s1_.js +2507 -0
  97. package/dist/plugin-sdk/session-CkOKZaqa.js +166 -0
  98. package/dist/plugin-sdk/signal.js +2 -2
  99. package/dist/plugin-sdk/skill-commands-BohYCgkq.js +336 -0
  100. package/dist/plugin-sdk/slash-commands.runtime-DpLfVTM6.js +8 -0
  101. package/dist/plugin-sdk/slash-dispatch.runtime-CASMHwpm.js +35 -0
  102. package/dist/plugin-sdk/slash-skill-commands.runtime-D7rrJEci.js +9 -0
  103. package/dist/plugin-sdk/sqlite-CJE3X7Mv.js +1005 -0
  104. package/dist/plugin-sdk/subagent-registry-runtime-B1oo5bih.js +35 -0
  105. package/dist/plugin-sdk/tables-D5VgpTmm.js +53 -0
  106. package/dist/plugin-sdk/target-errors-C6zZ_OpA.js +191 -0
  107. package/dist/{tokens-BWDIKewp.js → plugin-sdk/tokens-DUnJnpMS.js} +1 -1
  108. package/dist/plugin-sdk/web-TfUM1nSi.js +39 -0
  109. package/dist/plugin-sdk/whatsapp-actions-DuWJ0j1r.js +71 -0
  110. package/dist/proxy-fetch-BOh1PLOW.js +54 -0
  111. package/dist/{pw-ai-Ok6KGelf.js → pw-ai-DwH5GpEO.js} +9 -9
  112. package/dist/{qmd-manager-DhfEz4Ar.js → qmd-manager-DEscZz5_.js} +6 -6
  113. package/dist/{query-expansion-GqNV2iIE.js → query-expansion-BErUY8P2.js} +4 -4
  114. package/dist/runtime-whatsapp-login.runtime-BI3U306v.js +13 -0
  115. package/dist/runtime-whatsapp-outbound.runtime-Bsc2uD09.js +17 -0
  116. package/dist/{send-DwAoiT2p.js → send-BDnOgWIp.js} +25 -25
  117. package/dist/{send-CS0ocZHl.js → send-C-Q_WPMf.js} +3 -3
  118. package/dist/{send-6R8b9zsj.js → send-DUibfNQD.js} +5 -5
  119. package/dist/{send-DPflcjM5.js → send-DtBvCnPQ.js} +6 -6
  120. package/dist/{send-CEg4P96c.js → send-ORtn50qg.js} +5 -5
  121. package/dist/{session-BoIID5UR.js → session-B7imi6T5.js} +7 -7
  122. package/dist/{skill-commands-DhdiziMs.js → skill-commands-B9brPuiL.js} +9 -9
  123. package/dist/slash-commands.runtime-Cf6ygfBp.js +12 -0
  124. package/dist/slash-dispatch.runtime-CsmvhO5K.js +39 -0
  125. package/dist/slash-skill-commands.runtime-CX7stIEP.js +13 -0
  126. package/dist/subagent-registry-runtime-B_S1nf7y.js +39 -0
  127. package/dist/{subsystem-C8z6w6xC.js → subsystem-DfXy5gUB.js} +14 -14
  128. package/dist/{tables-DQusRhkD.js → tables-CjQqTOdD.js} +1 -1
  129. package/dist/{target-errors-CfavnC9U.js → target-errors-BZE1mc-W.js} +1 -1
  130. package/dist/tokens-6ul2IrzG.js +50 -0
  131. package/dist/{web-CrcrTQ2c.js → web-Cd8yK1Zq.js} +39 -39
  132. package/dist/{whatsapp-actions-B0u0ZAme.js → whatsapp-actions-CYEzUMBI.js} +15 -15
  133. package/dist/{workspace-CWDYHR27.js → workspace-DGIcKCCW.js} +20 -20
  134. package/extensions/cclawd-mfa-auth/README.md +118 -0
  135. package/extensions/cclawd-mfa-auth/index.ts +382 -0
  136. package/extensions/cclawd-mfa-auth/openclaw.plugin.json +34 -0
  137. package/extensions/cclawd-mfa-auth/package.json +27 -0
  138. package/extensions/cclawd-mfa-auth/src/auth-manager.ts +536 -0
  139. package/extensions/cclawd-mfa-auth/src/config.ts +82 -0
  140. package/extensions/cclawd-mfa-auth/src/dabby-client.ts +200 -0
  141. package/extensions/cclawd-mfa-auth/src/notification-service.ts +417 -0
  142. package/extensions/cclawd-mfa-auth/src/polling-manager.ts +232 -0
  143. package/extensions/cclawd-mfa-auth/src/providers/base.ts +25 -0
  144. package/extensions/cclawd-mfa-auth/src/providers/qr-code.ts +98 -0
  145. package/extensions/cclawd-mfa-auth/src/sensitive-detector.ts +159 -0
  146. package/extensions/cclawd-mfa-auth/src/session-resolver.ts +159 -0
  147. package/extensions/cclawd-mfa-auth/src/types.ts +156 -0
  148. package/extensions/mfa-auth/index.ts +675 -1028
  149. package/extensions/mfa-auth/openclaw.plugin.json +1 -1
  150. package/extensions/mfa-auth/src/notification-service.ts +2 -8
  151. package/package.json +453 -453
  152. package/dist/compact.runtime-BEn3giMt.js +0 -39
  153. package/dist/deliver-runtime-DkQ3XzGv.js +0 -19
  154. package/dist/deps-send-discord.runtime-BLpqSj6s.js +0 -19
  155. package/dist/deps-send-imessage.runtime-BFzyYqvR.js +0 -18
  156. package/dist/deps-send-signal.runtime-DT0TYCy1.js +0 -17
  157. package/dist/deps-send-slack.runtime-BhaGFfMX.js +0 -17
  158. package/dist/deps-send-telegram.runtime-B6Cic9NX.js +0 -20
  159. package/dist/deps-send-whatsapp.runtime-WtEhIq2S.js +0 -43
  160. package/dist/image-runtime-B1LFYfQ2.js +0 -12
  161. package/dist/manager-runtime-Da7ME9vS.js +0 -15
  162. package/dist/pi-model-discovery-runtime-DjM7Z1fx.js +0 -12
  163. package/dist/runtime-whatsapp-login.runtime-D4BRhQkK.js +0 -13
  164. package/dist/runtime-whatsapp-outbound.runtime-DJPpS6g-.js +0 -17
  165. package/dist/slash-commands.runtime-Cu1lTjV9.js +0 -12
  166. package/dist/slash-dispatch.runtime-DRVJEF4l.js +0 -39
  167. package/dist/slash-skill-commands.runtime-C373PJjv.js +0 -13
  168. package/dist/subagent-registry-runtime-D7hWBo1G.js +0 -39
@@ -1,20 +1,20 @@
1
- import "./paths-C0HLtPu0.js";
2
- import "./paths-hfkBoC7i.js";
3
- import "./subsystem-C8z6w6xC.js";
4
- import "./workspace-CWDYHR27.js";
5
- import "./logger-ChbX1G7s.js";
6
- import { Dr as normalizeWhatsAppTarget, Er as isWhatsAppGroupJid, dr as resolveWhatsAppAccount } from "./model-selection-wf3OY5DX.js";
7
- import "./github-copilot-token-CQmATy5E.js";
1
+ import "./paths-CehYKFsO.js";
2
+ import "./paths-DkxwiA8g.js";
3
+ import "./subsystem-DfXy5gUB.js";
4
+ import "./workspace-DGIcKCCW.js";
5
+ import "./logger-CbUVl62f.js";
6
+ import { Dr as normalizeWhatsAppTarget, Er as isWhatsAppGroupJid, dr as resolveWhatsAppAccount } from "./model-selection-Cv2Puf5z.js";
7
+ import "./github-copilot-token-8N63GdbE.js";
8
8
  import "./boolean-C7Ct_klp.js";
9
- import "./env-aYXLHjfZ.js";
10
- import "./frontmatter-DjZuS525.js";
11
- import "./fetch-DCTUdr1U.js";
12
- import "./fetch-guard-CqpEmMQ2.js";
13
- import "./ir-CzM3SxId.js";
9
+ import "./env-lw2hsIUY.js";
10
+ import "./frontmatter-C_obXuTp.js";
11
+ import "./fetch-D9NUULbj.js";
12
+ import "./fetch-guard-B5ZMnGaN.js";
13
+ import "./ir-CsgNUpOU.js";
14
14
  import "./render-IRnn-2gt.js";
15
- import { f as readReactionParams, h as readStringParam, i as ToolAuthorizationError, l as jsonResult, n as missingTargetError, o as createActionGate } from "./target-errors-CfavnC9U.js";
16
- import "./tables-DQusRhkD.js";
17
- import { r as sendReactionWhatsApp } from "./outbound-Bw0dOVS7.js";
15
+ import { f as readReactionParams, h as readStringParam, i as ToolAuthorizationError, l as jsonResult, n as missingTargetError, o as createActionGate } from "./target-errors-BZE1mc-W.js";
16
+ import "./tables-CjQqTOdD.js";
17
+ import { r as sendReactionWhatsApp } from "./outbound-Chpiwybe.js";
18
18
  //#region src/whatsapp/resolve-outbound-target.ts
19
19
  function resolveWhatsAppOutboundTarget(params) {
20
20
  const trimmed = params.to?.trim() ?? "";
@@ -1,10 +1,10 @@
1
- import { d as resolveRequiredHomeDir } from "./paths-hfkBoC7i.js";
2
- import { l as danger, m as shouldLogVerbose } from "./subsystem-C8z6w6xC.js";
3
- import { g as pathExists$1, n as logError, t as logDebug, y as resolveUserPath } from "./logger-ChbX1G7s.js";
1
+ import { d as resolveRequiredHomeDir } from "./paths-DkxwiA8g.js";
2
+ import { l as danger, m as shouldLogVerbose } from "./subsystem-DfXy5gUB.js";
3
+ import { g as pathExists$1, n as logError, t as logDebug, y as resolveUserPath } from "./logger-CbUVl62f.js";
4
4
  import fs from "node:fs/promises";
5
5
  import os from "node:os";
6
6
  import path from "node:path";
7
- import fs$1 from "node:fs";
7
+ import syncFs from "node:fs";
8
8
  import { promisify } from "node:util";
9
9
  import { execFile, spawn } from "node:child_process";
10
10
  import process$1 from "node:process";
@@ -566,7 +566,7 @@ function resolveBoundaryPathLexicalSync(params) {
566
566
  rootCanonicalPath: params.rootCanonicalPath,
567
567
  resolveParams: params.params,
568
568
  absolutePath: params.absolutePath,
569
- read: (cursor) => fs$1.lstatSync(cursor)
569
+ read: (cursor) => syncFs.lstatSync(cursor)
570
570
  });
571
571
  if (isPromiseLike(maybeStat)) throw new Error("Unexpected async lexical stat");
572
572
  const stat = maybeStat;
@@ -716,15 +716,15 @@ function resolvePathViaExistingAncestorSync(targetPath) {
716
716
  const normalized = path.resolve(targetPath);
717
717
  let cursor = normalized;
718
718
  const missingSuffix = [];
719
- while (!isFilesystemRoot(cursor) && !fs$1.existsSync(cursor)) {
719
+ while (!isFilesystemRoot(cursor) && !syncFs.existsSync(cursor)) {
720
720
  missingSuffix.unshift(path.basename(cursor));
721
721
  const parent = path.dirname(cursor);
722
722
  if (parent === cursor) break;
723
723
  cursor = parent;
724
724
  }
725
- if (!fs$1.existsSync(cursor)) return normalized;
725
+ if (!syncFs.existsSync(cursor)) return normalized;
726
726
  try {
727
- const resolvedAncestor = path.resolve(fs$1.realpathSync(cursor));
727
+ const resolvedAncestor = path.resolve(syncFs.realpathSync(cursor));
728
728
  if (missingSuffix.length === 0) return resolvedAncestor;
729
729
  return path.resolve(resolvedAncestor, ...missingSuffix);
730
730
  } catch {
@@ -749,7 +749,7 @@ function getPathKindSync(absolutePath, preserveFinalSymlink) {
749
749
  try {
750
750
  return {
751
751
  exists: true,
752
- kind: toResolvedKind(preserveFinalSymlink ? fs$1.lstatSync(absolutePath) : fs$1.statSync(absolutePath))
752
+ kind: toResolvedKind(preserveFinalSymlink ? syncFs.lstatSync(absolutePath) : syncFs.statSync(absolutePath))
753
753
  };
754
754
  } catch (error) {
755
755
  if (isNotFoundPathError(error)) return {
@@ -809,10 +809,10 @@ async function resolveSymlinkHopPath(symlinkPath) {
809
809
  }
810
810
  function resolveSymlinkHopPathSync(symlinkPath) {
811
811
  try {
812
- return path.resolve(fs$1.realpathSync(symlinkPath));
812
+ return path.resolve(syncFs.realpathSync(symlinkPath));
813
813
  } catch (error) {
814
814
  if (!isNotFoundPathError(error)) throw error;
815
- const linkTarget = fs$1.readlinkSync(symlinkPath);
815
+ const linkTarget = syncFs.readlinkSync(symlinkPath);
816
816
  return resolvePathViaExistingAncestorSync(path.resolve(path.dirname(symlinkPath), linkTarget));
817
817
  }
818
818
  }
@@ -836,7 +836,7 @@ function sameFileIdentity(left, right) {
836
836
  return sameFileIdentity$1(left, right);
837
837
  }
838
838
  function openVerifiedFileSync(params) {
839
- const ioFs = params.ioFs ?? fs$1;
839
+ const ioFs = params.ioFs ?? syncFs;
840
840
  const allowedType = params.allowedType ?? "file";
841
841
  const openReadFlags = ioFs.constants.O_RDONLY | (typeof ioFs.constants.O_NOFOLLOW === "number" ? ioFs.constants.O_NOFOLLOW : 0);
842
842
  let fd = null;
@@ -912,7 +912,7 @@ function canUseBoundaryFileOpen(ioFs) {
912
912
  return typeof ioFs.openSync === "function" && typeof ioFs.closeSync === "function" && typeof ioFs.fstatSync === "function" && typeof ioFs.lstatSync === "function" && typeof ioFs.realpathSync === "function" && typeof ioFs.readFileSync === "function" && typeof ioFs.constants === "object" && ioFs.constants !== null;
913
913
  }
914
914
  function openBoundaryFileSync(params) {
915
- const ioFs = params.ioFs ?? fs$1;
915
+ const ioFs = params.ioFs ?? syncFs;
916
916
  const resolved = resolveBoundaryFilePathGeneric({
917
917
  absolutePath: params.absolutePath,
918
918
  resolve: (absolutePath) => resolveBoundaryPathSync({
@@ -963,7 +963,7 @@ function finalizeBoundaryFileOpen(params) {
963
963
  });
964
964
  }
965
965
  async function openBoundaryFile(params) {
966
- const ioFs = params.ioFs ?? fs$1;
966
+ const ioFs = params.ioFs ?? syncFs;
967
967
  const maybeResolved = resolveBoundaryFilePathGeneric({
968
968
  absolutePath: params.absolutePath,
969
969
  resolve: (absolutePath) => resolveBoundaryPath({
@@ -1119,7 +1119,7 @@ function resolveNpmArgvForWindows(argv) {
1119
1119
  if (!cliName) return null;
1120
1120
  const nodeDir = path.dirname(process$1.execPath);
1121
1121
  const cliPath = path.join(nodeDir, "node_modules", "npm", "bin", cliName);
1122
- if (!fs$1.existsSync(cliPath)) {
1122
+ if (!syncFs.existsSync(cliPath)) {
1123
1123
  const command = argv[0] ?? "";
1124
1124
  return [path.extname(command).toLowerCase() ? command : `${command}.cmd`, ...argv.slice(1)];
1125
1125
  }
@@ -1323,7 +1323,7 @@ async function readPackageName(dir) {
1323
1323
  }
1324
1324
  function readPackageNameSync(dir) {
1325
1325
  try {
1326
- const raw = fs$1.readFileSync(path.join(dir, "package.json"), "utf-8");
1326
+ const raw = syncFs.readFileSync(path.join(dir, "package.json"), "utf-8");
1327
1327
  const parsed = JSON.parse(raw);
1328
1328
  return typeof parsed.name === "string" ? parsed.name : null;
1329
1329
  } catch {
@@ -1357,7 +1357,7 @@ function candidateDirsFromArgv1(argv1) {
1357
1357
  const normalized = path.resolve(argv1);
1358
1358
  const candidates = [path.dirname(normalized)];
1359
1359
  try {
1360
- const resolved = fs$1.realpathSync(normalized);
1360
+ const resolved = syncFs.realpathSync(normalized);
1361
1361
  if (resolved !== normalized) candidates.push(path.dirname(resolved));
1362
1362
  } catch {}
1363
1363
  const parts = normalized.split(path.sep);
@@ -1469,14 +1469,14 @@ async function readWorkspaceFileWithGuards(params) {
1469
1469
  const identity = workspaceFileIdentity(opened.stat, opened.path);
1470
1470
  const cached = workspaceFileCache.get(params.filePath);
1471
1471
  if (cached && cached.identity === identity) {
1472
- fs$1.closeSync(opened.fd);
1472
+ syncFs.closeSync(opened.fd);
1473
1473
  return {
1474
1474
  ok: true,
1475
1475
  content: cached.content
1476
1476
  };
1477
1477
  }
1478
1478
  try {
1479
- const content = fs$1.readFileSync(opened.fd, "utf-8");
1479
+ const content = syncFs.readFileSync(opened.fd, "utf-8");
1480
1480
  workspaceFileCache.set(params.filePath, {
1481
1481
  content,
1482
1482
  identity
@@ -1493,7 +1493,7 @@ async function readWorkspaceFileWithGuards(params) {
1493
1493
  error
1494
1494
  };
1495
1495
  } finally {
1496
- fs$1.closeSync(opened.fd);
1496
+ syncFs.closeSync(opened.fd);
1497
1497
  }
1498
1498
  }
1499
1499
  function stripFrontMatter(content) {
@@ -0,0 +1,118 @@
1
+ # Cclawd MFA Auth Plugin
2
+
3
+ OpenClaw 插件,为多渠道提供 MFA(多因素认证)功能。
4
+
5
+ ## 功能特性
6
+
7
+ - ✅ **首次对话认证**:用户首次对话时触发 MFA 认证
8
+ - ✅ **敏感操作认证**:敏感操作(如执行命令)需要二次认证
9
+ - ✅ **/reauth 命令**:重置认证状态,重新认证
10
+ - ✅ **多渠道支持**:支持 Web/WebChat 和其他渠道
11
+ - ✅ **轮询认证结果**:自动轮询认证状态,成功后推送通知
12
+
13
+ ## 安装
14
+
15
+ ```bash
16
+ pnpm install
17
+ ```
18
+
19
+ ## 配置
20
+
21
+ 通过环境变量配置插件:
22
+
23
+ ```bash
24
+ # Dabby API 配置
25
+ MFA_AUTH_API_KEY=your_api_key_here
26
+ DABBY_API_BASE_URL=https://api.dabby.com
27
+
28
+ # 认证有效期(毫秒)
29
+ MFA_VERIFICATION_DURATION=120000 # 敏感操作认证有效期,默认 2 分钟
30
+ MFA_FIRST_MESSAGE_AUTH_DURATION=86400000 # 首次认证有效期,默认 24 小时
31
+
32
+ # 功能开关
33
+ MFA_REQUIRE_AUTH_ON_FIRST_MESSAGE=true # 启用首次消息认证
34
+ MFA_REQUIRE_AUTH_ON_SENSITIVE_OPERATION=true # 启用敏感操作认证
35
+
36
+ # 敏感关键词(逗号分隔)
37
+ MFA_SENSITIVE_KEYWORDS=rm,delete,drop,shutdown
38
+
39
+ # Gateway 配置
40
+ MFA_GATEWAY_HOST=127.0.0.1 # Gateway 主机地址
41
+ MFA_ENABLE_AUTH_NOTIFICATION=true # 启用认证成功通知
42
+
43
+ # 状态持久化目录
44
+ MFA_AUTH_STATE_DIR=~/.openclaw/cclawd-mfa-auth/
45
+ ```
46
+
47
+ ## 使用
48
+
49
+ ### 1. 首次对话认证
50
+
51
+ 用户首次发送消息时,插件会自动触发认证流程:
52
+
53
+ 1. 生成二维码认证链接
54
+ 2. 推送认证链接给用户
55
+ 3. 轮询认证状态
56
+ 4. 认证成功后推送通知
57
+
58
+ ### 2. 敏感操作认证
59
+
60
+ 当用户执行敏感操作(如 bash 命令包含敏感关键词)时:
61
+
62
+ 1. 拦截操作
63
+ 2. 要求二次认证
64
+ 3. 认证成功后允许执行
65
+
66
+ ### 3. /reauth 命令
67
+
68
+ 用户可以随时发送 `/reauth` 命令重新认证:
69
+
70
+ ```
71
+ /reauth
72
+ ```
73
+
74
+ ## 认证流程
75
+
76
+ ```mermaid
77
+ sequenceDiagram
78
+ participant User
79
+ participant Plugin
80
+ participant AuthManager
81
+ participant DabbyAPI
82
+ participant NotificationService
83
+
84
+ User->>Plugin: 发送消息
85
+ Plugin->>AuthManager: 检查认证状态
86
+ alt 未认证
87
+ AuthManager->>DabbyAPI: 获取二维码
88
+ DabbyAPI-->>AuthManager: certToken + qrCodeUrl
89
+ AuthManager->>NotificationService: 推送认证链接
90
+ NotificationService-->>User: 显示二维码
91
+ loop 轮询认证结果
92
+ AuthManager->>DabbyAPI: 检查认证状态
93
+ DabbyAPI-->>AuthManager: 返回状态
94
+ end
95
+ AuthManager->>NotificationService: 推送成功消息
96
+ NotificationService-->>User: 认证成功
97
+ end
98
+ ```
99
+
100
+ ## 支持的渠道
101
+
102
+ - ✅ Web/WebChat
103
+ - ✅ Feishu(飞书)
104
+ - 🚧 其他渠道(可扩展)
105
+
106
+ ## 开发
107
+
108
+ ```bash
109
+ # 开发模式
110
+ pnpm dev
111
+
112
+ # 构建
113
+ pnpm build
114
+ ```
115
+
116
+ ## License
117
+
118
+ MIT
@@ -0,0 +1,382 @@
1
+ /**
2
+ * Cclawd MFA Auth Plugin - Main Entry
3
+ */
4
+
5
+ import type { OpenClawPluginApi } from 'openclaw/plugin-sdk';
6
+ import { authManager } from './src/auth-manager.js';
7
+ import { config } from './src/config.js';
8
+ import { NotificationService } from './src/notification-service.js';
9
+ import { pollingManager } from './src/polling-manager.js';
10
+ import { SessionResolver } from './src/session-resolver.js';
11
+ import { sensitiveDetector } from './src/sensitive-detector.js';
12
+ import { qrCodeAuthProvider } from './src/providers/qr-code.js';
13
+ import type { AuthSession, PendingAuthContext } from './src/types.js';
14
+
15
+ const notificationService = NotificationService.getInstance();
16
+
17
+ /**
18
+ * 发送认证消息
19
+ */
20
+ async function sendAuthMessage(
21
+ channel: string | undefined,
22
+ accountId: string | undefined,
23
+ to: string,
24
+ message: string,
25
+ userId: string,
26
+ overrideSessionKey?: string,
27
+ ): Promise<void> {
28
+ const session: AuthSession = {
29
+ userId,
30
+ sessionId: 'notification',
31
+ authMethod: 'qr-code',
32
+ timestamp: Date.now(),
33
+ originalContext: {
34
+ sessionKey: overrideSessionKey || `${channel || 'web'}:${accountId || ''}:${userId}`,
35
+ senderId: userId,
36
+ commandBody: '',
37
+ channel: channel || 'web',
38
+ accountId: accountId || '',
39
+ to,
40
+ toolName: 'notification',
41
+ toolParams: {},
42
+ timestamp: Date.now(),
43
+ triggerType: 'sensitive_operation',
44
+ },
45
+ };
46
+
47
+ await notificationService.sendAuthNotification(session, message);
48
+ }
49
+
50
+ /**
51
+ * 插件注册函数
52
+ */
53
+ export default function register(api: OpenClawPluginApi) {
54
+ console.log('[cclawd-mfa-auth] Plugin registration started');
55
+ authManager.registerProvider(qrCodeAuthProvider);
56
+
57
+ notificationService.setConfig(api.config);
58
+
59
+ /**
60
+ * 处理消息接收事件 - 首次对话认证
61
+ */
62
+ api.on('message_received', async (event, ctx) => {
63
+ await authManager.ensureInitialized();
64
+
65
+ api.logger.info(
66
+ `[cclawd-mfa-auth] First message auth check: config.requireAuthOnFirstMessage=${config.requireAuthOnFirstMessage}`,
67
+ );
68
+
69
+ if (!config.requireAuthOnFirstMessage) {
70
+ api.logger.warn(`[cclawd-mfa-auth] First message auth is disabled in config, skipping.`);
71
+ return;
72
+ }
73
+
74
+ const content = event.content || '';
75
+ const isReauthCommand = content.trim() === '/reauth';
76
+
77
+ if (isReauthCommand) {
78
+ api.logger.info(`[cclawd-mfa-auth] /reauth command detected, skipping first message auth check`);
79
+ return;
80
+ }
81
+
82
+ // 解析会话信息
83
+ // metadata.senderId 是 WebChat 的真实用户标识
84
+ const metadataSenderId = event.metadata?.senderId as string | undefined;
85
+
86
+ const resolved = SessionResolver.resolveFromContext({
87
+ sessionKey: ctx.sessionKey,
88
+ channelId: ctx.channelId,
89
+ conversationId: ctx.conversationId,
90
+ accountId: ctx.accountId,
91
+ from: event.from,
92
+ senderId: metadataSenderId || ctx.senderId,
93
+ });
94
+
95
+ const userId = resolved.userId;
96
+
97
+ api.logger.info(`[cclawd-mfa-auth] Extracted userId="${userId}", sessionKey="${resolved.sessionKey}"`);
98
+
99
+ // 检查是否已认证
100
+ if (authManager.isUserVerifiedForFirstMessage(userId)) {
101
+ api.logger.info(`[cclawd-mfa-auth] User ${userId} already verified for first message`);
102
+
103
+ const notificationInfo = authManager.checkAndConsumeNotification(userId);
104
+ if (notificationInfo) {
105
+ const messageText = notificationInfo.isReauth
106
+ ? '✅ 重新认证成功,请继续对话。'
107
+ : '✅ 首次认证成功,请继续对话。';
108
+
109
+ await sendAuthMessage(
110
+ resolved.channel,
111
+ resolved.accountId,
112
+ event.metadata?.to as string | undefined || event.from || userId,
113
+ messageText,
114
+ userId,
115
+ resolved.sessionKey,
116
+ );
117
+ }
118
+ return;
119
+ }
120
+
121
+ api.logger.info(`[cclawd-mfa-auth] First message from unauthenticated user ${userId}, requiring auth`);
122
+
123
+ // 生成认证会话
124
+ const session = await authManager.generateSession(userId, {
125
+ sessionKey: resolved.sessionKey,
126
+ senderId: userId,
127
+ commandBody: event.content || '',
128
+ channel: resolved.channel,
129
+ to: event.metadata?.to as string | undefined || event.from,
130
+ accountId: resolved.accountId,
131
+ toolName: '',
132
+ toolParams: {},
133
+ timestamp: Date.now(),
134
+ triggerType: 'first_message',
135
+ });
136
+
137
+ if (!session) {
138
+ api.logger.error(`[cclawd-mfa-auth] Failed to generate first message auth session for user ${userId}`);
139
+ return;
140
+ }
141
+
142
+ api.logger.info(`[cclawd-mfa-auth] Blocking first message from ${userId}`);
143
+
144
+ // 发送认证链接
145
+ const messageText = `🔐 首次对话需要进行认证
146
+
147
+ 为了您的账户安全,首次对话前需要完成身份验证。
148
+
149
+ 📱 请点击以下链接完成扫码认证:
150
+ ${session.qrCodeUrl}
151
+
152
+ 验证有效期: ${Math.floor(config.timeout / 60000)} 分钟`;
153
+
154
+ try {
155
+ await sendAuthMessage(
156
+ resolved.channel,
157
+ resolved.accountId,
158
+ event.metadata?.to as string | undefined || event.from || userId,
159
+ messageText,
160
+ userId,
161
+ resolved.sessionKey,
162
+ );
163
+
164
+ // 启动轮询
165
+ pollingManager.startPolling(api, userId, session.sessionId, {
166
+ triggerType: 'first_message',
167
+ isReauth: false,
168
+ channel: resolved.channel,
169
+ accountId: resolved.accountId,
170
+ to: event.metadata?.to as string | undefined,
171
+ sessionKey: resolved.sessionKey,
172
+ });
173
+
174
+ api.logger.info(`[cclawd-mfa-auth] Sent first message auth notification`);
175
+ } catch (error) {
176
+ api.logger.error(`[cclawd-mfa-auth] Failed to send first message auth notification: ${String(error)}`);
177
+ }
178
+ });
179
+
180
+ /**
181
+ * 处理工具调用前事件 - 敏感操作认证
182
+ */
183
+ api.on('before_tool_call', async (event, ctx) => {
184
+ await authManager.ensureInitialized();
185
+ if (!config.requireAuthOnSensitiveOperation) {
186
+ return undefined;
187
+ }
188
+
189
+ const { toolName, params } = event;
190
+
191
+ api.logger.info(`[cclawd-mfa-auth] Tool call detected: ${toolName}`);
192
+
193
+ // 检查是否为敏感操作
194
+ const sensitiveCheck = sensitiveDetector.checkToolCall(toolName, params || {});
195
+ if (!sensitiveCheck.isSensitive) {
196
+ api.logger.info(`[cclawd-mfa-auth] Tool ${toolName} is not sensitive, allowing`);
197
+ return undefined;
198
+ }
199
+
200
+ // 解析会话信息
201
+ const resolved = SessionResolver.resolveFromContext({
202
+ sessionKey: ctx.sessionKey,
203
+ channelId: ctx.channelId,
204
+ conversationId: ctx.conversationId,
205
+ accountId: ctx.accountId,
206
+ from: ctx.from,
207
+ senderId: ctx.senderId,
208
+ });
209
+
210
+ const userId = resolved.userId;
211
+
212
+ // 检查是否已认证
213
+ if (authManager.isUserVerifiedForSensitiveOps(userId)) {
214
+ api.logger.info(`[cclawd-mfa-auth] User ${userId} is verified for sensitive ops, allowing`);
215
+
216
+ const notificationInfo = authManager.checkAndConsumeNotification(userId);
217
+ if (notificationInfo) {
218
+ await sendAuthMessage(
219
+ resolved.channel,
220
+ resolved.accountId,
221
+ resolved.to || userId,
222
+ '✅ 二次认证成功,请重新发送之前的命令(或回复"确认")即可执行。',
223
+ userId,
224
+ resolved.sessionKey,
225
+ );
226
+ }
227
+
228
+ return undefined;
229
+ }
230
+
231
+ api.logger.info(`[cclawd-mfa-auth] User ${userId} is NOT verified for sensitive ops.`);
232
+
233
+ // 生成认证会话
234
+ const session = await authManager.generateSession(userId, {
235
+ sessionKey: resolved.sessionKey,
236
+ senderId: userId,
237
+ commandBody: sensitiveCheck.preview,
238
+ channel: resolved.channel,
239
+ to: resolved.to,
240
+ accountId: resolved.accountId,
241
+ toolName,
242
+ toolParams: params || {},
243
+ timestamp: Date.now(),
244
+ triggerType: 'sensitive_operation',
245
+ });
246
+
247
+ if (!session) {
248
+ api.logger.error(`[cclawd-mfa-auth] Failed to generate session for user ${userId}`);
249
+ return undefined;
250
+ }
251
+
252
+ api.logger.info(`[cclawd-mfa-auth] Blocking sensitive tool call: ${toolName} from ${userId}`);
253
+
254
+ // 发送认证链接
255
+ const messageText = `🔐 该操作需要二次认证
256
+
257
+ 检测到敏感操作: ${sensitiveCheck.preview}
258
+
259
+ 📱 请点击以下链接完成扫码认证:
260
+ ${session.qrCodeUrl}
261
+
262
+ 验证有效期: ${Math.floor(config.timeout / 60000)} 分钟
263
+
264
+ 验证成功后,请回复"确认"或者重新发送之前的命令以继续执行。`;
265
+
266
+ try {
267
+ await sendAuthMessage(
268
+ resolved.channel,
269
+ resolved.accountId,
270
+ resolved.to || userId,
271
+ messageText,
272
+ userId,
273
+ resolved.sessionKey,
274
+ );
275
+
276
+ // 启动轮询
277
+ pollingManager.startPolling(api, userId, session.sessionId, {
278
+ triggerType: 'sensitive_operation',
279
+ isReauth: false,
280
+ channel: resolved.channel,
281
+ accountId: resolved.accountId,
282
+ to: resolved.to,
283
+ sessionKey: resolved.sessionKey,
284
+ });
285
+
286
+ api.logger.info(`[cclawd-mfa-auth] Sent sensitive operation auth notification`);
287
+ } catch (error) {
288
+ api.logger.error(`[cclawd-mfa-auth] Failed to send sensitive operation auth notification: ${String(error)}`);
289
+ }
290
+
291
+ // 注册待执行操作
292
+ authManager.registerPendingExecution(userId, session.sessionId);
293
+
294
+ return {
295
+ block: true,
296
+ blockReason: `🔐 该操作需要二次认证`,
297
+ };
298
+ });
299
+
300
+ /**
301
+ * 注册 /reauth 命令
302
+ */
303
+ api.registerCommand({
304
+ name: 'reauth',
305
+ description: '重新进行首次对话认证',
306
+ acceptsArgs: false,
307
+ requireAuth: false,
308
+ handler: async (ctx) => {
309
+ const userId = ctx.from || ctx.senderId || 'unknown';
310
+ api.logger.info(`[cclawd-mfa-auth] /reauth command received. userId=${userId}`);
311
+
312
+ // 清除首次消息认证状态
313
+ authManager.clearFirstMessageAuth(userId);
314
+
315
+ // 解析会话信息
316
+ const resolved = SessionResolver.resolveFromContext({
317
+ sessionKey: ctx.sessionKey,
318
+ channelId: ctx.channel,
319
+ accountId: ctx.accountId,
320
+ from: ctx.from,
321
+ senderId: ctx.senderId,
322
+ to: ctx.to,
323
+ });
324
+
325
+ // 生成认证会话
326
+ const session = await authManager.generateSession(userId, {
327
+ sessionKey: resolved.sessionKey,
328
+ senderId: userId,
329
+ commandBody: '/reauth',
330
+ channel: resolved.channel,
331
+ to: resolved.to,
332
+ accountId: resolved.accountId,
333
+ toolName: '',
334
+ toolParams: {},
335
+ timestamp: Date.now(),
336
+ triggerType: 'first_message',
337
+ });
338
+
339
+ if (!session) {
340
+ api.logger.error(`[cclawd-mfa-auth] Failed to generate reauth session for user ${userId}`);
341
+ return { text: '❌ 认证会话创建失败,请稍后重试。' };
342
+ }
343
+
344
+ api.logger.info(`[cclawd-mfa-auth] Reauth requested by user ${userId}, session=${session.sessionId}`);
345
+
346
+ const messageText = `🔐 重新认证
347
+
348
+ 📱 请点击以下链接完成扫码认证:
349
+ ${session.qrCodeUrl}
350
+
351
+ 验证有效期: ${Math.floor(config.timeout / 60000)} 分钟`;
352
+
353
+ try {
354
+ await sendAuthMessage(
355
+ resolved.channel,
356
+ resolved.accountId,
357
+ resolved.to || userId,
358
+ messageText,
359
+ userId,
360
+ resolved.sessionKey,
361
+ );
362
+
363
+ // 启动轮询
364
+ pollingManager.startPolling(api, userId, session.sessionId, {
365
+ triggerType: 'first_message',
366
+ isReauth: true,
367
+ channel: resolved.channel,
368
+ accountId: resolved.accountId,
369
+ to: resolved.to,
370
+ sessionKey: resolved.sessionKey,
371
+ });
372
+
373
+ return { text: '📱 认证链接已发送,请查看最新消息。' };
374
+ } catch (error) {
375
+ api.logger.error(`[cclawd-mfa-auth] Failed to send reauth link: ${String(error)}`);
376
+ return { text: '❌ 认证链接发送失败,请稍后重试。' };
377
+ }
378
+ },
379
+ });
380
+
381
+ api.logger.info('[cclawd-mfa-auth] Plugin loaded successfully');
382
+ }