@tontoko/fast-playwright-mcp 0.0.4

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 (107) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +1047 -0
  3. package/cli.js +18 -0
  4. package/config.d.ts +124 -0
  5. package/index.d.ts +25 -0
  6. package/index.js +18 -0
  7. package/lib/actions.d.js +0 -0
  8. package/lib/batch/batch-executor.js +137 -0
  9. package/lib/browser-context-factory.js +252 -0
  10. package/lib/browser-server-backend.js +139 -0
  11. package/lib/config/constants.js +80 -0
  12. package/lib/config.js +405 -0
  13. package/lib/context.js +274 -0
  14. package/lib/diagnostics/common/diagnostic-base.js +63 -0
  15. package/lib/diagnostics/common/error-enrichment-utils.js +212 -0
  16. package/lib/diagnostics/common/index.js +56 -0
  17. package/lib/diagnostics/common/initialization-manager.js +210 -0
  18. package/lib/diagnostics/common/performance-tracker.js +132 -0
  19. package/lib/diagnostics/diagnostic-error.js +140 -0
  20. package/lib/diagnostics/diagnostic-level.js +123 -0
  21. package/lib/diagnostics/diagnostic-thresholds.js +347 -0
  22. package/lib/diagnostics/element-discovery.js +441 -0
  23. package/lib/diagnostics/enhanced-error-handler.js +376 -0
  24. package/lib/diagnostics/error-enrichment.js +157 -0
  25. package/lib/diagnostics/frame-reference-manager.js +179 -0
  26. package/lib/diagnostics/page-analyzer.js +639 -0
  27. package/lib/diagnostics/parallel-page-analyzer.js +129 -0
  28. package/lib/diagnostics/resource-manager.js +134 -0
  29. package/lib/diagnostics/smart-config.js +482 -0
  30. package/lib/diagnostics/smart-handle.js +118 -0
  31. package/lib/diagnostics/unified-system.js +717 -0
  32. package/lib/extension/cdp-relay.js +486 -0
  33. package/lib/extension/extension-context-factory.js +74 -0
  34. package/lib/extension/main.js +41 -0
  35. package/lib/file-utils.js +42 -0
  36. package/lib/generate-keys.js +75 -0
  37. package/lib/http-server.js +50 -0
  38. package/lib/in-process-client.js +64 -0
  39. package/lib/index.js +48 -0
  40. package/lib/javascript.js +90 -0
  41. package/lib/log.js +33 -0
  42. package/lib/loop/loop-claude.js +247 -0
  43. package/lib/loop/loop-open-ai.js +222 -0
  44. package/lib/loop/loop.js +174 -0
  45. package/lib/loop/main.js +46 -0
  46. package/lib/loopTools/context.js +76 -0
  47. package/lib/loopTools/main.js +65 -0
  48. package/lib/loopTools/perform.js +40 -0
  49. package/lib/loopTools/snapshot.js +37 -0
  50. package/lib/loopTools/tool.js +26 -0
  51. package/lib/manual-promise.js +125 -0
  52. package/lib/mcp/in-process-transport.js +91 -0
  53. package/lib/mcp/proxy-backend.js +127 -0
  54. package/lib/mcp/server.js +123 -0
  55. package/lib/mcp/transport.js +159 -0
  56. package/lib/package.js +28 -0
  57. package/lib/program.js +82 -0
  58. package/lib/response.js +493 -0
  59. package/lib/schemas/expectation.js +152 -0
  60. package/lib/session-log.js +210 -0
  61. package/lib/tab.js +417 -0
  62. package/lib/tools/base-tool-handler.js +141 -0
  63. package/lib/tools/batch-execute.js +150 -0
  64. package/lib/tools/common.js +65 -0
  65. package/lib/tools/console.js +60 -0
  66. package/lib/tools/diagnose/diagnose-analysis-runner.js +101 -0
  67. package/lib/tools/diagnose/diagnose-config-handler.js +130 -0
  68. package/lib/tools/diagnose/diagnose-report-builder.js +394 -0
  69. package/lib/tools/diagnose.js +147 -0
  70. package/lib/tools/dialogs.js +57 -0
  71. package/lib/tools/evaluate.js +67 -0
  72. package/lib/tools/files.js +53 -0
  73. package/lib/tools/find-elements.js +307 -0
  74. package/lib/tools/install.js +60 -0
  75. package/lib/tools/keyboard.js +93 -0
  76. package/lib/tools/mouse.js +110 -0
  77. package/lib/tools/navigate.js +82 -0
  78. package/lib/tools/network.js +50 -0
  79. package/lib/tools/pdf.js +46 -0
  80. package/lib/tools/screenshot.js +113 -0
  81. package/lib/tools/snapshot.js +158 -0
  82. package/lib/tools/tabs.js +97 -0
  83. package/lib/tools/tool.js +47 -0
  84. package/lib/tools/utils.js +131 -0
  85. package/lib/tools/wait.js +64 -0
  86. package/lib/tools.js +65 -0
  87. package/lib/types/batch.js +47 -0
  88. package/lib/types/diff.js +0 -0
  89. package/lib/types/performance.js +0 -0
  90. package/lib/types/threshold-base.js +0 -0
  91. package/lib/utils/array-utils.js +44 -0
  92. package/lib/utils/code-deduplication-utils.js +141 -0
  93. package/lib/utils/common-formatters.js +252 -0
  94. package/lib/utils/console-filter.js +64 -0
  95. package/lib/utils/diagnostic-report-utils.js +178 -0
  96. package/lib/utils/diff-formatter.js +126 -0
  97. package/lib/utils/disposable-manager.js +135 -0
  98. package/lib/utils/error-handler-middleware.js +77 -0
  99. package/lib/utils/image-processor.js +137 -0
  100. package/lib/utils/index.js +92 -0
  101. package/lib/utils/report-builder.js +189 -0
  102. package/lib/utils/request-logger.js +82 -0
  103. package/lib/utils/response-diff-detector.js +150 -0
  104. package/lib/utils/section-builder.js +62 -0
  105. package/lib/utils/tool-patterns.js +153 -0
  106. package/lib/utils.js +46 -0
  107. package/package.json +77 -0
