@sfmc-bds/cli 0.2.0-beta.0 → 0.2.0-beta.10

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 (183) hide show
  1. package/dist/argv-parse.d.ts +11 -0
  2. package/dist/argv-parse.d.ts.map +1 -0
  3. package/dist/argv-parse.js +28 -0
  4. package/dist/argv-parse.js.map +7 -0
  5. package/dist/cli-gate.d.ts +11 -0
  6. package/dist/cli-gate.d.ts.map +1 -0
  7. package/dist/cli-gate.js +46 -0
  8. package/dist/cli-gate.js.map +7 -0
  9. package/dist/command-palette.d.ts +61 -0
  10. package/dist/command-palette.d.ts.map +1 -0
  11. package/dist/command-palette.js +352 -0
  12. package/dist/command-palette.js.map +7 -0
  13. package/dist/command-surface.d.ts +85 -0
  14. package/dist/command-surface.d.ts.map +1 -0
  15. package/dist/command-surface.js +292 -0
  16. package/dist/command-surface.js.map +7 -0
  17. package/dist/commands-reload.js +2 -2
  18. package/dist/commands-reload.js.map +2 -2
  19. package/dist/commands.d.ts +1 -1
  20. package/dist/commands.d.ts.map +1 -1
  21. package/dist/commands.js +196 -21
  22. package/dist/commands.js.map +2 -2
  23. package/dist/debug-command.d.ts +5 -0
  24. package/dist/debug-command.d.ts.map +1 -0
  25. package/dist/debug-command.js +118 -0
  26. package/dist/debug-command.js.map +7 -0
  27. package/dist/help-text.d.ts +3 -0
  28. package/dist/help-text.d.ts.map +1 -0
  29. package/dist/help-text.js +160 -0
  30. package/dist/help-text.js.map +7 -0
  31. package/dist/i18n/locales/en.d.ts +103 -89
  32. package/dist/i18n/locales/en.d.ts.map +1 -1
  33. package/dist/i18n/locales/en.js +105 -91
  34. package/dist/i18n/locales/en.js.map +2 -2
  35. package/dist/i18n/locales/zh-CN.d.ts.map +1 -1
  36. package/dist/i18n/locales/zh-CN.js +138 -118
  37. package/dist/i18n/locales/zh-CN.js.map +2 -2
  38. package/dist/index.d.ts +2 -2
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +9 -4
  41. package/dist/index.js.map +2 -2
  42. package/dist/llbot-launch.d.ts +20 -0
  43. package/dist/llbot-launch.d.ts.map +1 -0
  44. package/dist/llbot-launch.js +40 -0
  45. package/dist/llbot-launch.js.map +7 -0
  46. package/dist/log-filter.d.ts +69 -0
  47. package/dist/log-filter.d.ts.map +1 -0
  48. package/dist/log-filter.js +150 -0
  49. package/dist/log-filter.js.map +7 -0
  50. package/dist/logs.d.ts +29 -7
  51. package/dist/logs.d.ts.map +1 -1
  52. package/dist/logs.js +164 -72
  53. package/dist/logs.js.map +3 -3
  54. package/dist/main.js +55 -46
  55. package/dist/main.js.map +2 -2
  56. package/dist/module-commands.d.ts +17 -40
  57. package/dist/module-commands.d.ts.map +1 -1
  58. package/dist/module-commands.js +129 -85
  59. package/dist/module-commands.js.map +2 -2
  60. package/dist/module-pack-build.d.ts +10 -0
  61. package/dist/module-pack-build.d.ts.map +1 -0
  62. package/dist/module-pack-build.js +434 -0
  63. package/dist/module-pack-build.js.map +7 -0
  64. package/dist/module-toggle.d.ts +33 -0
  65. package/dist/module-toggle.d.ts.map +1 -0
  66. package/dist/module-toggle.js +28 -0
  67. package/dist/module-toggle.js.map +7 -0
  68. package/dist/node-service-probe.d.ts +18 -0
  69. package/dist/node-service-probe.d.ts.map +1 -0
  70. package/dist/node-service-probe.js +97 -0
  71. package/dist/node-service-probe.js.map +7 -0
  72. package/dist/pack-lifecycle.d.ts +1 -1
  73. package/dist/pack-lifecycle.d.ts.map +1 -1
  74. package/dist/pack-lifecycle.js +14 -4
  75. package/dist/pack-lifecycle.js.map +2 -2
  76. package/dist/pack-update/index.d.ts +18 -0
  77. package/dist/pack-update/index.d.ts.map +1 -0
  78. package/dist/pack-update/index.js +113 -0
  79. package/dist/pack-update/index.js.map +7 -0
  80. package/dist/registry.d.ts +7 -4
  81. package/dist/registry.d.ts.map +1 -1
  82. package/dist/registry.js +15 -3
  83. package/dist/registry.js.map +2 -2
  84. package/dist/repl-windows/format-display.d.ts +10 -0
  85. package/dist/repl-windows/format-display.d.ts.map +1 -0
  86. package/dist/repl-windows/format-display.js +57 -0
  87. package/dist/repl-windows/format-display.js.map +7 -0
  88. package/dist/repl-windows/host.d.ts +60 -0
  89. package/dist/repl-windows/host.d.ts.map +1 -0
  90. package/dist/repl-windows/host.js +179 -0
  91. package/dist/repl-windows/host.js.map +7 -0
  92. package/dist/repl-windows/index.d.ts +9 -0
  93. package/dist/repl-windows/index.d.ts.map +1 -0
  94. package/dist/repl-windows/index.js +13 -0
  95. package/dist/repl-windows/index.js.map +7 -0
  96. package/dist/repl-windows/logs-filter-window.d.ts +15 -0
  97. package/dist/repl-windows/logs-filter-window.d.ts.map +1 -0
  98. package/dist/repl-windows/logs-filter-window.js +77 -0
  99. package/dist/repl-windows/logs-filter-window.js.map +7 -0
  100. package/dist/repl-windows/service-window.d.ts +4 -0
  101. package/dist/repl-windows/service-window.d.ts.map +1 -0
  102. package/dist/repl-windows/service-window.js +35 -0
  103. package/dist/repl-windows/service-window.js.map +7 -0
  104. package/dist/repl-windows/types.d.ts +56 -0
  105. package/dist/repl-windows/types.d.ts.map +1 -0
  106. package/dist/repl-windows/types.js +1 -0
  107. package/dist/repl-windows/types.js.map +7 -0
  108. package/dist/repl.d.ts +6 -9
  109. package/dist/repl.d.ts.map +1 -1
  110. package/dist/repl.js +698 -427
  111. package/dist/repl.js.map +3 -3
  112. package/dist/runtime.d.ts +6 -13
  113. package/dist/runtime.d.ts.map +1 -1
  114. package/dist/runtime.js +23 -28
  115. package/dist/runtime.js.map +2 -2
  116. package/dist/send-target.d.ts +11 -0
  117. package/dist/send-target.d.ts.map +1 -0
  118. package/dist/send-target.js +42 -0
  119. package/dist/send-target.js.map +7 -0
  120. package/dist/services.d.ts +50 -4
  121. package/dist/services.d.ts.map +1 -1
  122. package/dist/services.js +244 -20
  123. package/dist/services.js.map +2 -2
  124. package/dist/theme.js +1 -1
  125. package/dist/theme.js.map +2 -2
  126. package/dist/wizard.d.ts.map +1 -1
  127. package/dist/wizard.js +76 -16
  128. package/dist/wizard.js.map +2 -2
  129. package/dist/world-packs.d.ts +15 -0
  130. package/dist/world-packs.d.ts.map +1 -1
  131. package/dist/world-packs.js +90 -87
  132. package/dist/world-packs.js.map +2 -2
  133. package/package.json +24 -21
  134. package/scripts/module-install/check-modules.mjs +204 -0
  135. package/scripts/module-install/fetch-module.mjs +1007 -0
  136. package/scripts/module-install/install-resolver.test.mjs +48 -0
  137. package/scripts/module-install/lib/catalog.mjs +96 -0
  138. package/scripts/module-install/lib/io.mjs +37 -0
  139. package/scripts/module-install/lib/link-from.mjs +80 -0
  140. package/scripts/module-install/lib/lock.mjs +78 -0
  141. package/scripts/module-install/lib/npm-resolver.mjs +55 -0
  142. package/scripts/module-install/lib/packages.mjs +142 -0
  143. package/scripts/module-install/lib/paths.mjs +48 -0
  144. package/scripts/module-install/lib/registry-index.mjs +50 -0
  145. package/scripts/module-install/link-local.test.mjs +51 -0
  146. package/scripts/module-install/local-resolver.test.mjs +51 -0
  147. package/scripts/module-install/registry-index.test.mjs +28 -0
  148. package/dist/module-wizard.d.ts +0 -14
  149. package/dist/module-wizard.d.ts.map +0 -1
  150. package/dist/module-wizard.js +0 -313
  151. package/dist/module-wizard.js.map +0 -7
  152. package/dist/pack-update/bindings.d.ts +0 -12
  153. package/dist/pack-update/bindings.d.ts.map +0 -1
  154. package/dist/pack-update/bindings.js +0 -64
  155. package/dist/pack-update/bindings.js.map +0 -7
  156. package/dist/pack-update/config.d.ts +0 -22
  157. package/dist/pack-update/config.d.ts.map +0 -1
  158. package/dist/pack-update/config.js +0 -141
  159. package/dist/pack-update/config.js.map +0 -7
  160. package/dist/pack-update/providers/curseforge.d.ts +0 -23
  161. package/dist/pack-update/providers/curseforge.d.ts.map +0 -1
  162. package/dist/pack-update/providers/curseforge.js +0 -209
  163. package/dist/pack-update/providers/curseforge.js.map +0 -7
  164. package/dist/pack-update/providers/index.d.ts +0 -16
  165. package/dist/pack-update/providers/index.d.ts.map +0 -1
  166. package/dist/pack-update/providers/index.js +0 -37
  167. package/dist/pack-update/providers/index.js.map +0 -7
  168. package/dist/pack-update/service.d.ts +0 -21
  169. package/dist/pack-update/service.d.ts.map +0 -1
  170. package/dist/pack-update/service.js +0 -567
  171. package/dist/pack-update/service.js.map +0 -7
  172. package/dist/pack-update/types.d.ts +0 -126
  173. package/dist/pack-update/types.d.ts.map +0 -1
  174. package/dist/pack-update/types.js +0 -8
  175. package/dist/pack-update/types.js.map +0 -7
  176. package/dist/pack-update/version-policy.d.ts +0 -80
  177. package/dist/pack-update/version-policy.d.ts.map +0 -1
  178. package/dist/pack-update/version-policy.js +0 -216
  179. package/dist/pack-update/version-policy.js.map +0 -7
  180. package/dist/remote-agent.d.ts +0 -18
  181. package/dist/remote-agent.d.ts.map +0 -1
  182. package/dist/remote-agent.js +0 -196
  183. package/dist/remote-agent.js.map +0 -7
