@agent-devtools/svelte 0.0.0-beta-20260526084930

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Seungwoo Lee
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # @agent-devtools/svelte
2
+
3
+ Svelte adapter for [agent-devtools](https://github.com/Seungwoo321/agent-devtools). Provides the floating chat widget, DOM picker, and Svelte 4/5 source resolver for Svelte host applications.
4
+
5
+ > Dev-only. The mount entry refuses to run when `NODE_ENV === 'production'`. Bundler integrations (Vite, SvelteKit) further strip imports from production builds — see [`dev-only-guard`](https://github.com/Seungwoo321/agent-devtools/blob/main/.claude/rules/dev-only-guard.md).
6
+
7
+ ## What this adapter provides
8
+
9
+ - **DOM → source bridge** — `element.__svelte_meta.loc.{ file, line, column }`. The Svelte compiler attaches this metadata to every DOM element in dev mode. No tree walk needed; the picked element already carries its source.
10
+ - **Component name** — basename of the `.svelte` file path (`src/Counter.svelte` → `Counter`).
11
+ - **Ancestor chain** — climbs the DOM `parentElement` chain leaf-first and collects distinct `__svelte_meta.loc.file` entries. Capped at depth 10.
12
+ - **Source extraction** — comes for free with the DOM bridge; `file` is workspace-normalised, `line` and `column` are passed through verbatim.
13
+ - **Widget UI** — `@agent-devtools/widget-core` shell. Svelte's reactivity system is never touched.
14
+ - **Reused by** — `@agent-devtools/sveltekit` imports this walker directly.
15
+
16
+ Peer range: `svelte >= 4` (the `__svelte_meta` shape is stable across Svelte 4 and Svelte 5 dev builds).
17
+
18
+ ## Install
19
+
20
+ ```bash
21
+ pnpm add -D @agent-devtools/svelte
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ```ts
27
+ // In a dev-only entry, e.g. src/main.dev.ts gated by import.meta.env.DEV
28
+ import { mountAgentDevtoolsSvelte } from '@agent-devtools/svelte';
29
+ mountAgentDevtoolsSvelte();
30
+ ```
31
+
32
+ The walker reads `element.__svelte_meta.loc.{file,line,column}`, the dev-only metadata that the Svelte compiler attaches to every DOM element. componentName is derived from the basename of the `.svelte` file (e.g. `Counter.svelte` → `Counter`).
33
+
34
+ For SvelteKit hosts, use `@agent-devtools/sveltekit` which registers a dev-only handle hook.
35
+
36
+ ## Status
37
+
38
+ Phase 2 adapter expansion. Walker, picker, widget and bundler integration land incrementally. See the plan tree in Clawket (`PLAN-01KSBW8EMVP50W21DQKVB3G0NG`).
@@ -0,0 +1,84 @@
1
+ import { MountAgentDevtoolsOptions, AgentDevtoolsHandle, BuildSelectorOptions, PickedEvidence } from '@agent-devtools/widget-core';
2
+ export { createAgentInfoFetcher, createDefaultTransport, createHandoffRequester, createPageContextEnricher, createRelatedImportsFetcher, createSettingsStore, createSourceSliceFetcher } from '@agent-devtools/widget-core';
3
+
4
+ interface MountAgentDevtoolsSvelteOptions extends Omit<MountAgentDevtoolsOptions, 'describePicked'> {
5
+ describePicked?: MountAgentDevtoolsOptions['describePicked'];
6
+ }
7
+ declare function mountAgentDevtoolsSvelte(options?: MountAgentDevtoolsSvelteOptions): AgentDevtoolsHandle;
8
+
9
+ interface DescribePickedSvelteOptions {
10
+ selector?: BuildSelectorOptions;
11
+ textLimit?: number;
12
+ outerHTMLLimit?: number;
13
+ componentChainDepth?: number;
14
+ }
15
+ /**
16
+ * Build `PickedEvidence` for a DOM element rendered by Svelte. Uses the
17
+ * compiler-injected `__svelte_meta` to identify the owning `.svelte`
18
+ * file directly — no instance graph needed. When the element is not
19
+ * Svelte-rendered (static HTML or third-party widget), falls back to
20
+ * DOM-only fields.
21
+ */
22
+ declare function describePickedSvelte(element: Element, options?: DescribePickedSvelteOptions): PickedEvidence;
23
+
24
+ interface SvelteSourceLocation {
25
+ fileName: string;
26
+ lineNumber: number;
27
+ columnNumber?: number;
28
+ }
29
+ /**
30
+ * Shape of the `__svelte_meta` property the Svelte compiler attaches to
31
+ * each DOM element in dev mode. Only `loc` is reliably present across
32
+ * Svelte 4 and Svelte 5. `source` and `component` are optional and may
33
+ * vary between major versions.
34
+ */
35
+ interface SvelteElementMeta {
36
+ loc?: {
37
+ file?: string;
38
+ line?: number;
39
+ column?: number;
40
+ };
41
+ source?: string;
42
+ component?: unknown;
43
+ }
44
+ interface SvelteComponentRef {
45
+ componentName: string;
46
+ source?: SvelteSourceLocation;
47
+ }
48
+
49
+ /**
50
+ * Walk DOM ancestors yielding a `SvelteComponentRef` for each level
51
+ * whose `__svelte_meta` resolves to a unique source file. Two sibling
52
+ * elements rendered by the same `.svelte` file share the same `file`
53
+ * path; we deduplicate by file path so a component appears once in
54
+ * the chain.
55
+ */
56
+ declare function walkComponentAncestors(element: Element | null | undefined, options?: {
57
+ readonly maxDepth?: number;
58
+ }): Generator<SvelteComponentRef>;
59
+
60
+ /**
61
+ * Read the Svelte dev-mode metadata that the compiler attaches to every
62
+ * DOM element it created. Returns `null` when the element was not
63
+ * rendered by Svelte (static HTML, third-party widget) or when the host
64
+ * is built in production mode (compiler strips `__svelte_meta`).
65
+ */
66
+ declare function readSvelteMeta(element: Element | null): SvelteElementMeta | null;
67
+
68
+ /**
69
+ * Resolve a `SvelteSourceLocation` from a `__svelte_meta` entry. The
70
+ * file path is normalised to a workspace-relative form when possible
71
+ * (strips Vite's `/@fs/` prefix, decodes `file://` URLs, removes a
72
+ * trailing `?t=<bust>` query string) so the agent can grep for it
73
+ * directly. Returns `undefined` when the meta lacks a file or line.
74
+ */
75
+ declare function resolveSourceFromMeta(meta: SvelteElementMeta | null): SvelteSourceLocation | undefined;
76
+ /**
77
+ * Derive a human-readable component name from a Svelte source path.
78
+ * Strategy: use the file's basename without extension. Falls back to
79
+ * `'Unknown'` when nothing usable is present, mirroring the convention
80
+ * shared by the React and Vue adapters.
81
+ */
82
+ declare function deriveComponentName(file: string | undefined): string;
83
+
84
+ export { type DescribePickedSvelteOptions, type MountAgentDevtoolsSvelteOptions, type SvelteComponentRef, type SvelteElementMeta, type SvelteSourceLocation, deriveComponentName, describePickedSvelte, mountAgentDevtoolsSvelte as mountAgentDevtools, mountAgentDevtoolsSvelte, readSvelteMeta, resolveSourceFromMeta, walkComponentAncestors };
package/dist/index.js ADDED
@@ -0,0 +1,169 @@
1
+ import { buildSelector, mountAgentDevtools } from '@agent-devtools/widget-core';
2
+ export { createAgentInfoFetcher, createDefaultTransport, createHandoffRequester, createPageContextEnricher, createRelatedImportsFetcher, createSettingsStore, createSourceSliceFetcher } from '@agent-devtools/widget-core';
3
+
4
+ // src/orchestrator/mount.ts
5
+
6
+ // src/component/dom-bridge.ts
7
+ function readSvelteMeta(element) {
8
+ if (!element) return null;
9
+ const meta = element.__svelte_meta;
10
+ if (!meta || typeof meta !== "object") return null;
11
+ return meta;
12
+ }
13
+
14
+ // src/component/source.ts
15
+ function resolveSourceFromMeta(meta) {
16
+ if (!meta?.loc) return void 0;
17
+ const { file, line, column } = meta.loc;
18
+ if (typeof file !== "string" || file.length === 0) return void 0;
19
+ if (typeof line !== "number" || !Number.isFinite(line)) return void 0;
20
+ const fileName = normalisePath(file);
21
+ if (typeof column === "number" && Number.isFinite(column)) {
22
+ return { fileName, lineNumber: line, columnNumber: column };
23
+ }
24
+ return { fileName, lineNumber: line };
25
+ }
26
+ function normalisePath(raw) {
27
+ let path = raw;
28
+ if (path.startsWith("file://")) {
29
+ try {
30
+ path = decodeURIComponent(new URL(path).pathname);
31
+ } catch {
32
+ }
33
+ }
34
+ const queryAt = path.indexOf("?");
35
+ if (queryAt >= 0) path = path.slice(0, queryAt);
36
+ if (path.startsWith("/@fs/")) path = path.slice("/@fs".length);
37
+ return path;
38
+ }
39
+ function deriveComponentName(file) {
40
+ if (typeof file !== "string" || file.length === 0) return "Unknown";
41
+ const cleaned = normalisePath(file);
42
+ const lastSlash = cleaned.lastIndexOf("/");
43
+ const base = lastSlash >= 0 ? cleaned.slice(lastSlash + 1) : cleaned;
44
+ const dot = base.lastIndexOf(".");
45
+ const name = dot > 0 ? base.slice(0, dot) : base;
46
+ return name.length > 0 ? name : "Unknown";
47
+ }
48
+
49
+ // src/component/walker.ts
50
+ function* walkComponentAncestors(element, options = {}) {
51
+ const maxDepth = options.maxDepth ?? 10;
52
+ if (!element) return;
53
+ const seenFiles = /* @__PURE__ */ new Set();
54
+ let cursor = element;
55
+ let yielded = 0;
56
+ while (cursor) {
57
+ const meta = readSvelteMeta(cursor);
58
+ const file = meta?.loc?.file;
59
+ if (typeof file === "string" && file.length > 0 && !seenFiles.has(file)) {
60
+ seenFiles.add(file);
61
+ const source = resolveSourceFromMeta(meta);
62
+ const ref = {
63
+ componentName: deriveComponentName(file)
64
+ };
65
+ if (source) ref.source = source;
66
+ yield ref;
67
+ yielded += 1;
68
+ if (yielded >= maxDepth) return;
69
+ }
70
+ cursor = cursor.parentElement;
71
+ }
72
+ }
73
+
74
+ // src/component/picked.ts
75
+ var DEFAULT_TEXT_LIMIT = 120;
76
+ var DEFAULT_OUTER_HTML_LIMIT = 4096;
77
+ var DEFAULT_COMPONENT_CHAIN_DEPTH = 10;
78
+ var TRUNCATION_MARKER = "\u2026[truncated]";
79
+ function describePickedSvelte(element, options = {}) {
80
+ const meta = readSvelteMeta(element);
81
+ const file = meta?.loc?.file;
82
+ const componentName = file ? deriveComponentName(file) : element.tagName.toLowerCase();
83
+ const textLimit = options.textLimit ?? DEFAULT_TEXT_LIMIT;
84
+ const outerHTMLLimit = options.outerHTMLLimit ?? DEFAULT_OUTER_HTML_LIMIT;
85
+ const chainDepth = options.componentChainDepth ?? DEFAULT_COMPONENT_CHAIN_DEPTH;
86
+ const result = {
87
+ componentName,
88
+ tagName: element.tagName,
89
+ selector: buildSelector(element, options.selector ?? {}),
90
+ outerHTML: clampString(element.outerHTML ?? "", outerHTMLLimit),
91
+ attributes: collectAttributes(element),
92
+ componentChain: collectComponentChain(element, chainDepth)
93
+ };
94
+ const source = resolveSourceFromMeta(meta);
95
+ if (source) result.source = source;
96
+ const rect = readBoundingRect(element);
97
+ if (rect) result.boundingRect = rect;
98
+ const text = extractText(element, textLimit);
99
+ if (text !== void 0) result.text = text;
100
+ if (element.id) result.id = element.id;
101
+ const className = readClassName(element);
102
+ if (className !== void 0) result.className = className;
103
+ return result;
104
+ }
105
+ function clampString(raw, max) {
106
+ if (raw.length <= max) return raw;
107
+ return raw.slice(0, max) + TRUNCATION_MARKER;
108
+ }
109
+ function collectAttributes(element) {
110
+ const out = {};
111
+ for (let i = 0; i < element.attributes.length; i += 1) {
112
+ const attr = element.attributes.item(i);
113
+ if (!attr) continue;
114
+ out[attr.name] = attr.value;
115
+ }
116
+ return out;
117
+ }
118
+ function readBoundingRect(element) {
119
+ const fn = element.getBoundingClientRect;
120
+ if (typeof fn !== "function") return void 0;
121
+ let rect;
122
+ try {
123
+ rect = fn.call(element);
124
+ } catch {
125
+ return void 0;
126
+ }
127
+ if (!rect) return void 0;
128
+ return { x: rect.x, y: rect.y, width: rect.width, height: rect.height };
129
+ }
130
+ function extractText(el, limit) {
131
+ const raw = el.textContent;
132
+ if (raw === null || raw === void 0) return void 0;
133
+ const trimmed = raw.replace(/\s+/g, " ").trim();
134
+ if (trimmed.length === 0) return void 0;
135
+ return trimmed.length <= limit ? trimmed : `${trimmed.slice(0, limit)}\u2026`;
136
+ }
137
+ function readClassName(el) {
138
+ const raw = el.className;
139
+ if (typeof raw !== "string") return void 0;
140
+ const trimmed = raw.trim();
141
+ return trimmed.length > 0 ? trimmed : void 0;
142
+ }
143
+ function collectComponentChain(element, maxDepth) {
144
+ const out = [];
145
+ for (const ref of walkComponentAncestors(element, { maxDepth })) {
146
+ const entry = { componentName: ref.componentName };
147
+ if (ref.source) entry.source = ref.source;
148
+ out.push(entry);
149
+ }
150
+ return out;
151
+ }
152
+
153
+ // src/orchestrator/mount.ts
154
+ function mountAgentDevtoolsSvelte(options = {}) {
155
+ const proc = typeof globalThis !== "undefined" ? globalThis.process : void 0;
156
+ if (proc?.env?.NODE_ENV === "production") {
157
+ throw new Error(
158
+ "@agent-devtools/svelte: mountAgentDevtoolsSvelte must not run in production. Ensure the bundler strips this import in production builds."
159
+ );
160
+ }
161
+ return mountAgentDevtools({
162
+ ...options,
163
+ describePicked: options.describePicked ?? describePickedSvelte
164
+ });
165
+ }
166
+
167
+ export { deriveComponentName, describePickedSvelte, mountAgentDevtoolsSvelte as mountAgentDevtools, mountAgentDevtoolsSvelte, readSvelteMeta, resolveSourceFromMeta, walkComponentAncestors };
168
+ //# sourceMappingURL=index.js.map
169
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/component/dom-bridge.ts","../src/component/source.ts","../src/component/walker.ts","../src/component/picked.ts","../src/orchestrator/mount.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { SvelteElementMeta } from './types.js';\n\n/**\n * Read the Svelte dev-mode metadata that the compiler attaches to every\n * DOM element it created. Returns `null` when the element was not\n * rendered by Svelte (static HTML, third-party widget) or when the host\n * is built in production mode (compiler strips `__svelte_meta`).\n */\nexport function readSvelteMeta(element: Element | null): SvelteElementMeta | null {\n if (!element) return null;\n const meta = (element as unknown as { __svelte_meta?: SvelteElementMeta }).__svelte_meta;\n if (!meta || typeof meta !== 'object') return null;\n return meta;\n}\n","import type { SvelteElementMeta, SvelteSourceLocation } from './types.js';\n\n/**\n * Resolve a `SvelteSourceLocation` from a `__svelte_meta` entry. The\n * file path is normalised to a workspace-relative form when possible\n * (strips Vite's `/@fs/` prefix, decodes `file://` URLs, removes a\n * trailing `?t=<bust>` query string) so the agent can grep for it\n * directly. Returns `undefined` when the meta lacks a file or line.\n */\nexport function resolveSourceFromMeta(\n meta: SvelteElementMeta | null,\n): SvelteSourceLocation | undefined {\n if (!meta?.loc) return undefined;\n const { file, line, column } = meta.loc;\n if (typeof file !== 'string' || file.length === 0) return undefined;\n if (typeof line !== 'number' || !Number.isFinite(line)) return undefined;\n const fileName = normalisePath(file);\n if (typeof column === 'number' && Number.isFinite(column)) {\n return { fileName, lineNumber: line, columnNumber: column };\n }\n return { fileName, lineNumber: line };\n}\n\nfunction normalisePath(raw: string): string {\n let path = raw;\n if (path.startsWith('file://')) {\n try {\n path = decodeURIComponent(new URL(path).pathname);\n } catch {\n // fall through\n }\n }\n const queryAt = path.indexOf('?');\n if (queryAt >= 0) path = path.slice(0, queryAt);\n if (path.startsWith('/@fs/')) path = path.slice('/@fs'.length);\n return path;\n}\n\n/**\n * Derive a human-readable component name from a Svelte source path.\n * Strategy: use the file's basename without extension. Falls back to\n * `'Unknown'` when nothing usable is present, mirroring the convention\n * shared by the React and Vue adapters.\n */\nexport function deriveComponentName(file: string | undefined): string {\n if (typeof file !== 'string' || file.length === 0) return 'Unknown';\n const cleaned = normalisePath(file);\n const lastSlash = cleaned.lastIndexOf('/');\n const base = lastSlash >= 0 ? cleaned.slice(lastSlash + 1) : cleaned;\n const dot = base.lastIndexOf('.');\n const name = dot > 0 ? base.slice(0, dot) : base;\n return name.length > 0 ? name : 'Unknown';\n}\n","import { readSvelteMeta } from './dom-bridge.js';\nimport { deriveComponentName, resolveSourceFromMeta } from './source.js';\nimport type { SvelteComponentRef } from './types.js';\n\n/**\n * Walk DOM ancestors yielding a `SvelteComponentRef` for each level\n * whose `__svelte_meta` resolves to a unique source file. Two sibling\n * elements rendered by the same `.svelte` file share the same `file`\n * path; we deduplicate by file path so a component appears once in\n * the chain.\n */\nexport function* walkComponentAncestors(\n element: Element | null | undefined,\n options: { readonly maxDepth?: number } = {},\n): Generator<SvelteComponentRef> {\n const maxDepth = options.maxDepth ?? 10;\n if (!element) return;\n const seenFiles = new Set<string>();\n let cursor: Element | null = element;\n let yielded = 0;\n while (cursor) {\n const meta = readSvelteMeta(cursor);\n const file = meta?.loc?.file;\n if (typeof file === 'string' && file.length > 0 && !seenFiles.has(file)) {\n seenFiles.add(file);\n const source = resolveSourceFromMeta(meta);\n const ref: SvelteComponentRef = {\n componentName: deriveComponentName(file),\n };\n if (source) ref.source = source;\n yield ref;\n yielded += 1;\n if (yielded >= maxDepth) return;\n }\n cursor = cursor.parentElement;\n }\n}\n","import {\n buildSelector,\n type BoundingRect,\n type BuildSelectorOptions,\n type ComponentChainEntry,\n type PickedEvidence,\n} from '@agent-devtools/widget-core';\nimport { readSvelteMeta } from './dom-bridge.js';\nimport { deriveComponentName, resolveSourceFromMeta } from './source.js';\nimport { walkComponentAncestors } from './walker.js';\n\nconst DEFAULT_TEXT_LIMIT = 120;\nconst DEFAULT_OUTER_HTML_LIMIT = 4096;\nconst DEFAULT_COMPONENT_CHAIN_DEPTH = 10;\nconst TRUNCATION_MARKER = '…[truncated]';\n\nexport interface DescribePickedSvelteOptions {\n selector?: BuildSelectorOptions;\n textLimit?: number;\n outerHTMLLimit?: number;\n componentChainDepth?: number;\n}\n\n/**\n * Build `PickedEvidence` for a DOM element rendered by Svelte. Uses the\n * compiler-injected `__svelte_meta` to identify the owning `.svelte`\n * file directly — no instance graph needed. When the element is not\n * Svelte-rendered (static HTML or third-party widget), falls back to\n * DOM-only fields.\n */\nexport function describePickedSvelte(\n element: Element,\n options: DescribePickedSvelteOptions = {},\n): PickedEvidence {\n const meta = readSvelteMeta(element);\n const file = meta?.loc?.file;\n const componentName = file ? deriveComponentName(file) : element.tagName.toLowerCase();\n const textLimit = options.textLimit ?? DEFAULT_TEXT_LIMIT;\n const outerHTMLLimit = options.outerHTMLLimit ?? DEFAULT_OUTER_HTML_LIMIT;\n const chainDepth = options.componentChainDepth ?? DEFAULT_COMPONENT_CHAIN_DEPTH;\n\n const result: PickedEvidence = {\n componentName,\n tagName: element.tagName,\n selector: buildSelector(element, options.selector ?? {}),\n outerHTML: clampString(element.outerHTML ?? '', outerHTMLLimit),\n attributes: collectAttributes(element),\n componentChain: collectComponentChain(element, chainDepth),\n };\n\n const source = resolveSourceFromMeta(meta);\n if (source) result.source = source;\n\n const rect = readBoundingRect(element);\n if (rect) result.boundingRect = rect;\n\n const text = extractText(element, textLimit);\n if (text !== undefined) result.text = text;\n if (element.id) result.id = element.id;\n const className = readClassName(element);\n if (className !== undefined) result.className = className;\n\n return result;\n}\n\nfunction clampString(raw: string, max: number): string {\n if (raw.length <= max) return raw;\n return raw.slice(0, max) + TRUNCATION_MARKER;\n}\n\nfunction collectAttributes(element: Element): Readonly<Record<string, string>> {\n const out: Record<string, string> = {};\n for (let i = 0; i < element.attributes.length; i += 1) {\n const attr = element.attributes.item(i);\n if (!attr) continue;\n out[attr.name] = attr.value;\n }\n return out;\n}\n\nfunction readBoundingRect(element: Element): BoundingRect | undefined {\n const fn = (element as { getBoundingClientRect?: () => DOMRect }).getBoundingClientRect;\n if (typeof fn !== 'function') return undefined;\n let rect: DOMRect;\n try {\n rect = fn.call(element);\n } catch {\n return undefined;\n }\n if (!rect) return undefined;\n return { x: rect.x, y: rect.y, width: rect.width, height: rect.height };\n}\n\nfunction extractText(el: Element, limit: number): string | undefined {\n const raw = el.textContent;\n if (raw === null || raw === undefined) return undefined;\n const trimmed = raw.replace(/\\s+/g, ' ').trim();\n if (trimmed.length === 0) return undefined;\n return trimmed.length <= limit ? trimmed : `${trimmed.slice(0, limit)}…`;\n}\n\nfunction readClassName(el: Element): string | undefined {\n const raw = el.className;\n if (typeof raw !== 'string') return undefined;\n const trimmed = raw.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction collectComponentChain(element: Element, maxDepth: number): readonly ComponentChainEntry[] {\n const out: ComponentChainEntry[] = [];\n for (const ref of walkComponentAncestors(element, { maxDepth })) {\n const entry: ComponentChainEntry = { componentName: ref.componentName };\n if (ref.source) entry.source = ref.source;\n out.push(entry);\n }\n return out;\n}\n","import {\n mountAgentDevtools,\n type AgentDevtoolsHandle,\n type MountAgentDevtoolsOptions,\n} from '@agent-devtools/widget-core';\nimport { describePickedSvelte } from '../component/picked.js';\n\nexport interface MountAgentDevtoolsSvelteOptions extends Omit<\n MountAgentDevtoolsOptions,\n 'describePicked'\n> {\n describePicked?: MountAgentDevtoolsOptions['describePicked'];\n}\n\nexport function mountAgentDevtoolsSvelte(\n options: MountAgentDevtoolsSvelteOptions = {},\n): AgentDevtoolsHandle {\n // Use globalThis.process so tsup's browser-platform build can't statically\n // eliminate the guard via dead-code analysis — the redundant Layer 2 check\n // must survive into dist alongside the @agent-devtools/widget-core guard.\n const proc = typeof globalThis !== 'undefined' ? globalThis.process : undefined;\n if (proc?.env?.NODE_ENV === 'production') {\n throw new Error(\n '@agent-devtools/svelte: mountAgentDevtoolsSvelte must not run in production. ' +\n 'Ensure the bundler strips this import in production builds.',\n );\n }\n return mountAgentDevtools({\n ...options,\n describePicked: options.describePicked ?? describePickedSvelte,\n });\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@agent-devtools/svelte",
3
+ "version": "0.0.0-beta-20260526084930",
4
+ "description": "Svelte adapter for agent-devtools — Svelte 4/5 component walker + DOM picker + closed Shadow DOM widget",
5
+ "keywords": [
6
+ "agent-devtools",
7
+ "devtools",
8
+ "svelte",
9
+ "claude",
10
+ "llm",
11
+ "dev-only"
12
+ ],
13
+ "license": "MIT",
14
+ "author": "Seungwoo Lee <seungwoo321@gmail.com>",
15
+ "homepage": "https://github.com/Seungwoo321/agent-devtools/tree/main/packages/svelte#readme",
16
+ "bugs": {
17
+ "url": "https://github.com/Seungwoo321/agent-devtools/issues"
18
+ },
19
+ "engines": {
20
+ "node": ">=22.13.0"
21
+ },
22
+ "type": "module",
23
+ "main": "./dist/index.js",
24
+ "module": "./dist/index.js",
25
+ "types": "./dist/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "import": "./dist/index.js"
30
+ }
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "README.md"
35
+ ],
36
+ "peerDependencies": {
37
+ "svelte": "^4.0.0 || ^5.0.0"
38
+ },
39
+ "dependencies": {
40
+ "@agent-devtools/core": "0.0.0-beta-20260526084930",
41
+ "@agent-devtools/widget-core": "0.0.0-beta-20260526084930"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^25.7.0",
45
+ "happy-dom": "^20.9.0",
46
+ "tsup": "^8.5.1",
47
+ "vitest": "^4.1.6"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
52
+ "repository": {
53
+ "type": "git",
54
+ "url": "https://github.com/Seungwoo321/agent-devtools.git",
55
+ "directory": "packages/svelte"
56
+ },
57
+ "scripts": {
58
+ "build": "tsup",
59
+ "dev": "tsup --watch",
60
+ "typecheck": "tsc --noEmit",
61
+ "test": "vitest run",
62
+ "test:watch": "vitest",
63
+ "clean": "rm -rf dist"
64
+ }
65
+ }