@@ -0,0 +1,131 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
+
20
+ // src/tools/utils.ts
21
+ import debug from "debug";
22
+ import { asLocator } from "playwright-core/lib/utils";
23
+ import { TIMEOUTS } from "../config/constants.js";
24
+ var toolsDebug = debug("pw:mcp:tools");
25
+ async function waitForCompletion(tab, callback) {
26
+ const requests = new Set;
27
+ let frameNavigated = false;
28
+ let navigationCompleted = false;
29
+ let waitCallback = () => {};
30
+ const waitBarrier = new Promise((f) => {
31
+ waitCallback = f;
32
+ });
33
+ const requestListener = (request) => requests.add(request);
34
+ const requestFinishedListener = (request) => {
35
+ requests.delete(request);
36
+ if (!requests.size && navigationCompleted) {
37
+ waitCallback();
38
+ }
39
+ };
40
+ const frameNavigateListener = (frame) => {
41
+ if (frame.parentFrame()) {
42
+ return;
43
+ }
44
+ frameNavigated = true;
45
+ (async () => {
46
+ try {
47
+ await tab.waitForLoadState("load");
48
+ await tab.waitForLoadState("networkidle", {
49
+ timeout: getNavigationConfig().networkIdleTimeout
50
+ }).catch((error) => {
51
+ toolsDebug("Network idle timeout reached:", error);
52
+ });
53
+ navigationCompleted = true;
54
+ if (!requests.size) {
55
+ waitCallback();
56
+ }
57
+ } catch (error) {
58
+ toolsDebug("Load state waiting failed, continuing:", error);
59
+ navigationCompleted = true;
60
+ waitCallback();
61
+ }
62
+ })().catch((error) => {
63
+ toolsDebug("Navigation handling failed:", error);
64
+ navigationCompleted = true;
65
+ waitCallback();
66
+ });
67
+ };
68
+ const onTimeout = () => {
69
+ dispose();
70
+ navigationCompleted = true;
71
+ waitCallback();
72
+ };
73
+ tab.page.on("request", requestListener);
74
+ tab.page.on("requestfinished", requestFinishedListener);
75
+ tab.page.on("framenavigated", frameNavigateListener);
76
+ const timeout = setTimeout(onTimeout, getNavigationConfig().completionTimeout);
77
+ const dispose = () => {
78
+ tab.page.off("request", requestListener);
79
+ tab.page.off("requestfinished", requestFinishedListener);
80
+ tab.page.off("framenavigated", frameNavigateListener);
81
+ clearTimeout(timeout);
82
+ };
83
+ try {
84
+ const result = await callback();
85
+ if (!(requests.size || frameNavigated)) {
86
+ navigationCompleted = true;
87
+ waitCallback();
88
+ }
89
+ await waitBarrier;
90
+ if (frameNavigated) {
91
+ await tab.waitForTimeout(getNavigationConfig().stabilityWait);
92
+ try {
93
+ await tab.page.evaluate(() => document.readyState);
94
+ } catch (error) {
95
+ toolsDebug("Page readyState check failed (context may be destroyed):", error);
96
+ }
97
+ } else {
98
+ await tab.waitForTimeout(getNavigationConfig().defaultWait);
99
+ }
100
+ return result;
101
+ } finally {
102
+ dispose();
103
+ }
104
+ }
105
+ async function generateLocator(locator) {
106
+ try {
107
+ const { resolvedSelector } = await locator._resolveSelector();
108
+ return asLocator("javascript", resolvedSelector);
109
+ } catch (error) {
110
+ toolsDebug("Locator generation failed:", error);
111
+ throw new Error("Ref not found, likely because element was removed. Use browser_snapshot to see what elements are currently on the page.");
112
+ }
113
+ }
114
+ async function callOnPageNoTrace(page, callback) {
115
+ return await page._wrapApiCall(() => callback(page), {
116
+ internal: true
117
+ });
118
+ }
119
+ function getNavigationConfig() {
120
+ return {
121
+ networkIdleTimeout: TIMEOUTS.NETWORK_IDLE_TIMEOUT,
122
+ completionTimeout: 15000,
123
+ stabilityWait: TIMEOUTS.STABILITY_WAIT,
124
+ defaultWait: TIMEOUTS.WAIT_FOR_COMPLETION
125
+ };
126
+ }
127
+ export {
128
+ waitForCompletion,
129
+ generateLocator,
130
+ callOnPageNoTrace
131
+ };
@@ -0,0 +1,64 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
+
20
+ // src/tools/wait.ts
21
+ import { z } from "zod";
22
+ import { expectationSchema } from "../schemas/expectation.js";
23
+ import { defineTool } from "./tool.js";
24
+ var wait = defineTool({
25
+ capability: "core",
26
+ schema: {
27
+ name: "browser_wait_for",
28
+ title: "Wait for",
29
+ description: `Wait for text to appear/disappear or time to pass.PREFER text-based wait over time for reliability.For loading states:wait for text:"Loading..." textGone:true.For dynamic content:wait for specific text to appear.expectation:{includeSnapshot:true,snapshotOptions:{selector:"#status"},diffOptions:{enabled:true}} shows only what changed.AVOID:fixed time waits unless necessary.`,
30
+ inputSchema: z.object({
31
+ time: z.number().optional().describe("The time to wait in seconds"),
32
+ text: z.string().optional().describe("The text to wait for"),
33
+ textGone: z.string().optional().describe("The text to wait for to disappear"),
34
+ expectation: expectationSchema
35
+ }),
36
+ type: "readOnly"
37
+ },
38
+ handle: async (context, params, response) => {
39
+ if (!(params.text || params.textGone || params.time)) {
40
+ throw new Error("Either time, text or textGone must be provided");
41
+ }
42
+ if (params.time) {
43
+ response.addCode(`await new Promise(f => setTimeout(f, ${params.time} * 1000));`);
44
+ await new Promise((f) => setTimeout(f, Math.min(30000, (params.time ?? 0) * 1000)));
45
+ }
46
+ const tab = context.currentTabOrDie();
47
+ const locator = params.text ? tab.page.getByText(params.text).first() : undefined;
48
+ const goneLocator = params.textGone ? tab.page.getByText(params.textGone).first() : undefined;
49
+ if (goneLocator) {
50
+ response.addCode(`await page.getByText(${JSON.stringify(params.textGone)}).first().waitFor({ state: 'hidden' });`);
51
+ await goneLocator.waitFor({ state: "hidden" });
52
+ }
53
+ if (locator) {
54
+ response.addCode(`await page.getByText(${JSON.stringify(params.text)}).first().waitFor({ state: 'visible' });`);
55
+ await locator.waitFor({ state: "visible" });
56
+ }
57
+ response.addResult(`Waited for ${params.text ?? params.textGone ?? params.time}`);
58
+ response.setIncludeSnapshot();
59
+ }
60
+ });
61
+ var wait_default = [wait];
62
+ export {
63
+ wait_default as default
64
+ };
package/lib/tools.js ADDED
@@ -0,0 +1,65 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
+
20
+ // src/tools.ts
21
+ import { batchExecuteTool } from "./tools/batch-execute.js";
22
+ import common from "./tools/common.js";
23
+ import console from "./tools/console.js";
24
+ import { browserDiagnose } from "./tools/diagnose.js";
25
+ import dialogs from "./tools/dialogs.js";
26
+ import evaluate from "./tools/evaluate.js";
27
+ import files from "./tools/files.js";
28
+ import { browserFindElements } from "./tools/find-elements.js";
29
+ import install from "./tools/install.js";
30
+ import keyboard from "./tools/keyboard.js";
31
+ import mouse from "./tools/mouse.js";
32
+ import navigate from "./tools/navigate.js";
33
+ import network from "./tools/network.js";
34
+ import pdf from "./tools/pdf.js";
35
+ import screenshot from "./tools/screenshot.js";
36
+ import snapshot from "./tools/snapshot.js";
37
+ import tabs from "./tools/tabs.js";
38
+ import wait from "./tools/wait.js";
39
+ var allTools = [
40
+ ...common,
41
+ ...console,
42
+ ...dialogs,
43
+ ...evaluate,
44
+ ...files,
45
+ ...install,
46
+ ...keyboard,
47
+ ...navigate,
48
+ ...network,
49
+ ...mouse,
50
+ ...pdf,
51
+ ...screenshot,
52
+ ...snapshot,
53
+ ...tabs,
54
+ ...wait,
55
+ batchExecuteTool,
56
+ browserFindElements,
57
+ browserDiagnose
58
+ ];
59
+ function filteredTools(config) {
60
+ return allTools.filter((tool) => tool.capability.startsWith("core") || config.capabilities?.includes(tool.capability));
61
+ }
62
+ export {
63
+ filteredTools,
64
+ allTools
65
+ };
@@ -0,0 +1,47 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
+
20
+ // src/types/batch.ts
21
+ import { z } from "zod";
22
+ import { expectationSchema } from "../schemas/expectation.js";
23
+ var parseJsonString = (val) => {
24
+ if (typeof val === "string") {
25
+ try {
26
+ return JSON.parse(val);
27
+ } catch {
28
+ return val;
29
+ }
30
+ }
31
+ return val;
32
+ };
33
+ var batchStepSchema = z.object({
34
+ tool: z.string().describe("Tool name to execute"),
35
+ arguments: z.record(z.unknown()).describe("Arguments for the tool"),
36
+ continueOnError: z.boolean().optional().default(false).describe("Continue batch execution if this step fails"),
37
+ expectation: expectationSchema.describe("Expected output configuration for this step")
38
+ });
39
+ var batchExecuteSchema = z.object({
40
+ steps: z.array(batchStepSchema).min(1).describe("Array of steps to execute in sequence"),
41
+ stopOnFirstError: z.boolean().optional().default(false).describe("Stop entire batch on first error"),
42
+ globalExpectation: z.preprocess(parseJsonString, expectationSchema).optional().describe("Default expectation for all steps")
43
+ });
44
+ export {
45
+ batchStepSchema,
46
+ batchExecuteSchema
47
+ };
File without changes
File without changes
File without changes
@@ -0,0 +1,44 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
+
20
+ // src/utils/array-utils.ts
21
+ function deduplicateAndLimit(items, limit) {
22
+ const unique = [...new Set(items)];
23
+ return limit ? unique.slice(0, limit) : unique;
24
+ }
25
+ function deduplicate(items) {
26
+ return [...new Set(items)];
27
+ }
28
+ function limitItems(items, limit) {
29
+ return limit > 0 ? items.slice(0, limit) : items;
30
+ }
31
+ function filterTruthy(items) {
32
+ return items.filter((item) => Boolean(item));
33
+ }
34
+ function joinFiltered(items, separator = `
35
+ `) {
36
+ return filterTruthy(items).join(separator);
37
+ }
38
+ export {
39
+ limitItems,
40
+ joinFiltered,
41
+ filterTruthy,
42
+ deduplicateAndLimit,
43
+ deduplicate
44
+ };
@@ -0,0 +1,141 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
+
20
+ // src/utils/code-deduplication-utils.ts
21
+ import { formatDiagnosticPair } from "./common-formatters.js";
22
+ var formatDiagnosticKeyValue = formatDiagnosticPair;
23
+ function formatElementCounts(counts) {
24
+ const results = [];
25
+ if (counts.total !== undefined) {
26
+ results.push(formatDiagnosticPair("Total elements", counts.total));
27
+ }
28
+ if (counts.visible !== undefined) {
29
+ results.push(formatDiagnosticPair("Visible elements", counts.visible));
30
+ }
31
+ if (counts.interactable !== undefined) {
32
+ results.push(formatDiagnosticPair("Interactable elements", counts.interactable));
33
+ }
34
+ if (counts.disabled !== undefined) {
35
+ results.push(formatDiagnosticPair("Disabled elements", counts.disabled));
36
+ }
37
+ return results;
38
+ }
39
+ function formatListItems(items, level = 0) {
40
+ const indent = " ".repeat(level);
41
+ return items.map((item) => `${indent}- ${item}`);
42
+ }
43
+
44
+ class ArrayBuilder {
45
+ items = [];
46
+ constructor(initial) {
47
+ if (initial) {
48
+ this.items = [...initial];
49
+ }
50
+ }
51
+ add(item) {
52
+ this.items.push(item);
53
+ return this;
54
+ }
55
+ addAll(items) {
56
+ this.items.push(...items);
57
+ return this;
58
+ }
59
+ addIf(condition, item) {
60
+ const shouldAdd = typeof condition === "function" ? condition() : condition;
61
+ if (shouldAdd) {
62
+ const itemToAdd = typeof item === "function" ? item() : item;
63
+ this.items.push(itemToAdd);
64
+ }
65
+ return this;
66
+ }
67
+ addAllIf(condition, items) {
68
+ const shouldAdd = typeof condition === "function" ? condition() : condition;
69
+ if (shouldAdd) {
70
+ const itemsToAdd = typeof items === "function" ? items() : items;
71
+ this.items.push(...itemsToAdd);
72
+ }
73
+ return this;
74
+ }
75
+ build() {
76
+ return [...this.items];
77
+ }
78
+ getItems() {
79
+ return [...this.items];
80
+ }
81
+ clear() {
82
+ this.items = [];
83
+ return this;
84
+ }
85
+ }
86
+ function joinLines(lines) {
87
+ return lines.join(`
88
+ `);
89
+ }
90
+ function truncateAtWordBoundary(text, maxLength) {
91
+ if (text.length <= maxLength) {
92
+ return text;
93
+ }
94
+ let truncateIndex = maxLength;
95
+ if (text[maxLength] && text[maxLength] !== " " && text[maxLength] !== `
96
+ `) {
97
+ for (let i = maxLength - 1;i >= 0; i--) {
98
+ if (text[i] === " " || text[i] === `
99
+ `) {
100
+ truncateIndex = i;
101
+ break;
102
+ }
103
+ }
104
+ if (maxLength - truncateIndex > 20) {
105
+ truncateIndex = maxLength;
106
+ }
107
+ }
108
+ return text.substring(0, truncateIndex).trim();
109
+ }
110
+ function formatError(error) {
111
+ const result = [`Error: ${error.message}`];
112
+ if (error.suggestions && error.suggestions.length > 0) {
113
+ result.push("", "Suggestions:");
114
+ result.push(...error.suggestions.map((s) => `- ${s}`));
115
+ }
116
+ return result;
117
+ }
118
+ function getStatusIcon(status) {
119
+ switch (status) {
120
+ case "success":
121
+ return "✅";
122
+ case "warning":
123
+ return "⚠️";
124
+ case "error":
125
+ return "\uD83D\uDEA8";
126
+ case "info":
127
+ return "ℹ️";
128
+ default:
129
+ return "⚪";
130
+ }
131
+ }
132
+ export {
133
+ truncateAtWordBoundary,
134
+ joinLines,
135
+ getStatusIcon,
136
+ formatListItems,
137
+ formatError,
138
+ formatElementCounts,
139
+ formatDiagnosticKeyValue,
140
+ ArrayBuilder
141
+ };