package/dist/registry.js CHANGED
@@ -30,15 +30,27 @@ function parseRegistryIndex(json) {
30
30
  const root = json;
31
31
  const modulesRaw = root.modules;
32
32
  if (typeof modulesRaw !== "object" || modulesRaw === null || Array.isArray(modulesRaw)) {
33
- throw new Error("registry index must have a 'modules' object mapping id \u2192 { repo, tag }");
33
+ throw new Error("registry index must have a 'modules' object mapping id \u2192 entry");
34
34
  }
35
35
  const filtered = {};
36
36
  for (const [k, v] of Object.entries(modulesRaw)) {
37
37
  if (k.startsWith("_")) continue;
38
38
  if (typeof v !== "object" || v === null || Array.isArray(v)) continue;
39
39
  const entry = v;
40
- if (typeof entry.repo !== "string" || typeof entry.tag !== "string") continue;
41
- filtered[k] = { repo: entry.repo, tag: entry.tag };
40
+ const hasNpm = typeof entry.npm === "string" && entry.npm.length > 0;
41
+ const hasGh = typeof entry.repo === "string" && typeof entry.tag === "string";
42
+ if (!hasNpm && !hasGh) continue;
43
+ const out = {};
44
+ if (hasNpm) {
45
+ out.npm = entry.npm;
46
+ if (typeof entry.version === "string") out.version = entry.version;
47
+ if (typeof entry.sdk === "string") out.sdk = entry.sdk;
48
+ }
49
+ if (hasGh) {
50
+ out.repo = entry.repo;
51
+ out.tag = entry.tag;
52
+ }
53
+ filtered[k] = out;
42
54
  }
43
55
  return filtered;
44
56
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/registry.ts"],
4
- "sourcesContent": ["/**\n * registry.ts \u2014 first-party sfmc-modules index resolution, shared between\n * the module CLI and the startup unknown-source warning.\n *\n * Talks to https://raw.githubusercontent.com/Tanya7z/sfmc-modules/main/index.json\n * (the registry lives in a separate repo to keep this one free of \"what\n * modules exist\" governance). Caches to <sfmc/src/.sfmc-registry-cache.json>\n * with a 1h TTL so a brief network blip doesn't degrade the CLI.\n *\n * Both helpers are best-effort: failures are surfaced as `null` and a\n * console warning, never an exception, because the CLI must still boot\n * when the registry is unreachable.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport process from \"node:process\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\nconst CACHE_PATH = path.join(__dirname, \".sfmc-registry-cache.json\");\nconst TTL_MS = 60 * 60 * 1000;\n\nconst DEFAULT_REGISTRY_REPO = \"Tanya7z/sfmc-modules\";\nconst DEFAULT_REGISTRY_TAG = \"main\";\nconst INDEX_URL = `https://raw.githubusercontent.com/${DEFAULT_REGISTRY_REPO}/${DEFAULT_REGISTRY_TAG}/index.json`;\n\nexport interface RegistryEntry {\n repo: string;\n tag: string;\n}\nexport type RegistryIndex = Record<string, RegistryEntry>;\n\ninterface RegistryCache {\n fetchedAt: number;\n index: RegistryIndex;\n}\n\nfunction readCache(): RegistryCache | null {\n try {\n if (!existsSync(CACHE_PATH)) return null;\n return JSON.parse(readFileSync(CACHE_PATH, \"utf8\")) as RegistryCache;\n } catch {\n return null;\n }\n}\n\nfunction writeCache(cache: RegistryCache): void {\n try {\n mkdirSync(path.dirname(CACHE_PATH), { recursive: true });\n writeFileSync(CACHE_PATH, JSON.stringify(cache, null, 2));\n } catch {\n /* cache write is best-effort */\n }\n}\n\n/**\n * \u89E3\u6790 first-party index.json\u3002\n * \u5951\u7EA6\u4E0E tools/lib/registry-index.mjs#parseRegistryIndex \u4FDD\u6301\u4E00\u81F4\uFF1A\n * `{ modules: { <folder>: { repo, tag } } }`\u3002\u5FFD\u7565 `_` \u524D\u7F00\u5143\u6570\u636E\u952E\u3002\n */\nexport function parseRegistryIndex(json: unknown): RegistryIndex {\n if (typeof json !== \"object\" || json === null || Array.isArray(json)) {\n throw new Error(\"registry index must be a JSON object with a 'modules' field\");\n }\n const root = json as Record<string, unknown>;\n const modulesRaw = root.modules;\n if (typeof modulesRaw !== \"object\" || modulesRaw === null || Array.isArray(modulesRaw)) {\n throw new Error(\"registry index must have a 'modules' object mapping id \u2192 { repo, tag }\");\n }\n const filtered: RegistryIndex = {};\n for (const [k, v] of Object.entries(modulesRaw as Record<string, unknown>)) {\n if (k.startsWith(\"_\")) continue;\n if (typeof v !== \"object\" || v === null || Array.isArray(v)) continue;\n const entry = v as Record<string, unknown>;\n if (typeof entry.repo !== \"string\" || typeof entry.tag !== \"string\") continue;\n filtered[k] = { repo: entry.repo, tag: entry.tag };\n }\n return filtered;\n}\n\nasync function fetchFresh(): Promise<RegistryIndex> {\n const res = await fetch(INDEX_URL, { headers: { \"User-Agent\": \"sfmc-cli\" } });\n if (!res.ok) throw new Error(`HTTP ${res.status} for ${INDEX_URL}`);\n return parseRegistryIndex(await res.json());\n}\n\nexport interface RegistryResult {\n index: RegistryIndex;\n /** True when the index came from a stale cache because the live fetch failed. */\n stale: boolean;\n}\n\n/**\n * Resolve the first-party index.\n *\n * Order (default):\n * 1. If the cache is fresh (< TTL): return it without trying the network.\n * 2. Otherwise attempt a live fetch.\n * - success \u2192 write cache, return fresh.\n * - failure + cache exists \u2192 return cache with `stale: true` and a warning.\n * - failure + no cache \u2192 return `{ index: {}, stale: true }` and warn.\n *\n * `force: true` \u8DF3\u8FC7 TTL \u65E9\u9000,\u59CB\u7EC8\u5C1D\u8BD5\u62C9\u7F51(\u4F9B `mod search` \u4E3B\u52A8\u5237\u65B0\u5217\u8868)\u3002\n * \u5931\u8D25\u65F6\u4ECD\u56DE\u9000\u5230\u7F13\u5B58,\u6C38\u4E0D\u629B\u5F02\u5E38\u3002\n */\nexport async function resolveRegistryIndex(opts?: { force?: boolean }): Promise<RegistryResult> {\n const cache = readCache();\n if (!opts?.force && cache && Date.now() - cache.fetchedAt < TTL_MS) {\n return { index: cache.index, stale: false };\n }\n try {\n const fresh = await fetchFresh();\n writeCache({ fetchedAt: Date.now(), index: fresh });\n return { index: fresh, stale: false };\n } catch (err) {\n if (cache) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`[sfmc] registry offline (${msg}); using cached index from ${new Date(cache.fetchedAt).toISOString()}\\n`);\n return { index: cache.index, stale: true };\n }\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`[sfmc] registry unreachable and no cache: ${msg}\\n`);\n return { index: {}, stale: true };\n }\n}\n\n/**\n * \u4ECE\u672C\u5730\u7F13\u5B58\u540C\u6B65\u8BFB\u51FA registry \u6A21\u5757 id(\u4F9B Tab \u8865\u5168)\u3002\n * \u65E0\u7F13\u5B58\u65F6\u8FD4\u56DE\u7A7A\u6570\u7EC4,\u4E0D\u89E6\u53D1\u7F51\u7EDC\u3002\n */\nexport function listRegistryModuleIdsSync(): string[] {\n const cache = readCache();\n if (!cache) return [];\n return Object.keys(cache.index).sort((a, b) => a.localeCompare(b));\n}\n\n/**\n * Compare a set of installed module ids to the registry and return the\n * subset that isn't published in the first-party index. The \"best-effort\"\n * guarantee: this returns an empty array when the registry can't be reached\n * (we don't want a network outage to mark every local module as unknown).\n */\nexport async function findUnknownModules(installedIds: string[]): Promise<string[]> {\n const { index, stale } = await resolveRegistryIndex();\n if (stale && Object.keys(index).length === 0) {\n /* No cache either \u2014 silently treat every module as \"we couldn't tell\".\n * Otherwise offline mode would scream warnings at every boot. */\n return [];\n }\n return installedIds.filter((id) => !index[id]);\n}\n\nexport { DEFAULT_REGISTRY_REPO, DEFAULT_REGISTRY_TAG };"],
5
- "mappings": "AAcA,SAAS,YAAY,WAAW,cAAc,qBAAqB;AACnE,OAAO,UAAU;AACjB,OAAO,aAAa;AACpB,SAAS,qBAAqB;AAE9B,MAAM,YAAY,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AAC7D,MAAM,aAAa,KAAK,KAAK,WAAW,2BAA2B;AACnE,MAAM,SAAS,KAAK,KAAK;AAEzB,MAAM,wBAAwB;AAC9B,MAAM,uBAAuB;AAC7B,MAAM,YAAY,qCAAqC,qBAAqB,IAAI,oBAAoB;AAapG,SAAS,YAAkC;AACzC,MAAI;AACF,QAAI,CAAC,WAAW,UAAU,EAAG,QAAO;AACpC,WAAO,KAAK,MAAM,aAAa,YAAY,MAAM,CAAC;AAAA,EACpD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,WAAW,OAA4B;AAC9C,MAAI;AACF,cAAU,KAAK,QAAQ,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AACvD,kBAAc,YAAY,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAAA,EAC1D,QAAQ;AAAA,EAER;AACF;AAOO,SAAS,mBAAmB,MAA8B;AAC/D,MAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,MAAM,QAAQ,IAAI,GAAG;AACpE,UAAM,IAAI,MAAM,6DAA6D;AAAA,EAC/E;AACA,QAAM,OAAO;AACb,QAAM,aAAa,KAAK;AACxB,MAAI,OAAO,eAAe,YAAY,eAAe,QAAQ,MAAM,QAAQ,UAAU,GAAG;AACtF,UAAM,IAAI,MAAM,6EAAwE;AAAA,EAC1F;AACA,QAAM,WAA0B,CAAC;AACjC,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,UAAqC,GAAG;AAC1E,QAAI,EAAE,WAAW,GAAG,EAAG;AACvB,QAAI,OAAO,MAAM,YAAY,MAAM,QAAQ,MAAM,QAAQ,CAAC,EAAG;AAC7D,UAAM,QAAQ;AACd,QAAI,OAAO,MAAM,SAAS,YAAY,OAAO,MAAM,QAAQ,SAAU;AACrE,aAAS,CAAC,IAAI,EAAE,MAAM,MAAM,MAAM,KAAK,MAAM,IAAI;AAAA,EACnD;AACA,SAAO;AACT;AAEA,eAAe,aAAqC;AAClD,QAAM,MAAM,MAAM,MAAM,WAAW,EAAE,SAAS,EAAE,cAAc,WAAW,EAAE,CAAC;AAC5E,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,QAAQ,IAAI,MAAM,QAAQ,SAAS,EAAE;AAClE,SAAO,mBAAmB,MAAM,IAAI,KAAK,CAAC;AAC5C;AAqBA,eAAsB,qBAAqB,MAAqD;AAC9F,QAAM,QAAQ,UAAU;AACxB,MAAI,CAAC,MAAM,SAAS,SAAS,KAAK,IAAI,IAAI,MAAM,YAAY,QAAQ;AAClE,WAAO,EAAE,OAAO,MAAM,OAAO,OAAO,MAAM;AAAA,EAC5C;AACA,MAAI;AACF,UAAM,QAAQ,MAAM,WAAW;AAC/B,eAAW,EAAE,WAAW,KAAK,IAAI,GAAG,OAAO,MAAM,CAAC;AAClD,WAAO,EAAE,OAAO,OAAO,OAAO,MAAM;AAAA,EACtC,SAAS,KAAK;AACZ,QAAI,OAAO;AACT,YAAMA,OAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,cAAQ,OAAO,MAAM,4BAA4BA,IAAG,8BAA8B,IAAI,KAAK,MAAM,SAAS,EAAE,YAAY,CAAC;AAAA,CAAI;AAC7H,aAAO,EAAE,OAAO,MAAM,OAAO,OAAO,KAAK;AAAA,IAC3C;AACA,UAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,YAAQ,OAAO,MAAM,6CAA6C,GAAG;AAAA,CAAI;AACzE,WAAO,EAAE,OAAO,CAAC,GAAG,OAAO,KAAK;AAAA,EAClC;AACF;AAMO,SAAS,4BAAsC;AACpD,QAAM,QAAQ,UAAU;AACxB,MAAI,CAAC,MAAO,QAAO,CAAC;AACpB,SAAO,OAAO,KAAK,MAAM,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,cAAc,CAAC,CAAC;AACnE;AAQA,eAAsB,mBAAmB,cAA2C;AAClF,QAAM,EAAE,OAAO,MAAM,IAAI,MAAM,qBAAqB;AACpD,MAAI,SAAS,OAAO,KAAK,KAAK,EAAE,WAAW,GAAG;AAG5C,WAAO,CAAC;AAAA,EACV;AACA,SAAO,aAAa,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;AAC/C;",
4
+ "sourcesContent": ["/**\n * registry.ts \u2014 first-party sfmc-modules index resolution, shared between\n * the module CLI and the startup unknown-source warning.\n *\n * Talks to https://raw.githubusercontent.com/Tanya7z/sfmc-modules/main/index.json\n * (the registry lives in a separate repo to keep this one free of \"what\n * modules exist\" governance). Caches to <sfmc/src/.sfmc-registry-cache.json>\n * with a 1h TTL so a brief network blip doesn't degrade the CLI.\n *\n * Both helpers are best-effort: failures are surfaced as `null` and a\n * console warning, never an exception, because the CLI must still boot\n * when the registry is unreachable.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport process from \"node:process\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\nconst CACHE_PATH = path.join(__dirname, \".sfmc-registry-cache.json\");\nconst TTL_MS = 60 * 60 * 1000;\n\nconst DEFAULT_REGISTRY_REPO = \"Tanya7z/sfmc-modules\";\nconst DEFAULT_REGISTRY_TAG = \"main\";\nconst INDEX_URL = `https://raw.githubusercontent.com/${DEFAULT_REGISTRY_REPO}/${DEFAULT_REGISTRY_TAG}/index.json`;\n\nexport interface RegistryEntry {\n npm?: string;\n version?: string;\n sdk?: string;\n repo?: string;\n tag?: string;\n}\nexport type RegistryIndex = Record<string, RegistryEntry>;\n\ninterface RegistryCache {\n fetchedAt: number;\n index: RegistryIndex;\n}\n\nfunction readCache(): RegistryCache | null {\n try {\n if (!existsSync(CACHE_PATH)) return null;\n return JSON.parse(readFileSync(CACHE_PATH, \"utf8\")) as RegistryCache;\n } catch {\n return null;\n }\n}\n\nfunction writeCache(cache: RegistryCache): void {\n try {\n mkdirSync(path.dirname(CACHE_PATH), { recursive: true });\n writeFileSync(CACHE_PATH, JSON.stringify(cache, null, 2));\n } catch {\n /* cache write is best-effort */\n }\n}\n\n/**\n * \u89E3\u6790 first-party index.json\u3002\n * \u5951\u7EA6\u4E0E scripts/module-install/lib/registry-index.mjs#parseRegistryIndex \u4FDD\u6301\u4E00\u81F4\uFF1A\n * `{ modules: { <id>: { npm? | repo+tag } } }`\u3002\u5FFD\u7565 `_` \u524D\u7F00\u5143\u6570\u636E\u952E\u3002\n */\nexport function parseRegistryIndex(json: unknown): RegistryIndex {\n if (typeof json !== \"object\" || json === null || Array.isArray(json)) {\n throw new Error(\"registry index must be a JSON object with a 'modules' field\");\n }\n const root = json as Record<string, unknown>;\n const modulesRaw = root.modules;\n if (typeof modulesRaw !== \"object\" || modulesRaw === null || Array.isArray(modulesRaw)) {\n throw new Error(\"registry index must have a 'modules' object mapping id \u2192 entry\");\n }\n const filtered: RegistryIndex = {};\n for (const [k, v] of Object.entries(modulesRaw as Record<string, unknown>)) {\n if (k.startsWith(\"_\")) continue;\n if (typeof v !== \"object\" || v === null || Array.isArray(v)) continue;\n const entry = v as Record<string, unknown>;\n const hasNpm = typeof entry.npm === \"string\" && entry.npm.length > 0;\n const hasGh = typeof entry.repo === \"string\" && typeof entry.tag === \"string\";\n if (!hasNpm && !hasGh) continue;\n const out: RegistryEntry = {};\n if (hasNpm) {\n out.npm = entry.npm as string;\n if (typeof entry.version === \"string\") out.version = entry.version;\n if (typeof entry.sdk === \"string\") out.sdk = entry.sdk;\n }\n if (hasGh) {\n out.repo = entry.repo as string;\n out.tag = entry.tag as string;\n }\n filtered[k] = out;\n }\n return filtered;\n}\n\nasync function fetchFresh(): Promise<RegistryIndex> {\n const res = await fetch(INDEX_URL, { headers: { \"User-Agent\": \"sfmc-cli\" } });\n if (!res.ok) throw new Error(`HTTP ${res.status} for ${INDEX_URL}`);\n return parseRegistryIndex(await res.json());\n}\n\nexport interface RegistryResult {\n index: RegistryIndex;\n /** True when the index came from a stale cache because the live fetch failed. */\n stale: boolean;\n}\n\n/**\n * Resolve the first-party index.\n *\n * Order (default):\n * 1. If the cache is fresh (< TTL): return it without trying the network.\n * 2. Otherwise attempt a live fetch.\n * - success \u2192 write cache, return fresh.\n * - failure + cache exists \u2192 return cache with `stale: true` and a warning.\n * - failure + no cache \u2192 return `{ index: {}, stale: true }` and warn.\n *\n * `force: true` \u8DF3\u8FC7 TTL \u65E9\u9000,\u59CB\u7EC8\u5C1D\u8BD5\u62C9\u7F51(\u4F9B `mod search` \u4E3B\u52A8\u5237\u65B0\u5217\u8868)\u3002\n * \u5931\u8D25\u65F6\u4ECD\u56DE\u9000\u5230\u7F13\u5B58,\u6C38\u4E0D\u629B\u5F02\u5E38\u3002\n */\nexport async function resolveRegistryIndex(opts?: { force?: boolean }): Promise<RegistryResult> {\n const cache = readCache();\n if (!opts?.force && cache && Date.now() - cache.fetchedAt < TTL_MS) {\n return { index: cache.index, stale: false };\n }\n try {\n const fresh = await fetchFresh();\n writeCache({ fetchedAt: Date.now(), index: fresh });\n return { index: fresh, stale: false };\n } catch (err) {\n if (cache) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`[sfmc] registry offline (${msg}); using cached index from ${new Date(cache.fetchedAt).toISOString()}\\n`);\n return { index: cache.index, stale: true };\n }\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`[sfmc] registry unreachable and no cache: ${msg}\\n`);\n return { index: {}, stale: true };\n }\n}\n\n/**\n * \u4ECE\u672C\u5730\u7F13\u5B58\u540C\u6B65\u8BFB\u51FA registry \u6A21\u5757 id(\u4F9B Tab \u8865\u5168)\u3002\n * \u65E0\u7F13\u5B58\u65F6\u8FD4\u56DE\u7A7A\u6570\u7EC4,\u4E0D\u89E6\u53D1\u7F51\u7EDC\u3002\n */\nexport function listRegistryModuleIdsSync(): string[] {\n const cache = readCache();\n if (!cache) return [];\n return Object.keys(cache.index).sort((a, b) => a.localeCompare(b));\n}\n\n/**\n * Compare a set of installed module ids to the registry and return the\n * subset that isn't published in the first-party index. The \"best-effort\"\n * guarantee: this returns an empty array when the registry can't be reached\n * (we don't want a network outage to mark every local module as unknown).\n */\nexport async function findUnknownModules(installedIds: string[]): Promise<string[]> {\n const { index, stale } = await resolveRegistryIndex();\n if (stale && Object.keys(index).length === 0) {\n /* No cache either \u2014 silently treat every module as \"we couldn't tell\".\n * Otherwise offline mode would scream warnings at every boot. */\n return [];\n }\n return installedIds.filter((id) => !index[id]);\n}\n\nexport { DEFAULT_REGISTRY_REPO, DEFAULT_REGISTRY_TAG };"],
5
+ "mappings": "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",
6
6
  "names": ["msg"]
7
7
  }
