domagic-turbopack-plugin 1.1.9

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/README.md ADDED
@@ -0,0 +1,106 @@
1
+ # domagic-turbopack-plugin
2
+
3
+ DOMagic 的 Next.js Turbopack 适配包,用于开发环境下给 React JSX/TSX 节点写入 DOMagic 定位信息,并通过独立本地服务处理 AI 样式修改和提交代码相关接口。
4
+
5
+ > Turbopack 不支持 webpack plugin,所以这里不是 `new Plugin()` 形态,而是 `withDOMagicTurbopack()` + `domagic-turbopack-server`。
6
+
7
+ ## 安装
8
+
9
+ ```bash
10
+ npm install -D domagic-turbopack-plugin
11
+ ```
12
+
13
+ ## 配置 Next
14
+
15
+ ```ts
16
+ // next.config.ts
17
+ import { withDOMagicTurbopack } from 'domagic-turbopack-plugin'
18
+
19
+ export default withDOMagicTurbopack(
20
+ {
21
+ // 你的原 Next config
22
+ },
23
+ {
24
+ pathMode: 'relative',
25
+ },
26
+ )
27
+ ```
28
+
29
+ 如果你的 `next.config.js` 还是 CommonJS,可以用动态 import:
30
+
31
+ ```js
32
+ // next.config.js
33
+ module.exports = async () => {
34
+ const { withDOMagicTurbopack } = await import('domagic-turbopack-plugin')
35
+
36
+ return withDOMagicTurbopack(
37
+ {
38
+ // 你的原 Next config
39
+ },
40
+ {
41
+ pathMode: 'relative',
42
+ },
43
+ )
44
+ }
45
+ ```
46
+
47
+ ## 启动
48
+
49
+ 开两个终端:
50
+
51
+ ```bash
52
+ npx domagic-turbopack-server \
53
+ --provider codex \
54
+ --cwd "$PWD" \
55
+ --command "/你的/codex/绝对路径"
56
+ ```
57
+
58
+ ```bash
59
+ npx next dev --turbopack
60
+ ```
61
+
62
+ 默认 DOMagic 服务地址是:
63
+
64
+ ```text
65
+ http://127.0.0.1:32183
66
+ ```
67
+
68
+ 如果你想换端口:
69
+
70
+ ```bash
71
+ npx domagic-turbopack-server --port 42183
72
+ ```
73
+
74
+ 同时在 Next 配置里保持一致:
75
+
76
+ ```ts
77
+ export default withDOMagicTurbopack(
78
+ {},
79
+ {
80
+ server: {
81
+ port: 42183,
82
+ },
83
+ },
84
+ )
85
+ ```
86
+
87
+ ## 支持范围
88
+
89
+ - 支持 Next.js Turbopack 的 `.tsx` / `.jsx` React 文件。
90
+ - 内部复用 DOMagic 核心能力,业务项目只需要安装 `domagic-turbopack-plugin`。
91
+ - 通过 Next rewrites 把 `/__domagic__/*` 转发到本地 DOMagic sidecar 服务。
92
+ - 不支持 Vue 文件。Vue 场景继续用 Vite/Webpack 适配包更合适。
93
+
94
+ ## 注意
95
+
96
+ Turbopack 当前不支持 webpack plugins,也不使用 `HtmlWebpackPlugin`。因此 DOMagic runtime 是通过 loader 注入到开发产物里的,并用全局标记避免重复初始化。
97
+
98
+ 一般不需要在业务代码里手动引入 runtime。如果你确实有自定义注入场景,请从 Turbopack 包自己的入口引入:
99
+
100
+ ```ts
101
+ import { createOverlayRuntimeScript } from 'domagic-turbopack-plugin/runtime'
102
+ ```
103
+
104
+ 不要在 Turbopack 项目里直接引用 `domagic-vite-plugin/runtime`。
105
+
106
+ DOMagic 默认只在开发环境启用,`next build` / `NODE_ENV=production` 时会自动跳过,不会影响线上生产包。
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env node
2
+ import { startDomagicTurbopackServer } from './server.js';
3
+ const port = parseNumberArg('--port') ?? parseNumberEnv('DOMAGIC_TURBOPACK_PORT');
4
+ const host = parseStringArg('--host') ?? process.env.DOMAGIC_TURBOPACK_HOST;
5
+ startDomagicTurbopackServer({
6
+ host,
7
+ port,
8
+ agent: {
9
+ provider: parseProviderArg('--provider') ?? parseProviderEnv('DOMAGIC_AGENT_PROVIDER'),
10
+ command: parseStringArg('--command'),
11
+ cwd: parseStringArg('--cwd'),
12
+ },
13
+ });
14
+ function parseNumberArg(name) {
15
+ const index = process.argv.indexOf(name);
16
+ const value = index >= 0 ? process.argv[index + 1] : undefined;
17
+ if (!value) {
18
+ return;
19
+ }
20
+ const parsed = Number(value);
21
+ return Number.isFinite(parsed) ? parsed : undefined;
22
+ }
23
+ function parseStringArg(name) {
24
+ const index = process.argv.indexOf(name);
25
+ const value = index >= 0 ? process.argv[index + 1] : undefined;
26
+ return value?.trim() || undefined;
27
+ }
28
+ function parseProviderArg(name) {
29
+ return parseProviderValue(parseStringArg(name));
30
+ }
31
+ function parseProviderEnv(name) {
32
+ return parseProviderValue(process.env[name]);
33
+ }
34
+ function parseProviderValue(value) {
35
+ const provider = value?.trim();
36
+ if (provider === 'codex' ||
37
+ provider === 'claude-code' ||
38
+ provider === 'gemini' ||
39
+ provider === 'generic-cli') {
40
+ return provider;
41
+ }
42
+ return undefined;
43
+ }
44
+ function parseNumberEnv(name) {
45
+ const value = process.env[name];
46
+ if (!value) {
47
+ return;
48
+ }
49
+ const parsed = Number(value);
50
+ return Number.isFinite(parsed) ? parsed : undefined;
51
+ }
@@ -0,0 +1,35 @@
1
+ import type { DomagicOptions } from 'domagic-vite-plugin/options';
2
+ export type DOMagicTurbopackOptions = Pick<DomagicOptions, 'pathMode' | 'root'> & {
3
+ enabled?: boolean;
4
+ server?: {
5
+ host?: string;
6
+ port?: number;
7
+ url?: string;
8
+ };
9
+ };
10
+ type Rewrite = {
11
+ source: string;
12
+ destination: string;
13
+ };
14
+ type RewriteConfig = Rewrite[] | {
15
+ beforeFiles?: Rewrite[];
16
+ afterFiles?: Rewrite[];
17
+ fallback?: Rewrite[];
18
+ };
19
+ type NextConfig = {
20
+ turbopack?: {
21
+ rules?: Record<string, unknown>;
22
+ [key: string]: unknown;
23
+ };
24
+ experimental?: {
25
+ [key: string]: unknown;
26
+ };
27
+ compiler?: {
28
+ define?: Record<string, unknown>;
29
+ [key: string]: unknown;
30
+ };
31
+ rewrites?: (...args: unknown[]) => Promise<RewriteConfig> | RewriteConfig;
32
+ [key: string]: unknown;
33
+ };
34
+ export declare function withDOMagicTurbopack<TConfig extends NextConfig>(nextConfig?: TConfig, options?: DOMagicTurbopackOptions): TConfig;
35
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,90 @@
1
+ import { fileURLToPath } from 'node:url';
2
+ const DEFAULT_SERVER_HOST = '127.0.0.1';
3
+ const DEFAULT_SERVER_PORT = 32183;
4
+ export function withDOMagicTurbopack(nextConfig = {}, options = {}) {
5
+ if (options.enabled === false || isProductionBuild()) {
6
+ return nextConfig;
7
+ }
8
+ const root = options.root ?? process.cwd();
9
+ const loader = resolveLoaderPath();
10
+ const loaderOptions = {
11
+ pathMode: options.pathMode,
12
+ root,
13
+ injectRuntime: true,
14
+ };
15
+ const domagicRules = {
16
+ '*.tsx': createRule(loader, loaderOptions),
17
+ '*.jsx': createRule(loader, loaderOptions),
18
+ };
19
+ const previousRewrites = nextConfig.rewrites;
20
+ const domagicRewrite = createDomagicRewrite(options);
21
+ const nextTurbopack = {
22
+ ...(nextConfig.turbopack ?? {}),
23
+ rules: {
24
+ ...(nextConfig.turbopack?.rules ?? {}),
25
+ ...domagicRules,
26
+ },
27
+ };
28
+ return {
29
+ ...nextConfig,
30
+ compiler: normalizeCompilerConfig(nextConfig.compiler),
31
+ turbopack: nextTurbopack,
32
+ async rewrites(...args) {
33
+ const current = previousRewrites ? await previousRewrites(...args) : [];
34
+ return mergeRewrites(current, domagicRewrite);
35
+ },
36
+ };
37
+ }
38
+ function createRule(loader, options) {
39
+ return {
40
+ loaders: [
41
+ {
42
+ loader,
43
+ options,
44
+ },
45
+ ],
46
+ };
47
+ }
48
+ function normalizeCompilerConfig(compiler) {
49
+ if (!compiler?.define) {
50
+ return compiler;
51
+ }
52
+ return {
53
+ ...compiler,
54
+ define: Object.fromEntries(Object.entries(compiler.define).map(([key, value]) => [
55
+ key,
56
+ typeof value === 'string' ? value : JSON.stringify(value),
57
+ ])),
58
+ };
59
+ }
60
+ function createDomagicRewrite(options) {
61
+ return {
62
+ source: '/__domagic__/:path*',
63
+ destination: `${resolveServerUrl(options)}/__domagic__/:path*`,
64
+ };
65
+ }
66
+ function resolveServerUrl(options) {
67
+ if (options.server?.url) {
68
+ return options.server.url.replace(/\/$/, '');
69
+ }
70
+ const host = options.server?.host ?? DEFAULT_SERVER_HOST;
71
+ const port = options.server?.port ?? DEFAULT_SERVER_PORT;
72
+ return `http://${host}:${port}`;
73
+ }
74
+ function mergeRewrites(current, domagicRewrite) {
75
+ if (Array.isArray(current)) {
76
+ return [domagicRewrite, ...current];
77
+ }
78
+ return {
79
+ beforeFiles: [domagicRewrite, ...(current.beforeFiles ?? [])],
80
+ afterFiles: current.afterFiles ?? [],
81
+ fallback: current.fallback ?? [],
82
+ };
83
+ }
84
+ function resolveLoaderPath() {
85
+ return fileURLToPath(new URL('./loader.js', import.meta.url));
86
+ }
87
+ function isProductionBuild() {
88
+ return (process.env.NODE_ENV === 'production' ||
89
+ process.env.NEXT_PHASE === 'phase-production-build');
90
+ }
@@ -0,0 +1,15 @@
1
+ import type { DomagicOptions } from 'domagic-vite-plugin/options';
2
+ type LoaderCallback = (error: Error | null, content?: string, sourceMap?: unknown) => void;
3
+ type LoaderContext = {
4
+ resourcePath: string;
5
+ rootContext?: string;
6
+ async?: () => LoaderCallback;
7
+ callback?: LoaderCallback;
8
+ getOptions?: () => DOMagicTurbopackLoaderOptions;
9
+ };
10
+ export type DOMagicTurbopackLoaderOptions = DomagicOptions & {
11
+ injectRuntime?: boolean;
12
+ };
13
+ export declare function transformTurbopackSource(source: string, resourcePath: string, options?: DOMagicTurbopackLoaderOptions, root?: string): string;
14
+ export default function domagicTurbopackLoader(this: LoaderContext, source: string, sourceMap?: unknown): string | void;
15
+ export {};
package/dist/loader.js ADDED
@@ -0,0 +1,42 @@
1
+ import { formatDomagicFile } from 'domagic-vite-plugin/options';
2
+ import { transformReactSource } from 'domagic-vite-plugin/react-transform';
3
+ import { createOverlayRuntimeScript } from './runtime.js';
4
+ export function transformTurbopackSource(source, resourcePath, options = {}, root = process.cwd()) {
5
+ return transformTurbopackSourceWithMap(source, resourcePath, options, root).code;
6
+ }
7
+ function transformTurbopackSourceWithMap(source, resourcePath, options = {}, root = process.cwd(), sourceMap) {
8
+ const fileValue = formatDomagicFile(resourcePath, options, options.root ?? root);
9
+ const transformed = /\.[jt]sx$/.test(resourcePath)
10
+ ? transformReactSource(source, fileValue)?.code ?? source
11
+ : source;
12
+ const sourceWithRuntime = options.injectRuntime
13
+ ? appendRuntimeGuard(transformed)
14
+ : transformed;
15
+ return {
16
+ code: sourceWithRuntime,
17
+ sourceMap,
18
+ };
19
+ }
20
+ export default function domagicTurbopackLoader(source, sourceMap) {
21
+ const options = this.getOptions?.() ?? {};
22
+ const root = options.root ?? this.rootContext ?? process.cwd();
23
+ const transformed = transformTurbopackSourceWithMap(source, this.resourcePath, options, root, sourceMap);
24
+ const callback = this.async?.() ?? this.callback;
25
+ if (callback) {
26
+ callback(null, transformed.code, transformed.sourceMap);
27
+ return;
28
+ }
29
+ return transformed.code;
30
+ }
31
+ function appendRuntimeGuard(source) {
32
+ return `${source}
33
+
34
+ if (
35
+ typeof window !== 'undefined' &&
36
+ !window.__DOMAGIC_TURBOPACK_RUNTIME_INSTALLED__
37
+ ) {
38
+ window.__DOMAGIC_TURBOPACK_RUNTIME_INSTALLED__ = true;
39
+ ${createOverlayRuntimeScript()}
40
+ }
41
+ `;
42
+ }
@@ -0,0 +1,4 @@
1
+ export { DOMAGIC_EDIT_ENDPOINT, DOMAGIC_EDIT_STATUS_ENDPOINT, DOMAGIC_GIT_COMMIT_MESSAGE_ENDPOINT, DOMAGIC_GIT_COMMIT_PUSH_ENDPOINT, DOMAGIC_GIT_STATUS_ENDPOINT, DOMAGIC_REVIEW_ENDPOINT, DOMAGIC_REVIEW_STATUS_ENDPOINT, DOMAGIC_RUNTIME_SESSION_ENDPOINT, computeOverlayPosition, getTaskPollDelay, } from 'domagic-vite-plugin/runtime';
2
+ import { type OverlayRuntimeOptions } from 'domagic-vite-plugin/runtime';
3
+ export type { OverlayRuntimeOptions } from 'domagic-vite-plugin/runtime';
4
+ export declare function createOverlayRuntimeScript(options?: OverlayRuntimeOptions): string;
@@ -0,0 +1,8 @@
1
+ export { DOMAGIC_EDIT_ENDPOINT, DOMAGIC_EDIT_STATUS_ENDPOINT, DOMAGIC_GIT_COMMIT_MESSAGE_ENDPOINT, DOMAGIC_GIT_COMMIT_PUSH_ENDPOINT, DOMAGIC_GIT_STATUS_ENDPOINT, DOMAGIC_REVIEW_ENDPOINT, DOMAGIC_REVIEW_STATUS_ENDPOINT, DOMAGIC_RUNTIME_SESSION_ENDPOINT, computeOverlayPosition, getTaskPollDelay, } from 'domagic-vite-plugin/runtime';
2
+ import { createOverlayRuntimeScript as createBaseOverlayRuntimeScript, } from 'domagic-vite-plugin/runtime';
3
+ export function createOverlayRuntimeScript(options = {}) {
4
+ return createBaseOverlayRuntimeScript({
5
+ reloadAfterStyleEdit: true,
6
+ ...options,
7
+ });
8
+ }
@@ -0,0 +1,13 @@
1
+ import { createServer, type IncomingMessage, type ServerResponse } from 'node:http';
2
+ import type { DomagicAgentOptions } from 'domagic-vite-plugin/options';
3
+ export type DOMagicTurbopackServerOptions = {
4
+ host?: string;
5
+ port?: number;
6
+ agent?: DomagicAgentOptions;
7
+ root?: string;
8
+ };
9
+ type ConnectNext = () => void;
10
+ type ConnectMiddleware = (req: IncomingMessage, res: ServerResponse, next: ConnectNext) => void | Promise<void>;
11
+ export declare function createDomagicTurbopackMiddleware(agentOptions?: DomagicAgentOptions, projectRoot?: string): ConnectMiddleware;
12
+ export declare function startDomagicTurbopackServer(options?: DOMagicTurbopackServerOptions): ReturnType<typeof createServer>;
13
+ export {};
package/dist/server.js ADDED
@@ -0,0 +1,45 @@
1
+ import { createServer } from 'node:http';
2
+ import { installStyleEditMiddlewareWithOptions } from 'domagic-vite-plugin/server';
3
+ const DEFAULT_HOST = '127.0.0.1';
4
+ const DEFAULT_PORT = 32183;
5
+ export function createDomagicTurbopackMiddleware(agentOptions, projectRoot) {
6
+ const serverLike = {
7
+ middlewares: {
8
+ handlers: [],
9
+ use(handler) {
10
+ this.handlers.push(handler);
11
+ },
12
+ },
13
+ };
14
+ installStyleEditMiddlewareWithOptions(serverLike, agentOptions, projectRoot);
15
+ return withCors(serverLike.middlewares.handlers[0]);
16
+ }
17
+ export function startDomagicTurbopackServer(options = {}) {
18
+ const host = options.host ?? DEFAULT_HOST;
19
+ const port = options.port ?? DEFAULT_PORT;
20
+ const middleware = createDomagicTurbopackMiddleware(options.agent, options.root ?? options.agent?.cwd);
21
+ const server = createServer((req, res) => {
22
+ void middleware(req, res, () => {
23
+ res.statusCode = 404;
24
+ res.setHeader('Content-Type', 'application/json');
25
+ res.end(JSON.stringify({ ok: false, error: 'DOMagic endpoint not found' }));
26
+ });
27
+ });
28
+ server.listen(port, host, () => {
29
+ console.log(`[domagic] Turbopack server listening on http://${host}:${port}`);
30
+ });
31
+ return server;
32
+ }
33
+ function withCors(middleware) {
34
+ return (req, res, next) => {
35
+ res.setHeader('Access-Control-Allow-Origin', '*');
36
+ res.setHeader('Access-Control-Allow-Methods', 'GET,POST,OPTIONS');
37
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
38
+ if (req.method === 'OPTIONS') {
39
+ res.statusCode = 204;
40
+ res.end();
41
+ return;
42
+ }
43
+ return middleware(req, res, next);
44
+ };
45
+ }
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "domagic-turbopack-plugin",
3
+ "version": "1.1.9",
4
+ "description": "A development-only Turbopack adapter for DOM source mapping and AI-assisted style edits.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ },
14
+ "./loader": {
15
+ "types": "./dist/loader.d.ts",
16
+ "import": "./dist/loader.js"
17
+ },
18
+ "./server": {
19
+ "types": "./dist/server.d.ts",
20
+ "import": "./dist/server.js"
21
+ },
22
+ "./runtime": {
23
+ "types": "./dist/runtime.d.ts",
24
+ "import": "./dist/runtime.js"
25
+ }
26
+ },
27
+ "bin": {
28
+ "domagic-turbopack-server": "dist/cli.js"
29
+ },
30
+ "files": [
31
+ "dist"
32
+ ],
33
+ "sideEffects": false,
34
+ "keywords": [
35
+ "turbopack",
36
+ "nextjs",
37
+ "dom",
38
+ "react",
39
+ "ai"
40
+ ],
41
+ "license": "UNLICENSED",
42
+ "publishConfig": {
43
+ "registry": "https://registry.npmjs.org/"
44
+ },
45
+ "scripts": {
46
+ "build": "tsc -p tsconfig.json",
47
+ "prepublishOnly": "npm run build && npm test",
48
+ "test": "vitest run --config vitest.config.ts"
49
+ },
50
+ "dependencies": {
51
+ "domagic-vite-plugin": "1.1.9",
52
+ "typescript": "^5.9.3"
53
+ },
54
+ "peerDependencies": {
55
+ "next": ">=15.3.0"
56
+ },
57
+ "devDependencies": {
58
+ "@types/node": "^24.12.0",
59
+ "typescript": "^5.9.3",
60
+ "vitest": "^3.2.4"
61
+ }
62
+ }