@@ -0,0 +1,10 @@
1
+ import { type UnifiedLog } from "../logs.js";
2
+ export type FormatDisplayOpts = {
3
+ /** 服务窗内省略来源标签(落盘不受影响) */
4
+ omitSource?: boolean;
5
+ };
6
+ /** TTY 展示格式化 */
7
+ export declare function formatLogDisplay(l: UnifiedLog, opts?: FormatDisplayOpts): string;
8
+ /** 与 formatLogDisplay 对齐的悬挂缩进宽度 */
9
+ export declare function logDisplayPrefixWidth(l: UnifiedLog, opts?: FormatDisplayOpts): number;
10
+ //# sourceMappingURL=format-display.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-display.d.ts","sourceRoot":"","sources":["../../src/repl-windows/format-display.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,UAAU,EAEhB,MAAM,YAAY,CAAC;AAgCpB,MAAM,MAAM,iBAAiB,GAAG;IAC9B,yBAAyB;IACzB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,gBAAgB;AAChB,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,GAAE,iBAAsB,GAAG,MAAM,CAUpF;AAED,mCAAmC;AACnC,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,GAAE,iBAAsB,GAAG,MAAM,CAQzF"}
@@ -0,0 +1,57 @@
1
+ import { stripBdsLogPrefix } from "@sfmc-bds/sdk/logs";
2
+ import {
3
+ formatSourceTag,
4
+ resolveDisplayLevel,
5
+ visibleWidth
6
+ } from "../logs.js";
7
+ import { c, highlightLogLine } from "../theme.js";
8
+ const LEVEL_PLAIN = {
9
+ error: "[ERR]",
10
+ warn: "[WRN]",
11
+ success: "[SUC]",
12
+ debug: "[DBG]",
13
+ info: "[INF]"
14
+ };
15
+ function levelTagDisplay(lvl) {
16
+ const text = LEVEL_PLAIN[lvl] ?? LEVEL_PLAIN.info;
17
+ switch (lvl) {
18
+ case "error":
19
+ return c.red(text);
20
+ case "warn":
21
+ return c.yellow(text);
22
+ case "success":
23
+ return c.green(c.bold(text));
24
+ case "debug":
25
+ return c.dim(text);
26
+ default:
27
+ return c.blue(text);
28
+ }
29
+ }
30
+ function levelTagPlain(lvl) {
31
+ return LEVEL_PLAIN[lvl] ?? LEVEL_PLAIN.info;
32
+ }
33
+ function formatLogDisplay(l, opts = {}) {
34
+ const ts = c.dim(l.time.toLocaleTimeString());
35
+ const level = resolveDisplayLevel(l);
36
+ const lvl = levelTagDisplay(level);
37
+ const txt = highlightLogLine(l.source === "bds" ? stripBdsLogPrefix(l.text) : l.text);
38
+ if (opts.omitSource) {
39
+ return `${ts} ${lvl} ${txt}`;
40
+ }
41
+ const src = formatSourceTag(l.source);
42
+ return `${ts} ${src} ${lvl} ${txt}`;
43
+ }
44
+ function logDisplayPrefixWidth(l, opts = {}) {
45
+ const ts = l.time.toLocaleTimeString();
46
+ const level = resolveDisplayLevel(l);
47
+ const lvl = levelTagPlain(level);
48
+ if (opts.omitSource) {
49
+ return visibleWidth(`${ts} ${lvl} `);
50
+ }
51
+ return visibleWidth(`${ts} ${formatSourceTag(l.source)} ${lvl} `);
52
+ }
53
+ export {
54
+ formatLogDisplay,
55
+ logDisplayPrefixWidth
56
+ };
57
+ //# sourceMappingURL=format-display.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/repl-windows/format-display.ts"],
4
+ "sourcesContent": ["/**\n * repl-windows/format-display.ts \u2014 \u4EC5 TTY \u5C55\u793A\uFF1B\u843D\u76D8\u4ECD\u7528 logs.formatLog / SDK formatLogLine\n */\nimport { stripBdsLogPrefix } from \"@sfmc-bds/sdk/logs\";\nimport {\n formatSourceTag,\n resolveDisplayLevel,\n type UnifiedLog,\n visibleWidth,\n} from \"../logs.js\";\nimport { c, highlightLogLine } from \"../theme.js\";\n\n/** \u4E0E logs.ts LEVEL_TAG_TEXT \u5BF9\u9F50\u7684\u65E0\u8272\u7EA7\u522B\uFF08\u907F\u514D\u6539\u52A8\u843D\u76D8\u8DEF\u5F84\uFF09 */\nconst LEVEL_PLAIN: Record<string, string> = {\n error: \"[ERR]\",\n warn: \"[WRN]\",\n success: \"[SUC]\",\n debug: \"[DBG]\",\n info: \"[INF]\",\n};\n\nfunction levelTagDisplay(lvl: string): string {\n const text = LEVEL_PLAIN[lvl] ?? LEVEL_PLAIN.info!;\n switch (lvl) {\n case \"error\":\n return c.red(text);\n case \"warn\":\n return c.yellow(text);\n case \"success\":\n return c.green(c.bold(text));\n case \"debug\":\n return c.dim(text);\n default:\n return c.blue(text);\n }\n}\n\nfunction levelTagPlain(lvl: string): string {\n return LEVEL_PLAIN[lvl] ?? LEVEL_PLAIN.info!;\n}\n\nexport type FormatDisplayOpts = {\n /** \u670D\u52A1\u7A97\u5185\u7701\u7565\u6765\u6E90\u6807\u7B7E\uFF08\u843D\u76D8\u4E0D\u53D7\u5F71\u54CD\uFF09 */\n omitSource?: boolean;\n};\n\n/** TTY \u5C55\u793A\u683C\u5F0F\u5316 */\nexport function formatLogDisplay(l: UnifiedLog, opts: FormatDisplayOpts = {}): string {\n const ts = c.dim(l.time.toLocaleTimeString());\n const level = resolveDisplayLevel(l);\n const lvl = levelTagDisplay(level);\n const txt = highlightLogLine(l.source === \"bds\" ? stripBdsLogPrefix(l.text) : l.text);\n if (opts.omitSource) {\n return `${ts} ${lvl} ${txt}`;\n }\n const src = formatSourceTag(l.source);\n return `${ts} ${src} ${lvl} ${txt}`;\n}\n\n/** \u4E0E formatLogDisplay \u5BF9\u9F50\u7684\u60AC\u6302\u7F29\u8FDB\u5BBD\u5EA6 */\nexport function logDisplayPrefixWidth(l: UnifiedLog, opts: FormatDisplayOpts = {}): number {\n const ts = l.time.toLocaleTimeString();\n const level = resolveDisplayLevel(l);\n const lvl = levelTagPlain(level);\n if (opts.omitSource) {\n return visibleWidth(`${ts} ${lvl} `);\n }\n return visibleWidth(`${ts} ${formatSourceTag(l.source)} ${lvl} `);\n}\n"],
5
+ "mappings": "AAGA,SAAS,yBAAyB;AAClC;AAAA,EACE;AAAA,EACA;AAAA,EAEA;AAAA,OACK;AACP,SAAS,GAAG,wBAAwB;AAGpC,MAAM,cAAsC;AAAA,EAC1C,OAAO;AAAA,EACP,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AAAA,EACP,MAAM;AACR;AAEA,SAAS,gBAAgB,KAAqB;AAC5C,QAAM,OAAO,YAAY,GAAG,KAAK,YAAY;AAC7C,UAAQ,KAAK;AAAA,IACX,KAAK;AACH,aAAO,EAAE,IAAI,IAAI;AAAA,IACnB,KAAK;AACH,aAAO,EAAE,OAAO,IAAI;AAAA,IACtB,KAAK;AACH,aAAO,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;AAAA,IAC7B,KAAK;AACH,aAAO,EAAE,IAAI,IAAI;AAAA,IACnB;AACE,aAAO,EAAE,KAAK,IAAI;AAAA,EACtB;AACF;AAEA,SAAS,cAAc,KAAqB;AAC1C,SAAO,YAAY,GAAG,KAAK,YAAY;AACzC;AAQO,SAAS,iBAAiB,GAAe,OAA0B,CAAC,GAAW;AACpF,QAAM,KAAK,EAAE,IAAI,EAAE,KAAK,mBAAmB,CAAC;AAC5C,QAAM,QAAQ,oBAAoB,CAAC;AACnC,QAAM,MAAM,gBAAgB,KAAK;AACjC,QAAM,MAAM,iBAAiB,EAAE,WAAW,QAAQ,kBAAkB,EAAE,IAAI,IAAI,EAAE,IAAI;AACpF,MAAI,KAAK,YAAY;AACnB,WAAO,GAAG,EAAE,IAAI,GAAG,IAAI,GAAG;AAAA,EAC5B;AACA,QAAM,MAAM,gBAAgB,EAAE,MAAM;AACpC,SAAO,GAAG,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG;AACnC;AAGO,SAAS,sBAAsB,GAAe,OAA0B,CAAC,GAAW;AACzF,QAAM,KAAK,EAAE,KAAK,mBAAmB;AACrC,QAAM,QAAQ,oBAAoB,CAAC;AACnC,QAAM,MAAM,cAAc,KAAK;AAC/B,MAAI,KAAK,YAAY;AACnB,WAAO,aAAa,GAAG,EAAE,IAAI,GAAG,GAAG;AAAA,EACrC;AACA,SAAO,aAAa,GAAG,EAAE,IAAI,gBAAgB,EAAE,MAAM,CAAC,IAAI,GAAG,GAAG;AAClE;",
6
+ "names": []
7
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * repl-windows/host.ts — 窗口注册与切换(不写业务,只调度 ReplWindow)
3
+ *
4
+ * 每扇窗维护已渲染行缓存:切走清屏,切回直接恢复;后台仍把匹配日志写入对应缓存。
5
+ */
6
+ import { type UnifiedLog } from "../logs.js";
7
+ import type { ServiceName } from "../services.js";
8
+ import type { ReplWindow, WindowChrome, WindowKeyEvent, WindowKeyResult } from "./types.js";
9
+ export type HostWriteLog = (wrappedLine: string) => void;
10
+ export declare class WindowHost {
11
+ private readonly windows;
12
+ /** 窗口 id → 已渲染(已 wrap)的行;切回时直接 dump,无需重拉源 */
13
+ private readonly buffers;
14
+ /** 服务窗循环顺序(仅活跃服务) */
15
+ private serviceOrder;
16
+ private activeId;
17
+ private previousId;
18
+ private readonly writeLog;
19
+ private readonly onChromeChange;
20
+ constructor(opts: {
21
+ writeLog: HostWriteLog;
22
+ onChromeChange?: () => void;
23
+ });
24
+ register(win: ReplWindow): void;
25
+ unregister(id: string): void;
26
+ has(id: string): boolean;
27
+ getActive(): ReplWindow | undefined;
28
+ getActiveId(): string | null;
29
+ getChrome(): WindowChrome;
30
+ /** 是否已有展示缓存(有则切回时勿再 seed) */
31
+ hasBuffer(id: string): boolean;
32
+ getBuffer(id: string): readonly string[];
33
+ /** 首次进入时写入种子行 */
34
+ setBuffer(id: string, lines: string[]): void;
35
+ invalidateBuffer(id: string): void;
36
+ private appendToBuffer;
37
+ /** 按活跃服务同步 ServiceWindow id 列表(id = svc:<name>) */
38
+ setServiceOrder(ids: string[]): void;
39
+ open(id: string): boolean;
40
+ back(): boolean;
41
+ /**
42
+ * 在服务窗之间循环;返回新激活窗的 serviceName(供同步发送目标)。
43
+ * 若当前在非服务窗,先回到服务环。
44
+ */
45
+ cycleServiceWindows(): ServiceName | null;
46
+ /**
47
+ * 新日志:写入所有已 seed 缓存且 accept 的窗口;仅活动窗刷到 TTY。
48
+ * 活动窗尚未 seed:只刷 TTY(随后 showActiveWindow 会 seed 含历史的缓存)。
49
+ */
50
+ routeLog(log: UnifiedLog): void;
51
+ /** 返回活动窗对日志的展示结果(含 acceptLog) */
52
+ formatActiveLog(log: UnifiedLog): {
53
+ text: string;
54
+ indent: number;
55
+ } | null;
56
+ onKey(ev: WindowKeyEvent): WindowKeyResult;
57
+ isLogsActive(): boolean;
58
+ }
59
+ export declare function serviceWindowId(name: ServiceName): string;
60
+ //# sourceMappingURL=host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/repl-windows/host.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAe,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE5F,MAAM,MAAM,YAAY,GAAG,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;AAEzD,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiC;IACzD,6CAA6C;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+B;IACvD,qBAAqB;IACrB,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;IACxC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA2B;IAE1D,YAAY,IAAI,EAAE;QAAE,QAAQ,EAAE,YAAY,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAA;KAAE,EAGxE;IAED,QAAQ,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CAE9B;IAED,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAS3B;IAED,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAEvB;IAED,SAAS,IAAI,UAAU,GAAG,SAAS,CAElC;IAED,WAAW,IAAI,MAAM,GAAG,IAAI,CAE3B;IAED,SAAS,IAAI,YAAY,CAUxB;IAED,6BAA6B;IAC7B,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE7B;IAED,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAEvC;IAED,iBAAiB;IACjB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAE3C;IAED,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAEjC;IAED,OAAO,CAAC,cAAc;IAStB,mDAAmD;IACnD,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,CAenC;IAED,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAiBxB;IAED,IAAI,IAAI,OAAO,CAYd;IAED;;;OAGG;IACH,mBAAmB,IAAI,WAAW,GAAG,IAAI,CAWxC;IAED;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CAe9B;IAED,iCAAiC;IACjC,eAAe,CAAC,GAAG,EAAE,UAAU,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAIxE;IAED,KAAK,CAAC,EAAE,EAAE,cAAc,GAAG,eAAe,CASzC;IAED,YAAY,IAAI,OAAO,CAEtB;CACF;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAEzD"}
@@ -0,0 +1,179 @@
1
+ import { wrapLogLine } from "../logs.js";
2
+ class WindowHost {
3
+ windows = /* @__PURE__ */ new Map();
4
+ /** 窗口 id → 已渲染(已 wrap)的行;切回时直接 dump,无需重拉源 */
5
+ buffers = /* @__PURE__ */ new Map();
6
+ /** 服务窗循环顺序(仅活跃服务) */
7
+ serviceOrder = [];
8
+ activeId = null;
9
+ previousId = null;
10
+ writeLog;
11
+ onChromeChange;
12
+ constructor(opts) {
13
+ this.writeLog = opts.writeLog;
14
+ this.onChromeChange = opts.onChromeChange;
15
+ }
16
+ register(win) {
17
+ this.windows.set(win.id, win);
18
+ }
19
+ unregister(id) {
20
+ if (this.activeId === id) {
21
+ this.activeId = this.previousId;
22
+ this.previousId = null;
23
+ }
24
+ if (this.previousId === id) this.previousId = null;
25
+ this.windows.delete(id);
26
+ this.buffers.delete(id);
27
+ this.serviceOrder = this.serviceOrder.filter((x) => x !== id);
28
+ }
29
+ has(id) {
30
+ return this.windows.has(id);
31
+ }
32
+ getActive() {
33
+ return this.activeId ? this.windows.get(this.activeId) : void 0;
34
+ }
35
+ getActiveId() {
36
+ return this.activeId;
37
+ }
38
+ getChrome() {
39
+ const w = this.getActive();
40
+ if (!w) {
41
+ return { showsInput: true, footerShortcuts: "", title: "" };
42
+ }
43
+ return {
44
+ showsInput: w.showsInput,
45
+ footerShortcuts: w.footerShortcuts,
46
+ title: w.title
47
+ };
48
+ }
49
+ /** 是否已有展示缓存(有则切回时勿再 seed) */
50
+ hasBuffer(id) {
51
+ return this.buffers.has(id);
52
+ }
53
+ getBuffer(id) {
54
+ return this.buffers.get(id) ?? [];
55
+ }
56
+ /** 首次进入时写入种子行 */
57
+ setBuffer(id, lines) {
58
+ this.buffers.set(id, [...lines]);
59
+ }
60
+ invalidateBuffer(id) {
61
+ this.buffers.delete(id);
62
+ }
63
+ appendToBuffer(id, wrappedLine) {
64
+ let buf = this.buffers.get(id);
65
+ if (!buf) {
66
+ buf = [];
67
+ this.buffers.set(id, buf);
68
+ }
69
+ buf.push(wrappedLine);
70
+ }
71
+ /** 按活跃服务同步 ServiceWindow id 列表(id = svc:<name>) */
72
+ setServiceOrder(ids) {
73
+ this.serviceOrder = [...ids];
74
+ const stale = [...this.windows.keys()].filter((id) => id.startsWith("svc:") && !ids.includes(id));
75
+ for (const id of stale) {
76
+ this.windows.delete(id);
77
+ this.buffers.delete(id);
78
+ if (this.activeId === id) this.activeId = null;
79
+ if (this.previousId === id) this.previousId = null;
80
+ }
81
+ if (this.activeId?.startsWith("svc:") && !ids.includes(this.activeId)) {
82
+ this.activeId = null;
83
+ }
84
+ if (!this.activeId && ids.length > 0) {
85
+ this.open(ids[0]);
86
+ }
87
+ }
88
+ open(id) {
89
+ const next = this.windows.get(id);
90
+ if (!next) return false;
91
+ if (this.activeId === id) {
92
+ next.onActivate?.();
93
+ this.onChromeChange?.();
94
+ return true;
95
+ }
96
+ const prev = this.getActive();
97
+ prev?.onDeactivate?.();
98
+ if (this.activeId && this.activeId !== id) {
99
+ this.previousId = this.activeId;
100
+ }
101
+ this.activeId = id;
102
+ next.onActivate?.();
103
+ this.onChromeChange?.();
104
+ return true;
105
+ }
106
+ back() {
107
+ const fallback = (this.previousId && this.windows.has(this.previousId) ? this.previousId : null) ?? this.serviceOrder.find((id) => this.windows.has(id)) ?? null;
108
+ this.previousId = null;
109
+ if (!fallback) {
110
+ this.activeId = null;
111
+ this.onChromeChange?.();
112
+ return false;
113
+ }
114
+ return this.open(fallback);
115
+ }
116
+ /**
117
+ * 在服务窗之间循环;返回新激活窗的 serviceName(供同步发送目标)。
118
+ * 若当前在非服务窗,先回到服务环。
119
+ */
120
+ cycleServiceWindows() {
121
+ if (this.serviceOrder.length === 0) return null;
122
+ const cur = this.activeId;
123
+ const idx = cur ? this.serviceOrder.indexOf(cur) : -1;
124
+ if (idx < 0) {
125
+ this.open(this.serviceOrder[0]);
126
+ } else {
127
+ const next = this.serviceOrder[(idx + 1) % this.serviceOrder.length];
128
+ this.open(next);
129
+ }
130
+ return this.getActive()?.serviceName ?? null;
131
+ }
132
+ /**
133
+ * 新日志:写入所有已 seed 缓存且 accept 的窗口;仅活动窗刷到 TTY。
134
+ * 活动窗尚未 seed:只刷 TTY(随后 showActiveWindow 会 seed 含历史的缓存)。
135
+ */
136
+ routeLog(log) {
137
+ for (const [id, w] of this.windows) {
138
+ if (!w.acceptLog(log)) continue;
139
+ if (!this.buffers.has(id)) {
140
+ if (id === this.activeId) {
141
+ const { text: text2, indent: indent2 } = w.formatLogLine(log);
142
+ this.writeLog(wrapLogLine(text2, indent2));
143
+ }
144
+ continue;
145
+ }
146
+ const { text, indent } = w.formatLogLine(log);
147
+ const wrapped = wrapLogLine(text, indent);
148
+ this.appendToBuffer(id, wrapped);
149
+ if (id === this.activeId) this.writeLog(wrapped);
150
+ }
151
+ }
152
+ /** 返回活动窗对日志的展示结果(含 acceptLog) */
153
+ formatActiveLog(log) {
154
+ const w = this.getActive();
155
+ if (!w || !w.acceptLog(log)) return null;
156
+ return w.formatLogLine(log);
157
+ }
158
+ onKey(ev) {
159
+ const w = this.getActive();
160
+ if (!w?.onKey) return { action: "none" };
161
+ const r = w.onKey(ev);
162
+ if (r.action === "back") {
163
+ this.back();
164
+ return { action: "redraw" };
165
+ }
166
+ return r;
167
+ }
168
+ isLogsActive() {
169
+ return this.activeId === "logs";
170
+ }
171
+ }
172
+ function serviceWindowId(name) {
173
+ return `svc:${name}`;
174
+ }
175
+ export {
176
+ WindowHost,
177
+ serviceWindowId
178
+ };
179
+ //# sourceMappingURL=host.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/repl-windows/host.ts"],
4
+ "sourcesContent": ["/**\n * repl-windows/host.ts \u2014 \u7A97\u53E3\u6CE8\u518C\u4E0E\u5207\u6362\uFF08\u4E0D\u5199\u4E1A\u52A1\uFF0C\u53EA\u8C03\u5EA6 ReplWindow\uFF09\n *\n * \u6BCF\u6247\u7A97\u7EF4\u62A4\u5DF2\u6E32\u67D3\u884C\u7F13\u5B58\uFF1A\u5207\u8D70\u6E05\u5C4F\uFF0C\u5207\u56DE\u76F4\u63A5\u6062\u590D\uFF1B\u540E\u53F0\u4ECD\u628A\u5339\u914D\u65E5\u5FD7\u5199\u5165\u5BF9\u5E94\u7F13\u5B58\u3002\n */\nimport { wrapLogLine, type UnifiedLog } from \"../logs.js\";\nimport type { ServiceName } from \"../services.js\";\nimport type { ReplWindow, WindowChrome, WindowKeyEvent, WindowKeyResult } from \"./types.js\";\n\nexport type HostWriteLog = (wrappedLine: string) => void;\n\nexport class WindowHost {\n private readonly windows = new Map<string, ReplWindow>();\n /** \u7A97\u53E3 id \u2192 \u5DF2\u6E32\u67D3\uFF08\u5DF2 wrap\uFF09\u7684\u884C\uFF1B\u5207\u56DE\u65F6\u76F4\u63A5 dump\uFF0C\u65E0\u9700\u91CD\u62C9\u6E90 */\n private readonly buffers = new Map<string, string[]>();\n /** \u670D\u52A1\u7A97\u5FAA\u73AF\u987A\u5E8F\uFF08\u4EC5\u6D3B\u8DC3\u670D\u52A1\uFF09 */\n private serviceOrder: string[] = [];\n private activeId: string | null = null;\n private previousId: string | null = null;\n private readonly writeLog: HostWriteLog;\n private readonly onChromeChange: (() => void) | undefined;\n\n constructor(opts: { writeLog: HostWriteLog; onChromeChange?: () => void }) {\n this.writeLog = opts.writeLog;\n this.onChromeChange = opts.onChromeChange;\n }\n\n register(win: ReplWindow): void {\n this.windows.set(win.id, win);\n }\n\n unregister(id: string): void {\n if (this.activeId === id) {\n this.activeId = this.previousId;\n this.previousId = null;\n }\n if (this.previousId === id) this.previousId = null;\n this.windows.delete(id);\n this.buffers.delete(id);\n this.serviceOrder = this.serviceOrder.filter((x) => x !== id);\n }\n\n has(id: string): boolean {\n return this.windows.has(id);\n }\n\n getActive(): ReplWindow | undefined {\n return this.activeId ? this.windows.get(this.activeId) : undefined;\n }\n\n getActiveId(): string | null {\n return this.activeId;\n }\n\n getChrome(): WindowChrome {\n const w = this.getActive();\n if (!w) {\n return { showsInput: true, footerShortcuts: \"\", title: \"\" };\n }\n return {\n showsInput: w.showsInput,\n footerShortcuts: w.footerShortcuts,\n title: w.title,\n };\n }\n\n /** \u662F\u5426\u5DF2\u6709\u5C55\u793A\u7F13\u5B58\uFF08\u6709\u5219\u5207\u56DE\u65F6\u52FF\u518D seed\uFF09 */\n hasBuffer(id: string): boolean {\n return this.buffers.has(id);\n }\n\n getBuffer(id: string): readonly string[] {\n return this.buffers.get(id) ?? [];\n }\n\n /** \u9996\u6B21\u8FDB\u5165\u65F6\u5199\u5165\u79CD\u5B50\u884C */\n setBuffer(id: string, lines: string[]): void {\n this.buffers.set(id, [...lines]);\n }\n\n invalidateBuffer(id: string): void {\n this.buffers.delete(id);\n }\n\n private appendToBuffer(id: string, wrappedLine: string): void {\n let buf = this.buffers.get(id);\n if (!buf) {\n buf = [];\n this.buffers.set(id, buf);\n }\n buf.push(wrappedLine);\n }\n\n /** \u6309\u6D3B\u8DC3\u670D\u52A1\u540C\u6B65 ServiceWindow id \u5217\u8868\uFF08id = svc:<name>\uFF09 */\n setServiceOrder(ids: string[]): void {\n this.serviceOrder = [...ids];\n const stale = [...this.windows.keys()].filter((id) => id.startsWith(\"svc:\") && !ids.includes(id));\n for (const id of stale) {\n this.windows.delete(id);\n this.buffers.delete(id);\n if (this.activeId === id) this.activeId = null;\n if (this.previousId === id) this.previousId = null;\n }\n if (this.activeId?.startsWith(\"svc:\") && !ids.includes(this.activeId)) {\n this.activeId = null;\n }\n if (!this.activeId && ids.length > 0) {\n this.open(ids[0]!);\n }\n }\n\n open(id: string): boolean {\n const next = this.windows.get(id);\n if (!next) return false;\n if (this.activeId === id) {\n next.onActivate?.();\n this.onChromeChange?.();\n return true;\n }\n const prev = this.getActive();\n prev?.onDeactivate?.();\n if (this.activeId && this.activeId !== id) {\n this.previousId = this.activeId;\n }\n this.activeId = id;\n next.onActivate?.();\n this.onChromeChange?.();\n return true;\n }\n\n back(): boolean {\n const fallback =\n (this.previousId && this.windows.has(this.previousId) ? this.previousId : null) ??\n this.serviceOrder.find((id) => this.windows.has(id)) ??\n null;\n this.previousId = null;\n if (!fallback) {\n this.activeId = null;\n this.onChromeChange?.();\n return false;\n }\n return this.open(fallback);\n }\n\n /**\n * \u5728\u670D\u52A1\u7A97\u4E4B\u95F4\u5FAA\u73AF\uFF1B\u8FD4\u56DE\u65B0\u6FC0\u6D3B\u7A97\u7684 serviceName\uFF08\u4F9B\u540C\u6B65\u53D1\u9001\u76EE\u6807\uFF09\u3002\n * \u82E5\u5F53\u524D\u5728\u975E\u670D\u52A1\u7A97\uFF0C\u5148\u56DE\u5230\u670D\u52A1\u73AF\u3002\n */\n cycleServiceWindows(): ServiceName | null {\n if (this.serviceOrder.length === 0) return null;\n const cur = this.activeId;\n const idx = cur ? this.serviceOrder.indexOf(cur) : -1;\n if (idx < 0) {\n this.open(this.serviceOrder[0]!);\n } else {\n const next = this.serviceOrder[(idx + 1) % this.serviceOrder.length]!;\n this.open(next);\n }\n return this.getActive()?.serviceName ?? null;\n }\n\n /**\n * \u65B0\u65E5\u5FD7\uFF1A\u5199\u5165\u6240\u6709\u5DF2 seed \u7F13\u5B58\u4E14 accept \u7684\u7A97\u53E3\uFF1B\u4EC5\u6D3B\u52A8\u7A97\u5237\u5230 TTY\u3002\n * \u6D3B\u52A8\u7A97\u5C1A\u672A seed\uFF1A\u53EA\u5237 TTY\uFF08\u968F\u540E showActiveWindow \u4F1A seed \u542B\u5386\u53F2\u7684\u7F13\u5B58\uFF09\u3002\n */\n routeLog(log: UnifiedLog): void {\n for (const [id, w] of this.windows) {\n if (!w.acceptLog(log)) continue;\n if (!this.buffers.has(id)) {\n if (id === this.activeId) {\n const { text, indent } = w.formatLogLine(log);\n this.writeLog(wrapLogLine(text, indent));\n }\n continue;\n }\n const { text, indent } = w.formatLogLine(log);\n const wrapped = wrapLogLine(text, indent);\n this.appendToBuffer(id, wrapped);\n if (id === this.activeId) this.writeLog(wrapped);\n }\n }\n\n /** \u8FD4\u56DE\u6D3B\u52A8\u7A97\u5BF9\u65E5\u5FD7\u7684\u5C55\u793A\u7ED3\u679C\uFF08\u542B acceptLog\uFF09 */\n formatActiveLog(log: UnifiedLog): { text: string; indent: number } | null {\n const w = this.getActive();\n if (!w || !w.acceptLog(log)) return null;\n return w.formatLogLine(log);\n }\n\n onKey(ev: WindowKeyEvent): WindowKeyResult {\n const w = this.getActive();\n if (!w?.onKey) return { action: \"none\" };\n const r = w.onKey(ev);\n if (r.action === \"back\") {\n this.back();\n return { action: \"redraw\" };\n }\n return r;\n }\n\n isLogsActive(): boolean {\n return this.activeId === \"logs\";\n }\n}\n\nexport function serviceWindowId(name: ServiceName): string {\n return `svc:${name}`;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["text", "indent"]
7
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * repl-windows/index.ts — 类窗口系统出口
3
+ */
4
+ export { formatLogDisplay, logDisplayPrefixWidth } from "./format-display.js";
5
+ export { WindowHost, serviceWindowId } from "./host.js";
6
+ export { createLogsFilterWindow, type LogsFilterState } from "./logs-filter-window.js";
7
+ export { createServiceWindow } from "./service-window.js";
8
+ export type { ReplWindow, WindowChrome, WindowKeyEvent, WindowKeyResult } from "./types.js";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/repl-windows/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAC;AACvF,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { formatLogDisplay, logDisplayPrefixWidth } from "./format-display.js";
2
+ import { WindowHost, serviceWindowId } from "./host.js";
3
+ import { createLogsFilterWindow } from "./logs-filter-window.js";
4
+ import { createServiceWindow } from "./service-window.js";
5
+ export {
6
+ WindowHost,
7
+ createLogsFilterWindow,
8
+ createServiceWindow,
9
+ formatLogDisplay,
10
+ logDisplayPrefixWidth,
11
+ serviceWindowId
12
+ };
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/repl-windows/index.ts"],
4
+ "sourcesContent": ["/**\n * repl-windows/index.ts \u2014 \u7C7B\u7A97\u53E3\u7CFB\u7EDF\u51FA\u53E3\n */\nexport { formatLogDisplay, logDisplayPrefixWidth } from \"./format-display.js\";\nexport { WindowHost, serviceWindowId } from \"./host.js\";\nexport { createLogsFilterWindow, type LogsFilterState } from \"./logs-filter-window.js\";\nexport { createServiceWindow } from \"./service-window.js\";\nexport type { ReplWindow, WindowChrome, WindowKeyEvent, WindowKeyResult } from \"./types.js\";\n"],
5
+ "mappings": "AAGA,SAAS,kBAAkB,6BAA6B;AACxD,SAAS,YAAY,uBAAuB;AAC5C,SAAS,8BAAoD;AAC7D,SAAS,2BAA2B;",
6
+ "names": []
7
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * repl-windows/logs-filter-window.ts — /logs 筛选窗(无输入,快捷键筛选)
3
+ */
4
+ import { type LogLevel, type LogSource } from "../logs.js";
5
+ import type { ReplWindow } from "./types.js";
6
+ export type LogsFilterState = {
7
+ levels: LogLevel[];
8
+ sources: LogSource[];
9
+ };
10
+ export declare function createLogsFilterWindow(opts: {
11
+ getState: () => LogsFilterState;
12
+ setState: (next: LogsFilterState) => void;
13
+ onFilterChanged: () => void;
14
+ }): ReplWindow;
15
+ //# sourceMappingURL=logs-filter-window.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs-filter-window.d.ts","sourceRoot":"","sources":["../../src/repl-windows/logs-filter-window.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAe,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAmB,MAAM,YAAY,CAAC;AAGzF,OAAO,KAAK,EAAE,UAAU,EAAmC,MAAM,YAAY,CAAC;AAI9E,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,OAAO,EAAE,SAAS,EAAE,CAAC;CACtB,CAAC;AAYF,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAC3C,QAAQ,EAAE,MAAM,eAAe,CAAC;IAChC,QAAQ,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAC;IAC1C,eAAe,EAAE,MAAM,IAAI,CAAC;CAC7B,GAAG,UAAU,CAiEb"}
@@ -0,0 +1,77 @@
1
+ import { SOURCE_META } from "../logs.js";
2
+ import { c } from "../theme.js";
3
+ import { formatLogDisplay, logDisplayPrefixWidth } from "./format-display.js";
4
+ const LEVELS = ["", "info", "warn", "error", "debug", "success"];
5
+ function paintFooter(state) {
6
+ const lv = state.levels[0] ?? "*";
7
+ const src = state.sources[0] ?? "*";
8
+ return ` ${c.cyan("L")}${c.dim(" level:")}${c.text(String(lv))} ${c.cyan("S")}${c.dim(" source:")}${c.text(String(src))} ${c.cyan("Esc")}${c.dim(" back")}`;
9
+ }
10
+ function createLogsFilterWindow(opts) {
11
+ const cycleLevel = () => {
12
+ const st = opts.getState();
13
+ const cur = st.levels[0] ?? "";
14
+ const idx = LEVELS.indexOf(cur);
15
+ const next = LEVELS[(idx + 1) % LEVELS.length];
16
+ opts.setState({
17
+ ...st,
18
+ levels: next ? [next] : []
19
+ });
20
+ opts.onFilterChanged();
21
+ };
22
+ const cycleSource = () => {
23
+ const st = opts.getState();
24
+ const names = ["", ...SOURCE_META.map((m) => m.value)];
25
+ const cur = st.sources[0] ?? "";
26
+ const idx = Math.max(0, names.indexOf(cur));
27
+ const next = names[(idx + 1) % names.length];
28
+ opts.setState({
29
+ ...st,
30
+ sources: next ? [next] : []
31
+ });
32
+ opts.onFilterChanged();
33
+ };
34
+ return {
35
+ id: "logs",
36
+ title: "LOGS",
37
+ showsInput: false,
38
+ get footerShortcuts() {
39
+ return paintFooter(opts.getState());
40
+ },
41
+ acceptLog(log) {
42
+ const st = opts.getState();
43
+ if (st.levels.length && !st.levels.includes(log.level)) return false;
44
+ if (st.sources.length && !st.sources.includes(log.source)) return false;
45
+ return true;
46
+ },
47
+ formatLogLine(log) {
48
+ return {
49
+ text: formatLogDisplay(log, { omitSource: false }),
50
+ indent: logDisplayPrefixWidth(log, { omitSource: false })
51
+ };
52
+ },
53
+ getReplayFilter() {
54
+ const st = opts.getState();
55
+ return { levels: st.levels, sources: st.sources };
56
+ },
57
+ onKey(ev) {
58
+ if (ev.type === "escape") return { action: "back" };
59
+ if (ev.type === "char") {
60
+ const ch = ev.ch.toLowerCase();
61
+ if (ch === "l") {
62
+ cycleLevel();
63
+ return { action: "redraw" };
64
+ }
65
+ if (ch === "s") {
66
+ cycleSource();
67
+ return { action: "redraw" };
68
+ }
69
+ }
70
+ return { action: "handled" };
71
+ }
72
+ };
73
+ }
74
+ export {
75
+ createLogsFilterWindow
76
+ };
77
+ //# sourceMappingURL=logs-filter-window.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/repl-windows/logs-filter-window.ts"],
4
+ "sourcesContent": ["/**\n * repl-windows/logs-filter-window.ts \u2014 /logs \u7B5B\u9009\u7A97\uFF08\u65E0\u8F93\u5165\uFF0C\u5FEB\u6377\u952E\u7B5B\u9009\uFF09\n */\nimport { SOURCE_META, type LogLevel, type LogSource, type UnifiedLog } from \"../logs.js\";\nimport { c } from \"../theme.js\";\nimport { formatLogDisplay, logDisplayPrefixWidth } from \"./format-display.js\";\nimport type { ReplWindow, WindowKeyEvent, WindowKeyResult } from \"./types.js\";\n\nconst LEVELS: Array<LogLevel | \"\"> = [\"\", \"info\", \"warn\", \"error\", \"debug\", \"success\"];\n\nexport type LogsFilterState = {\n levels: LogLevel[];\n sources: LogSource[];\n};\n\nfunction paintFooter(state: LogsFilterState): string {\n const lv = state.levels[0] ?? \"*\";\n const src = state.sources[0] ?? \"*\";\n return (\n ` ${c.cyan(\"L\")}${c.dim(\" level:\")}${c.text(String(lv))} ` +\n `${c.cyan(\"S\")}${c.dim(\" source:\")}${c.text(String(src))} ` +\n `${c.cyan(\"Esc\")}${c.dim(\" back\")}`\n );\n}\n\nexport function createLogsFilterWindow(opts: {\n getState: () => LogsFilterState;\n setState: (next: LogsFilterState) => void;\n onFilterChanged: () => void;\n}): ReplWindow {\n const cycleLevel = (): void => {\n const st = opts.getState();\n const cur = st.levels[0] ?? \"\";\n const idx = LEVELS.indexOf(cur as LogLevel | \"\");\n const next = LEVELS[(idx + 1) % LEVELS.length]!;\n opts.setState({\n ...st,\n levels: next ? [next] : [],\n });\n opts.onFilterChanged();\n };\n\n const cycleSource = (): void => {\n const st = opts.getState();\n const names: Array<LogSource | \"\"> = [\"\", ...SOURCE_META.map((m) => m.value)];\n const cur = st.sources[0] ?? \"\";\n const idx = Math.max(0, names.indexOf(cur));\n const next = names[(idx + 1) % names.length]!;\n opts.setState({\n ...st,\n sources: next ? [next] : [],\n });\n opts.onFilterChanged();\n };\n\n return {\n id: \"logs\",\n title: \"LOGS\",\n showsInput: false,\n get footerShortcuts() {\n return paintFooter(opts.getState());\n },\n acceptLog(log: UnifiedLog): boolean {\n const st = opts.getState();\n if (st.levels.length && !st.levels.includes(log.level)) return false;\n if (st.sources.length && !st.sources.includes(log.source)) return false;\n return true;\n },\n formatLogLine(log: UnifiedLog) {\n return {\n text: formatLogDisplay(log, { omitSource: false }),\n indent: logDisplayPrefixWidth(log, { omitSource: false }),\n };\n },\n getReplayFilter() {\n const st = opts.getState();\n return { levels: st.levels, sources: st.sources };\n },\n onKey(ev: WindowKeyEvent): WindowKeyResult {\n if (ev.type === \"escape\") return { action: \"back\" };\n if (ev.type === \"char\") {\n const ch = ev.ch.toLowerCase();\n if (ch === \"l\") {\n cycleLevel();\n return { action: \"redraw\" };\n }\n if (ch === \"s\") {\n cycleSource();\n return { action: \"redraw\" };\n }\n }\n return { action: \"handled\" };\n },\n };\n}\n"],
5
+ "mappings": "AAGA,SAAS,mBAAmE;AAC5E,SAAS,SAAS;AAClB,SAAS,kBAAkB,6BAA6B;AAGxD,MAAM,SAA+B,CAAC,IAAI,QAAQ,QAAQ,SAAS,SAAS,SAAS;AAOrF,SAAS,YAAY,OAAgC;AACnD,QAAM,KAAK,MAAM,OAAO,CAAC,KAAK;AAC9B,QAAM,MAAM,MAAM,QAAQ,CAAC,KAAK;AAChC,SACE,KAAK,EAAE,KAAK,GAAG,CAAC,GAAG,EAAE,IAAI,SAAS,CAAC,GAAG,EAAE,KAAK,OAAO,EAAE,CAAC,CAAC,KACrD,EAAE,KAAK,GAAG,CAAC,GAAG,EAAE,IAAI,UAAU,CAAC,GAAG,EAAE,KAAK,OAAO,GAAG,CAAC,CAAC,KACrD,EAAE,KAAK,KAAK,CAAC,GAAG,EAAE,IAAI,OAAO,CAAC;AAErC;AAEO,SAAS,uBAAuB,MAIxB;AACb,QAAM,aAAa,MAAY;AAC7B,UAAM,KAAK,KAAK,SAAS;AACzB,UAAM,MAAM,GAAG,OAAO,CAAC,KAAK;AAC5B,UAAM,MAAM,OAAO,QAAQ,GAAoB;AAC/C,UAAM,OAAO,QAAQ,MAAM,KAAK,OAAO,MAAM;AAC7C,SAAK,SAAS;AAAA,MACZ,GAAG;AAAA,MACH,QAAQ,OAAO,CAAC,IAAI,IAAI,CAAC;AAAA,IAC3B,CAAC;AACD,SAAK,gBAAgB;AAAA,EACvB;AAEA,QAAM,cAAc,MAAY;AAC9B,UAAM,KAAK,KAAK,SAAS;AACzB,UAAM,QAA+B,CAAC,IAAI,GAAG,YAAY,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAC5E,UAAM,MAAM,GAAG,QAAQ,CAAC,KAAK;AAC7B,UAAM,MAAM,KAAK,IAAI,GAAG,MAAM,QAAQ,GAAG,CAAC;AAC1C,UAAM,OAAO,OAAO,MAAM,KAAK,MAAM,MAAM;AAC3C,SAAK,SAAS;AAAA,MACZ,GAAG;AAAA,MACH,SAAS,OAAO,CAAC,IAAI,IAAI,CAAC;AAAA,IAC5B,CAAC;AACD,SAAK,gBAAgB;AAAA,EACvB;AAEA,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,IAAI,kBAAkB;AACpB,aAAO,YAAY,KAAK,SAAS,CAAC;AAAA,IACpC;AAAA,IACA,UAAU,KAA0B;AAClC,YAAM,KAAK,KAAK,SAAS;AACzB,UAAI,GAAG,OAAO,UAAU,CAAC,GAAG,OAAO,SAAS,IAAI,KAAK,EAAG,QAAO;AAC/D,UAAI,GAAG,QAAQ,UAAU,CAAC,GAAG,QAAQ,SAAS,IAAI,MAAM,EAAG,QAAO;AAClE,aAAO;AAAA,IACT;AAAA,IACA,cAAc,KAAiB;AAC7B,aAAO;AAAA,QACL,MAAM,iBAAiB,KAAK,EAAE,YAAY,MAAM,CAAC;AAAA,QACjD,QAAQ,sBAAsB,KAAK,EAAE,YAAY,MAAM,CAAC;AAAA,MAC1D;AAAA,IACF;AAAA,IACA,kBAAkB;AAChB,YAAM,KAAK,KAAK,SAAS;AACzB,aAAO,EAAE,QAAQ,GAAG,QAAQ,SAAS,GAAG,QAAQ;AAAA,IAClD;AAAA,IACA,MAAM,IAAqC;AACzC,UAAI,GAAG,SAAS,SAAU,QAAO,EAAE,QAAQ,OAAO;AAClD,UAAI,GAAG,SAAS,QAAQ;AACtB,cAAM,KAAK,GAAG,GAAG,YAAY;AAC7B,YAAI,OAAO,KAAK;AACd,qBAAW;AACX,iBAAO,EAAE,QAAQ,SAAS;AAAA,QAC5B;AACA,YAAI,OAAO,KAAK;AACd,sBAAY;AACZ,iBAAO,EAAE,QAAQ,SAAS;AAAA,QAC5B;AAAA,MACF;AACA,aAAO,EAAE,QAAQ,UAAU;AAAA,IAC7B;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,4 @@
1
+ import { type ServiceName } from "../services.js";
2
+ import type { ReplWindow } from "./types.js";
3
+ export declare function createServiceWindow(name: ServiceName): ReplWindow;
4
+ //# sourceMappingURL=service-window.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-window.d.ts","sourceRoot":"","sources":["../../src/repl-windows/service-window.ts"],"names":[],"mappings":"AAIA,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAS7C,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,WAAW,GAAG,UAAU,CAqBjE"}
@@ -0,0 +1,35 @@
1
+ import { getQqBackendMode } from "../services.js";
2
+ import { formatLogDisplay, logDisplayPrefixWidth } from "./format-display.js";
3
+ import { serviceWindowId } from "./host.js";
4
+ function serviceWindowTitle(name) {
5
+ if (name === "qq") {
6
+ return getQqBackendMode() === "llbot" ? "QQ\xB7LLBOT" : "QQ\xB7OFFICIAL";
7
+ }
8
+ return name.toUpperCase();
9
+ }
10
+ function createServiceWindow(name) {
11
+ const id = serviceWindowId(name);
12
+ return {
13
+ id,
14
+ title: serviceWindowTitle(name),
15
+ showsInput: true,
16
+ footerShortcuts: "",
17
+ serviceName: name,
18
+ acceptLog(log) {
19
+ return log.source === name;
20
+ },
21
+ formatLogLine(log) {
22
+ return {
23
+ text: formatLogDisplay(log, { omitSource: true }),
24
+ indent: logDisplayPrefixWidth(log, { omitSource: true })
25
+ };
26
+ },
27
+ getReplayFilter() {
28
+ return { levels: [], sources: [name] };
29
+ }
30
+ };
31
+ }
32
+ export {
33
+ createServiceWindow
34
+ };
35
+ //# sourceMappingURL=service-window.js.map