@lijinmei-810/dev-inspector-vite 0.1.0

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/dist/index.cjs ADDED
@@ -0,0 +1,415 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ createDevHandoffPlugin: () => createDevHandoffPlugin,
34
+ createDevInspectorServerPlugin: () => createDevInspectorServerPlugin
35
+ });
36
+ module.exports = __toCommonJS(index_exports);
37
+ var import_node_fs = __toESM(require("fs"), 1);
38
+ var import_node_path = __toESM(require("path"), 1);
39
+ var import_node_child_process = require("child_process");
40
+ var import_node_os = __toESM(require("os"), 1);
41
+ function getStyleIntentMergeKey(entry) {
42
+ return [
43
+ entry.panelKind ?? "",
44
+ entry.scopeLabel ?? "",
45
+ entry.selector ?? "",
46
+ entry.targetLabel ?? ""
47
+ ].join("||");
48
+ }
49
+ function mergeEntryGroups(primary, secondary) {
50
+ const groupMap = /* @__PURE__ */ new Map();
51
+ const appendGroups = (groups) => {
52
+ groups.forEach((group) => {
53
+ const selector = group.selector;
54
+ if (!selector) return;
55
+ if (!groupMap.has(selector)) {
56
+ groupMap.set(selector, { selector, changes: [] });
57
+ }
58
+ const targetGroup = groupMap.get(selector);
59
+ group.changes.forEach((change) => {
60
+ if (!change.prop || !change.val) return;
61
+ if (!targetGroup.changes.some((item) => item.prop === change.prop)) {
62
+ targetGroup.changes.push(change);
63
+ }
64
+ });
65
+ });
66
+ };
67
+ appendGroups(primary);
68
+ appendGroups(secondary);
69
+ return Array.from(groupMap.values()).filter((group) => group.changes.length > 0);
70
+ }
71
+ function compactStyleIntentEntries(entries) {
72
+ const merged = [];
73
+ const pendingIndexByKey = /* @__PURE__ */ new Map();
74
+ entries.forEach((entry) => {
75
+ if (entry.status !== "pending") {
76
+ merged.push(entry);
77
+ return;
78
+ }
79
+ const mergeKey = getStyleIntentMergeKey(entry);
80
+ const existingIndex = pendingIndexByKey.get(mergeKey);
81
+ if (existingIndex === void 0) {
82
+ pendingIndexByKey.set(mergeKey, merged.length);
83
+ merged.push({
84
+ ...entry,
85
+ entries: mergeEntryGroups(entry.entries, [])
86
+ });
87
+ return;
88
+ }
89
+ const existing = merged[existingIndex];
90
+ merged[existingIndex] = {
91
+ ...existing,
92
+ note: existing.note || entry.note,
93
+ entries: mergeEntryGroups(existing.entries, entry.entries)
94
+ };
95
+ });
96
+ return merged;
97
+ }
98
+ function normalizeAndCompactStore(store) {
99
+ const normalized = normalizeStyleIntentStore(store);
100
+ return {
101
+ entries: compactStyleIntentEntries(normalized.entries)
102
+ };
103
+ }
104
+ function normalizeStyleIntentStore(store) {
105
+ return {
106
+ entries: (store.entries || []).map((entry) => ({
107
+ ...entry,
108
+ entries: (entry.entries || []).map((group) => ({
109
+ ...group,
110
+ changes: (group.changes || []).filter((change) => change.prop && change.val)
111
+ })).filter((group) => group.selector && group.changes.length > 0)
112
+ }))
113
+ };
114
+ }
115
+ function buildCssBlock(entries) {
116
+ return entries.map(({ selector, changes, note }) => {
117
+ const lines = changes.map((c) => ` ${c.prop}: ${c.val};`);
118
+ return [
119
+ `
120
+ /* DevInspector: ${(/* @__PURE__ */ new Date()).toLocaleString("zh-CN")} */`,
121
+ note ? `/* ${note} */` : "",
122
+ `${selector} {`,
123
+ ...lines,
124
+ "}"
125
+ ].filter(Boolean).join("\n");
126
+ }).join("\n") + "\n";
127
+ }
128
+ function createDevInspectorServerPlugin(options) {
129
+ const projectRoot = options.projectRoot;
130
+ const cssFile = options.cssFile ?? import_node_path.default.resolve(projectRoot, "src/styles/index.css");
131
+ const styleInboxJsonFile = options.styleInboxJsonFile ?? import_node_path.default.resolve(projectRoot, "docs/style-inbox.json");
132
+ const styleInboxMarkdownFile = options.styleInboxMarkdownFile ?? import_node_path.default.resolve(projectRoot, "docs/STYLE_INBOX.md");
133
+ const commitTargetFile = options.commitTargetFile ?? "src/styles/dev-overrides.css";
134
+ function ensureStyleInboxStore() {
135
+ if (!import_node_fs.default.existsSync(styleInboxJsonFile)) {
136
+ import_node_fs.default.writeFileSync(styleInboxJsonFile, JSON.stringify({ entries: [] }, null, 2));
137
+ }
138
+ }
139
+ function readStyleInboxStore() {
140
+ ensureStyleInboxStore();
141
+ const raw = JSON.parse(import_node_fs.default.readFileSync(styleInboxJsonFile, "utf-8"));
142
+ const normalized = normalizeStyleIntentStore(raw);
143
+ const compacted = normalizeAndCompactStore(raw);
144
+ if (JSON.stringify(normalized) !== JSON.stringify(compacted)) {
145
+ import_node_fs.default.writeFileSync(styleInboxJsonFile, JSON.stringify(compacted, null, 2));
146
+ }
147
+ return compacted;
148
+ }
149
+ function writeStyleInboxStore(data) {
150
+ import_node_fs.default.writeFileSync(styleInboxJsonFile, JSON.stringify(normalizeAndCompactStore(data), null, 2));
151
+ }
152
+ function appendStyleInbox(payload) {
153
+ if (!import_node_fs.default.existsSync(styleInboxMarkdownFile)) {
154
+ import_node_fs.default.writeFileSync(
155
+ styleInboxMarkdownFile,
156
+ "# Style Inbox\n\n> \u7528\u6237\u901A\u8FC7 DevInspector \u63D0\u4EA4\u7ED9 AI \u52A9\u624B\u7684\u6837\u5F0F\u610F\u56FE\u6536\u96C6\u5904\u3002\n> \u8FD9\u91CC\u8BB0\u5F55\u7684\u662F\u201C\u5F85\u56FA\u5316\u201D\u7684\u8BBE\u8BA1\u6539\u52A8\uFF0C\u4E0D\u7B49\u4E8E\u5DF2\u7ECF\u5B8C\u6210\u6B63\u5F0F\u4EE3\u7801\u6536\u655B\u3002\n\n"
157
+ );
158
+ }
159
+ const store = readStyleInboxStore();
160
+ const newEntry = {
161
+ id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
162
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
163
+ status: "pending",
164
+ pageUrl: payload.pageUrl,
165
+ panelKind: payload.panelKind,
166
+ scopeLabel: payload.scopeLabel,
167
+ selector: payload.selector,
168
+ targetLabel: payload.targetLabel,
169
+ note: payload.note,
170
+ entries: payload.entries
171
+ };
172
+ store.entries.unshift(newEntry);
173
+ writeStyleInboxStore(store);
174
+ const mergedStore = readStyleInboxStore();
175
+ const mergeKey = getStyleIntentMergeKey(newEntry);
176
+ const entry = mergedStore.entries.find((item) => item.status === "pending" && getStyleIntentMergeKey(item) === mergeKey) ?? newEntry;
177
+ const cssBlocks = payload.entries.map(({ selector, changes }) => {
178
+ const lines2 = changes.map(({ prop, val }) => ` ${prop}: ${val};`);
179
+ return `${selector} {
180
+ ${lines2.join("\n")}
181
+ }`;
182
+ }).join("\n\n");
183
+ const lines = [
184
+ `
185
+ ## ${(/* @__PURE__ */ new Date()).toLocaleString("zh-CN")}`,
186
+ "- \u72B6\u6001\uFF1A\u5F85 AI \u56FA\u5316",
187
+ payload.pageUrl ? `- \u9875\u9762\uFF1A${payload.pageUrl}` : "",
188
+ payload.panelKind ? `- \u9762\u677F\uFF1A${payload.panelKind}` : "",
189
+ payload.scopeLabel ? `- \u4F5C\u7528\u8303\u56F4\uFF1A${payload.scopeLabel}` : "",
190
+ payload.targetLabel ? `- \u76EE\u6807\uFF1A${payload.targetLabel}` : "",
191
+ payload.selector ? `- \u9009\u62E9\u5668\uFF1A\`${payload.selector}\`` : "",
192
+ payload.note ? `- \u5907\u6CE8\uFF1A${payload.note}` : "",
193
+ "",
194
+ "```css",
195
+ cssBlocks,
196
+ "```",
197
+ ""
198
+ ].filter(Boolean);
199
+ import_node_fs.default.appendFileSync(styleInboxMarkdownFile, lines.join("\n"));
200
+ return entry;
201
+ }
202
+ function getStyleIntentSummary() {
203
+ const store = readStyleInboxStore();
204
+ const pending = store.entries.filter((entry) => entry.status === "pending");
205
+ return {
206
+ pendingCount: pending.length,
207
+ latestPending: pending[0] ?? null,
208
+ pendingEntries: pending
209
+ };
210
+ }
211
+ function deleteStyleIntent(payload) {
212
+ const store = readStyleInboxStore();
213
+ let changed = false;
214
+ const nextEntries = store.entries.map((entry) => {
215
+ if (entry.id !== payload.id) return entry;
216
+ changed = true;
217
+ if (!payload.selector || !payload.prop) {
218
+ return { ...entry, status: "resolved" };
219
+ }
220
+ const nextGroups = entry.entries.map((group) => {
221
+ if (group.selector !== payload.selector) return group;
222
+ return {
223
+ ...group,
224
+ changes: group.changes.filter((change) => change.prop !== payload.prop)
225
+ };
226
+ }).filter((group) => group.changes.length > 0);
227
+ if (nextGroups.length === 0) {
228
+ return { ...entry, status: "resolved", entries: [] };
229
+ }
230
+ return { ...entry, entries: nextGroups };
231
+ });
232
+ if (!changed) return { ok: false, error: "NOT_FOUND" };
233
+ writeStyleInboxStore({ entries: nextEntries });
234
+ return { ok: true, ...getStyleIntentSummary() };
235
+ }
236
+ return {
237
+ name: "dev-inspector-server",
238
+ configureServer(server) {
239
+ server.middlewares.use("/__dev/apply-css", (req, res) => {
240
+ if (req.method !== "POST") {
241
+ res.statusCode = 405;
242
+ res.end();
243
+ return;
244
+ }
245
+ let body = "";
246
+ req.on("data", (c) => body += c);
247
+ req.on("end", () => {
248
+ try {
249
+ const payload = JSON.parse(body);
250
+ const entries = Array.isArray(payload.entries) ? payload.entries : [{ selector: payload.selector, changes: payload.changes, note: payload.note }];
251
+ const block = buildCssBlock(entries);
252
+ import_node_fs.default.appendFileSync(cssFile, block);
253
+ try {
254
+ const firstEntry = entries[0];
255
+ const msg = firstEntry?.note ? `style(DevInspector): ${firstEntry.selector} \u2014 ${firstEntry.note}` : `style(DevInspector): ${firstEntry?.selector ?? "multi-selectors"}`;
256
+ (0, import_node_child_process.execSync)(`cd "${projectRoot}" && git add ${commitTargetFile} && git commit -m ${JSON.stringify(msg)} --allow-empty`, { stdio: "pipe" });
257
+ } catch {
258
+ }
259
+ res.setHeader("Content-Type", "application/json");
260
+ res.end(JSON.stringify({ ok: true }));
261
+ } catch (e) {
262
+ res.statusCode = 500;
263
+ res.end(JSON.stringify({ ok: false, error: String(e) }));
264
+ }
265
+ });
266
+ });
267
+ server.middlewares.use("/__dev/submit-style-intent", (req, res) => {
268
+ if (req.method !== "POST") {
269
+ res.statusCode = 405;
270
+ res.end();
271
+ return;
272
+ }
273
+ let body = "";
274
+ req.on("data", (c) => body += c);
275
+ req.on("end", () => {
276
+ try {
277
+ const payload = JSON.parse(body);
278
+ const entry = appendStyleInbox(payload);
279
+ res.setHeader("Content-Type", "application/json");
280
+ res.end(JSON.stringify({ ok: true, entry, ...getStyleIntentSummary() }));
281
+ } catch (e) {
282
+ res.statusCode = 500;
283
+ res.setHeader("Content-Type", "application/json");
284
+ res.end(JSON.stringify({ ok: false, error: String(e) }));
285
+ }
286
+ });
287
+ });
288
+ server.middlewares.use("/__dev/style-intents/delete", (req, res) => {
289
+ if (req.method !== "POST") {
290
+ res.statusCode = 405;
291
+ res.end();
292
+ return;
293
+ }
294
+ let body = "";
295
+ req.on("data", (c) => body += c);
296
+ req.on("end", () => {
297
+ try {
298
+ const payload = JSON.parse(body);
299
+ const result = deleteStyleIntent(payload);
300
+ res.setHeader("Content-Type", "application/json");
301
+ res.end(JSON.stringify(result));
302
+ } catch (e) {
303
+ res.statusCode = 500;
304
+ res.setHeader("Content-Type", "application/json");
305
+ res.end(JSON.stringify({ ok: false, error: String(e) }));
306
+ }
307
+ });
308
+ });
309
+ server.middlewares.use("/__dev/style-intents", (req, res) => {
310
+ if (req.method !== "GET") {
311
+ res.statusCode = 405;
312
+ res.end();
313
+ return;
314
+ }
315
+ try {
316
+ res.setHeader("Content-Type", "application/json");
317
+ res.end(JSON.stringify({ ok: true, ...getStyleIntentSummary() }));
318
+ } catch (e) {
319
+ res.statusCode = 500;
320
+ res.setHeader("Content-Type", "application/json");
321
+ res.end(JSON.stringify({ ok: false, error: String(e) }));
322
+ }
323
+ });
324
+ }
325
+ };
326
+ }
327
+ function createDevHandoffPlugin(projectRoot) {
328
+ return {
329
+ name: "dev-handoff",
330
+ configureServer(server) {
331
+ server.middlewares.use("/__dev/handoff", (req, res) => {
332
+ const url = new URL(req.url, "http://localhost");
333
+ const includeCode = url.searchParams.get("code") !== "0";
334
+ const includeProduct = url.searchParams.get("product") !== "0";
335
+ const includeDesign = url.searchParams.get("design") !== "0";
336
+ const projectName = import_node_path.default.basename(projectRoot);
337
+ const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10).replace(/-/g, "");
338
+ const copyDir = import_node_fs.default.mkdtempSync(import_node_path.default.join(import_node_os.default.tmpdir(), "handoff-"));
339
+ try {
340
+ const excludes = [
341
+ "node_modules/",
342
+ "dist/",
343
+ ".git/",
344
+ ".DS_Store",
345
+ "src/dev/",
346
+ "CLAUDE.md",
347
+ "AGENTS.md",
348
+ "*_TEMPLATE.md",
349
+ "*_PROMPT.md",
350
+ "README.md",
351
+ "docs/MEMORY_RULES.md",
352
+ "docs/USER_CONTEXT.md",
353
+ "docs/HANDOFF.md",
354
+ "docs/LESSONS.md"
355
+ ];
356
+ if (!includeCode) excludes.push("src/");
357
+ if (!includeDesign) excludes.push("docs/design/");
358
+ if (!includeProduct && !includeDesign) {
359
+ excludes.push("docs/");
360
+ } else if (!includeProduct) {
361
+ [
362
+ "CHANGELOG.md",
363
+ "CODE_STRUCTURE.md",
364
+ "DECISIONS.md",
365
+ "DESIGN_STANDARDS.md",
366
+ "PRODUCT_PLAN.md",
367
+ "PROJECT.md"
368
+ ].forEach((file) => excludes.push(`docs/${file}`));
369
+ }
370
+ const flags = excludes.map((exclude) => `--exclude='${exclude}'`).join(" ");
371
+ (0, import_node_child_process.execSync)(`rsync -a ${flags} "${projectRoot}/" "${copyDir}/"`);
372
+ if (includeCode) {
373
+ const mainTsx = import_node_path.default.join(copyDir, "src", "main.tsx");
374
+ const stripScript = import_node_path.default.join(import_node_os.default.homedir(), ".claude/skills/handoff/scripts/strip_dev_block.py");
375
+ if (import_node_fs.default.existsSync(mainTsx) && import_node_fs.default.existsSync(stripScript)) {
376
+ (0, import_node_child_process.execSync)(`python3 "${stripScript}" "${mainTsx}"`);
377
+ }
378
+ }
379
+ const desktop = import_node_path.default.join(import_node_os.default.homedir(), "Desktop");
380
+ const filename = `${projectName}_handoff_${date}.zip`;
381
+ const destZip = import_node_path.default.join(desktop, filename);
382
+ (0, import_node_child_process.execSync)(`cd "${copyDir}" && zip -r "${destZip}" . -x "*.DS_Store"`, { stdio: "pipe" });
383
+ res.setHeader("Content-Type", "application/json");
384
+ res.end(JSON.stringify({ ok: true, path: destZip }));
385
+ } catch (e) {
386
+ res.statusCode = 500;
387
+ res.setHeader("Content-Type", "application/json");
388
+ res.end(JSON.stringify({ ok: false, error: String(e) }));
389
+ } finally {
390
+ try {
391
+ (0, import_node_child_process.execSync)(`rm -rf "${copyDir}"`);
392
+ } catch {
393
+ }
394
+ }
395
+ });
396
+ server.middlewares.use("/__dev/reveal", (req, res) => {
397
+ const url = new URL(req.url, "http://localhost");
398
+ const filePath = url.searchParams.get("path") ?? "";
399
+ try {
400
+ (0, import_node_child_process.execSync)(`open -R "${filePath}"`);
401
+ res.end("ok");
402
+ } catch {
403
+ res.statusCode = 500;
404
+ res.end("error");
405
+ }
406
+ });
407
+ }
408
+ };
409
+ }
410
+ // Annotate the CommonJS export names for ESM import in node:
411
+ 0 && (module.exports = {
412
+ createDevHandoffPlugin,
413
+ createDevInspectorServerPlugin
414
+ });
415
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { execSync } from 'node:child_process';\nimport os from 'node:os';\n\ntype StyleIntentEntry = {\n id: string;\n createdAt: string;\n status: 'pending' | 'resolved';\n pageUrl?: string;\n panelKind?: string;\n scopeLabel?: string;\n selector?: string;\n targetLabel?: string;\n note?: string;\n entries: { selector: string; changes: { prop: string; val: string; from?: string }[] }[];\n};\n\ntype DevInspectorServerOptions = {\n projectRoot: string;\n cssFile?: string;\n styleInboxJsonFile?: string;\n styleInboxMarkdownFile?: string;\n commitTargetFile?: string;\n};\n\nfunction getStyleIntentMergeKey(entry: StyleIntentEntry) {\n return [\n entry.panelKind ?? '',\n entry.scopeLabel ?? '',\n entry.selector ?? '',\n entry.targetLabel ?? '',\n ].join('||');\n}\n\nfunction mergeEntryGroups(\n primary: StyleIntentEntry['entries'],\n secondary: StyleIntentEntry['entries'],\n) {\n const groupMap = new Map<string, { selector: string; changes: { prop: string; val: string; from?: string }[] }>();\n\n const appendGroups = (groups: StyleIntentEntry['entries']) => {\n groups.forEach((group) => {\n const selector = group.selector;\n if (!selector) return;\n if (!groupMap.has(selector)) {\n groupMap.set(selector, { selector, changes: [] });\n }\n const targetGroup = groupMap.get(selector)!;\n group.changes.forEach((change) => {\n if (!change.prop || !change.val) return;\n if (!targetGroup.changes.some((item) => item.prop === change.prop)) {\n targetGroup.changes.push(change);\n }\n });\n });\n };\n\n appendGroups(primary);\n appendGroups(secondary);\n\n return Array.from(groupMap.values()).filter((group) => group.changes.length > 0);\n}\n\nfunction compactStyleIntentEntries(entries: StyleIntentEntry[]) {\n const merged: StyleIntentEntry[] = [];\n const pendingIndexByKey = new Map<string, number>();\n\n entries.forEach((entry) => {\n if (entry.status !== 'pending') {\n merged.push(entry);\n return;\n }\n\n const mergeKey = getStyleIntentMergeKey(entry);\n const existingIndex = pendingIndexByKey.get(mergeKey);\n if (existingIndex === undefined) {\n pendingIndexByKey.set(mergeKey, merged.length);\n merged.push({\n ...entry,\n entries: mergeEntryGroups(entry.entries, []),\n });\n return;\n }\n\n const existing = merged[existingIndex];\n merged[existingIndex] = {\n ...existing,\n note: existing.note || entry.note,\n entries: mergeEntryGroups(existing.entries, entry.entries),\n };\n });\n\n return merged;\n}\n\nfunction normalizeAndCompactStore(store: { entries: StyleIntentEntry[] }) {\n const normalized = normalizeStyleIntentStore(store);\n return {\n entries: compactStyleIntentEntries(normalized.entries),\n };\n}\n\nfunction normalizeStyleIntentStore(store: { entries: StyleIntentEntry[] }) {\n return {\n entries: (store.entries || []).map((entry) => ({\n ...entry,\n entries: (entry.entries || [])\n .map((group) => ({\n ...group,\n changes: (group.changes || []).filter((change) => change.prop && change.val),\n }))\n .filter((group) => group.selector && group.changes.length > 0),\n })),\n };\n}\n\nfunction buildCssBlock(entries: { selector: string; changes: { prop: string; val: string }[]; note?: string }[]) {\n return entries.map(({ selector, changes, note }) => {\n const lines = changes.map((c) => ` ${c.prop}: ${c.val};`);\n return [\n `\\n/* DevInspector: ${new Date().toLocaleString('zh-CN')} */`,\n note ? `/* ${note} */` : '',\n `${selector} {`,\n ...lines,\n '}',\n ].filter(Boolean).join('\\n');\n }).join('\\n') + '\\n';\n}\n\nexport function createDevInspectorServerPlugin(options: DevInspectorServerOptions) {\n const projectRoot = options.projectRoot;\n const cssFile = options.cssFile ?? path.resolve(projectRoot, 'src/styles/index.css');\n const styleInboxJsonFile = options.styleInboxJsonFile ?? path.resolve(projectRoot, 'docs/style-inbox.json');\n const styleInboxMarkdownFile = options.styleInboxMarkdownFile ?? path.resolve(projectRoot, 'docs/STYLE_INBOX.md');\n const commitTargetFile = options.commitTargetFile ?? 'src/styles/dev-overrides.css';\n\n function ensureStyleInboxStore() {\n if (!fs.existsSync(styleInboxJsonFile)) {\n fs.writeFileSync(styleInboxJsonFile, JSON.stringify({ entries: [] }, null, 2));\n }\n }\n\n function readStyleInboxStore(): { entries: StyleIntentEntry[] } {\n ensureStyleInboxStore();\n const raw = JSON.parse(fs.readFileSync(styleInboxJsonFile, 'utf-8'));\n const normalized = normalizeStyleIntentStore(raw);\n const compacted = normalizeAndCompactStore(raw);\n if (JSON.stringify(normalized) !== JSON.stringify(compacted)) {\n fs.writeFileSync(styleInboxJsonFile, JSON.stringify(compacted, null, 2));\n }\n return compacted;\n }\n\n function writeStyleInboxStore(data: { entries: StyleIntentEntry[] }) {\n fs.writeFileSync(styleInboxJsonFile, JSON.stringify(normalizeAndCompactStore(data), null, 2));\n }\n\n function appendStyleInbox(payload: {\n pageUrl?: string;\n panelKind?: string;\n scopeLabel?: string;\n selector?: string;\n targetLabel?: string;\n note?: string;\n entries: { selector: string; changes: { prop: string; val: string; from?: string }[] }[];\n }): StyleIntentEntry {\n if (!fs.existsSync(styleInboxMarkdownFile)) {\n fs.writeFileSync(\n styleInboxMarkdownFile,\n '# Style Inbox\\n\\n> 用户通过 DevInspector 提交给 AI 助手的样式意图收集处。\\n> 这里记录的是“待固化”的设计改动,不等于已经完成正式代码收敛。\\n\\n',\n );\n }\n\n const store = readStyleInboxStore();\n const newEntry: StyleIntentEntry = {\n id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n createdAt: new Date().toISOString(),\n status: 'pending',\n pageUrl: payload.pageUrl,\n panelKind: payload.panelKind,\n scopeLabel: payload.scopeLabel,\n selector: payload.selector,\n targetLabel: payload.targetLabel,\n note: payload.note,\n entries: payload.entries,\n };\n store.entries.unshift(newEntry);\n writeStyleInboxStore(store);\n const mergedStore = readStyleInboxStore();\n const mergeKey = getStyleIntentMergeKey(newEntry);\n const entry = mergedStore.entries.find((item) => item.status === 'pending' && getStyleIntentMergeKey(item) === mergeKey) ?? newEntry;\n\n const cssBlocks = payload.entries.map(({ selector, changes }) => {\n const lines = changes.map(({ prop, val }) => ` ${prop}: ${val};`);\n return `${selector} {\\n${lines.join('\\n')}\\n}`;\n }).join('\\n\\n');\n\n const lines = [\n `\\n## ${new Date().toLocaleString('zh-CN')}`,\n '- 状态:待 AI 固化',\n payload.pageUrl ? `- 页面:${payload.pageUrl}` : '',\n payload.panelKind ? `- 面板:${payload.panelKind}` : '',\n payload.scopeLabel ? `- 作用范围:${payload.scopeLabel}` : '',\n payload.targetLabel ? `- 目标:${payload.targetLabel}` : '',\n payload.selector ? `- 选择器:\\`${payload.selector}\\`` : '',\n payload.note ? `- 备注:${payload.note}` : '',\n '',\n '```css',\n cssBlocks,\n '```',\n '',\n ].filter(Boolean);\n\n fs.appendFileSync(styleInboxMarkdownFile, lines.join('\\n'));\n return entry;\n }\n\n function getStyleIntentSummary() {\n const store = readStyleInboxStore();\n const pending = store.entries.filter((entry) => entry.status === 'pending');\n return {\n pendingCount: pending.length,\n latestPending: pending[0] ?? null,\n pendingEntries: pending,\n };\n }\n\n function deleteStyleIntent(payload: { id: string; selector?: string; prop?: string }) {\n const store = readStyleInboxStore();\n let changed = false;\n const nextEntries = store.entries.map((entry) => {\n if (entry.id !== payload.id) return entry;\n changed = true;\n\n if (!payload.selector || !payload.prop) {\n return { ...entry, status: 'resolved' as const };\n }\n\n const nextGroups = entry.entries\n .map((group) => {\n if (group.selector !== payload.selector) return group;\n return {\n ...group,\n changes: group.changes.filter((change) => change.prop !== payload.prop),\n };\n })\n .filter((group) => group.changes.length > 0);\n\n if (nextGroups.length === 0) {\n return { ...entry, status: 'resolved' as const, entries: [] };\n }\n\n return { ...entry, entries: nextGroups };\n });\n\n if (!changed) return { ok: false, error: 'NOT_FOUND' };\n writeStyleInboxStore({ entries: nextEntries });\n return { ok: true, ...getStyleIntentSummary() };\n }\n\n return {\n name: 'dev-inspector-server',\n configureServer(server: any) {\n server.middlewares.use('/__dev/apply-css', (req: any, res: any) => {\n if (req.method !== 'POST') { res.statusCode = 405; res.end(); return; }\n let body = '';\n req.on('data', (c: any) => body += c);\n req.on('end', () => {\n try {\n const payload = JSON.parse(body);\n const entries = Array.isArray(payload.entries)\n ? payload.entries\n : [{ selector: payload.selector, changes: payload.changes, note: payload.note }];\n const block = buildCssBlock(entries);\n fs.appendFileSync(cssFile, block);\n\n try {\n const firstEntry = entries[0];\n const msg = firstEntry?.note\n ? `style(DevInspector): ${firstEntry.selector} — ${firstEntry.note}`\n : `style(DevInspector): ${firstEntry?.selector ?? 'multi-selectors'}`;\n execSync(`cd \"${projectRoot}\" && git add ${commitTargetFile} && git commit -m ${JSON.stringify(msg)} --allow-empty`, { stdio: 'pipe' });\n } catch {}\n\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ ok: true }));\n } catch (e) {\n res.statusCode = 500;\n res.end(JSON.stringify({ ok: false, error: String(e) }));\n }\n });\n });\n\n server.middlewares.use('/__dev/submit-style-intent', (req: any, res: any) => {\n if (req.method !== 'POST') { res.statusCode = 405; res.end(); return; }\n let body = '';\n req.on('data', (c: any) => body += c);\n req.on('end', () => {\n try {\n const payload = JSON.parse(body);\n const entry = appendStyleInbox(payload);\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ ok: true, entry, ...getStyleIntentSummary() }));\n } catch (e) {\n res.statusCode = 500;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ ok: false, error: String(e) }));\n }\n });\n });\n\n server.middlewares.use('/__dev/style-intents/delete', (req: any, res: any) => {\n if (req.method !== 'POST') { res.statusCode = 405; res.end(); return; }\n let body = '';\n req.on('data', (c: any) => body += c);\n req.on('end', () => {\n try {\n const payload = JSON.parse(body);\n const result = deleteStyleIntent(payload);\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify(result));\n } catch (e) {\n res.statusCode = 500;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ ok: false, error: String(e) }));\n }\n });\n });\n\n server.middlewares.use('/__dev/style-intents', (req: any, res: any) => {\n if (req.method !== 'GET') { res.statusCode = 405; res.end(); return; }\n try {\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ ok: true, ...getStyleIntentSummary() }));\n } catch (e) {\n res.statusCode = 500;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ ok: false, error: String(e) }));\n }\n });\n },\n };\n}\n\nexport function createDevHandoffPlugin(projectRoot: string) {\n return {\n name: 'dev-handoff',\n configureServer(server: any) {\n server.middlewares.use('/__dev/handoff', (req: any, res: any) => {\n const url = new URL(req.url, 'http://localhost');\n const includeCode = url.searchParams.get('code') !== '0';\n const includeProduct = url.searchParams.get('product') !== '0';\n const includeDesign = url.searchParams.get('design') !== '0';\n\n const projectName = path.basename(projectRoot);\n const date = new Date().toISOString().slice(0, 10).replace(/-/g, '');\n const copyDir = fs.mkdtempSync(path.join(os.tmpdir(), 'handoff-'));\n\n try {\n const excludes: string[] = [\n 'node_modules/', 'dist/', '.git/', '.DS_Store',\n 'src/dev/', 'CLAUDE.md', 'AGENTS.md',\n '*_TEMPLATE.md', '*_PROMPT.md',\n 'README.md',\n 'docs/MEMORY_RULES.md', 'docs/USER_CONTEXT.md',\n 'docs/HANDOFF.md', 'docs/LESSONS.md',\n ];\n\n if (!includeCode) excludes.push('src/');\n if (!includeDesign) excludes.push('docs/design/');\n if (!includeProduct && !includeDesign) {\n excludes.push('docs/');\n } else if (!includeProduct) {\n ['CHANGELOG.md', 'CODE_STRUCTURE.md', 'DECISIONS.md',\n 'DESIGN_STANDARDS.md', 'PRODUCT_PLAN.md', 'PROJECT.md']\n .forEach((file) => excludes.push(`docs/${file}`));\n }\n\n const flags = excludes.map((exclude) => `--exclude='${exclude}'`).join(' ');\n execSync(`rsync -a ${flags} \"${projectRoot}/\" \"${copyDir}/\"`);\n\n if (includeCode) {\n const mainTsx = path.join(copyDir, 'src', 'main.tsx');\n const stripScript = path.join(os.homedir(), '.claude/skills/handoff/scripts/strip_dev_block.py');\n if (fs.existsSync(mainTsx) && fs.existsSync(stripScript)) {\n execSync(`python3 \"${stripScript}\" \"${mainTsx}\"`);\n }\n }\n\n const desktop = path.join(os.homedir(), 'Desktop');\n const filename = `${projectName}_handoff_${date}.zip`;\n const destZip = path.join(desktop, filename);\n\n execSync(`cd \"${copyDir}\" && zip -r \"${destZip}\" . -x \"*.DS_Store\"`, { stdio: 'pipe' });\n\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ ok: true, path: destZip }));\n } catch (e) {\n res.statusCode = 500;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ ok: false, error: String(e) }));\n } finally {\n try { execSync(`rm -rf \"${copyDir}\"`); } catch {}\n }\n });\n\n server.middlewares.use('/__dev/reveal', (req: any, res: any) => {\n const url = new URL(req.url, 'http://localhost');\n const filePath = url.searchParams.get('path') ?? '';\n try {\n execSync(`open -R \"${filePath}\"`);\n res.end('ok');\n } catch {\n res.statusCode = 500;\n res.end('error');\n }\n });\n },\n };\n}\n"],"mappings":"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","names":["path","fs","lines","os"]}
@@ -0,0 +1,17 @@
1
+ type DevInspectorServerOptions = {
2
+ projectRoot: string;
3
+ cssFile?: string;
4
+ styleInboxJsonFile?: string;
5
+ styleInboxMarkdownFile?: string;
6
+ commitTargetFile?: string;
7
+ };
8
+ declare function createDevInspectorServerPlugin(options: DevInspectorServerOptions): {
9
+ name: string;
10
+ configureServer(server: any): void;
11
+ };
12
+ declare function createDevHandoffPlugin(projectRoot: string): {
13
+ name: string;
14
+ configureServer(server: any): void;
15
+ };
16
+
17
+ export { createDevHandoffPlugin, createDevInspectorServerPlugin };
@@ -0,0 +1,17 @@
1
+ type DevInspectorServerOptions = {
2
+ projectRoot: string;
3
+ cssFile?: string;
4
+ styleInboxJsonFile?: string;
5
+ styleInboxMarkdownFile?: string;
6
+ commitTargetFile?: string;
7
+ };
8
+ declare function createDevInspectorServerPlugin(options: DevInspectorServerOptions): {
9
+ name: string;
10
+ configureServer(server: any): void;
11
+ };
12
+ declare function createDevHandoffPlugin(projectRoot: string): {
13
+ name: string;
14
+ configureServer(server: any): void;
15
+ };
16
+
17
+ export { createDevHandoffPlugin, createDevInspectorServerPlugin };
package/dist/index.js ADDED
@@ -0,0 +1,379 @@
1
+ // src/index.ts
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import { execSync } from "child_process";
5
+ import os from "os";
6
+ function getStyleIntentMergeKey(entry) {
7
+ return [
8
+ entry.panelKind ?? "",
9
+ entry.scopeLabel ?? "",
10
+ entry.selector ?? "",
11
+ entry.targetLabel ?? ""
12
+ ].join("||");
13
+ }
14
+ function mergeEntryGroups(primary, secondary) {
15
+ const groupMap = /* @__PURE__ */ new Map();
16
+ const appendGroups = (groups) => {
17
+ groups.forEach((group) => {
18
+ const selector = group.selector;
19
+ if (!selector) return;
20
+ if (!groupMap.has(selector)) {
21
+ groupMap.set(selector, { selector, changes: [] });
22
+ }
23
+ const targetGroup = groupMap.get(selector);
24
+ group.changes.forEach((change) => {
25
+ if (!change.prop || !change.val) return;
26
+ if (!targetGroup.changes.some((item) => item.prop === change.prop)) {
27
+ targetGroup.changes.push(change);
28
+ }
29
+ });
30
+ });
31
+ };
32
+ appendGroups(primary);
33
+ appendGroups(secondary);
34
+ return Array.from(groupMap.values()).filter((group) => group.changes.length > 0);
35
+ }
36
+ function compactStyleIntentEntries(entries) {
37
+ const merged = [];
38
+ const pendingIndexByKey = /* @__PURE__ */ new Map();
39
+ entries.forEach((entry) => {
40
+ if (entry.status !== "pending") {
41
+ merged.push(entry);
42
+ return;
43
+ }
44
+ const mergeKey = getStyleIntentMergeKey(entry);
45
+ const existingIndex = pendingIndexByKey.get(mergeKey);
46
+ if (existingIndex === void 0) {
47
+ pendingIndexByKey.set(mergeKey, merged.length);
48
+ merged.push({
49
+ ...entry,
50
+ entries: mergeEntryGroups(entry.entries, [])
51
+ });
52
+ return;
53
+ }
54
+ const existing = merged[existingIndex];
55
+ merged[existingIndex] = {
56
+ ...existing,
57
+ note: existing.note || entry.note,
58
+ entries: mergeEntryGroups(existing.entries, entry.entries)
59
+ };
60
+ });
61
+ return merged;
62
+ }
63
+ function normalizeAndCompactStore(store) {
64
+ const normalized = normalizeStyleIntentStore(store);
65
+ return {
66
+ entries: compactStyleIntentEntries(normalized.entries)
67
+ };
68
+ }
69
+ function normalizeStyleIntentStore(store) {
70
+ return {
71
+ entries: (store.entries || []).map((entry) => ({
72
+ ...entry,
73
+ entries: (entry.entries || []).map((group) => ({
74
+ ...group,
75
+ changes: (group.changes || []).filter((change) => change.prop && change.val)
76
+ })).filter((group) => group.selector && group.changes.length > 0)
77
+ }))
78
+ };
79
+ }
80
+ function buildCssBlock(entries) {
81
+ return entries.map(({ selector, changes, note }) => {
82
+ const lines = changes.map((c) => ` ${c.prop}: ${c.val};`);
83
+ return [
84
+ `
85
+ /* DevInspector: ${(/* @__PURE__ */ new Date()).toLocaleString("zh-CN")} */`,
86
+ note ? `/* ${note} */` : "",
87
+ `${selector} {`,
88
+ ...lines,
89
+ "}"
90
+ ].filter(Boolean).join("\n");
91
+ }).join("\n") + "\n";
92
+ }
93
+ function createDevInspectorServerPlugin(options) {
94
+ const projectRoot = options.projectRoot;
95
+ const cssFile = options.cssFile ?? path.resolve(projectRoot, "src/styles/index.css");
96
+ const styleInboxJsonFile = options.styleInboxJsonFile ?? path.resolve(projectRoot, "docs/style-inbox.json");
97
+ const styleInboxMarkdownFile = options.styleInboxMarkdownFile ?? path.resolve(projectRoot, "docs/STYLE_INBOX.md");
98
+ const commitTargetFile = options.commitTargetFile ?? "src/styles/dev-overrides.css";
99
+ function ensureStyleInboxStore() {
100
+ if (!fs.existsSync(styleInboxJsonFile)) {
101
+ fs.writeFileSync(styleInboxJsonFile, JSON.stringify({ entries: [] }, null, 2));
102
+ }
103
+ }
104
+ function readStyleInboxStore() {
105
+ ensureStyleInboxStore();
106
+ const raw = JSON.parse(fs.readFileSync(styleInboxJsonFile, "utf-8"));
107
+ const normalized = normalizeStyleIntentStore(raw);
108
+ const compacted = normalizeAndCompactStore(raw);
109
+ if (JSON.stringify(normalized) !== JSON.stringify(compacted)) {
110
+ fs.writeFileSync(styleInboxJsonFile, JSON.stringify(compacted, null, 2));
111
+ }
112
+ return compacted;
113
+ }
114
+ function writeStyleInboxStore(data) {
115
+ fs.writeFileSync(styleInboxJsonFile, JSON.stringify(normalizeAndCompactStore(data), null, 2));
116
+ }
117
+ function appendStyleInbox(payload) {
118
+ if (!fs.existsSync(styleInboxMarkdownFile)) {
119
+ fs.writeFileSync(
120
+ styleInboxMarkdownFile,
121
+ "# Style Inbox\n\n> \u7528\u6237\u901A\u8FC7 DevInspector \u63D0\u4EA4\u7ED9 AI \u52A9\u624B\u7684\u6837\u5F0F\u610F\u56FE\u6536\u96C6\u5904\u3002\n> \u8FD9\u91CC\u8BB0\u5F55\u7684\u662F\u201C\u5F85\u56FA\u5316\u201D\u7684\u8BBE\u8BA1\u6539\u52A8\uFF0C\u4E0D\u7B49\u4E8E\u5DF2\u7ECF\u5B8C\u6210\u6B63\u5F0F\u4EE3\u7801\u6536\u655B\u3002\n\n"
122
+ );
123
+ }
124
+ const store = readStyleInboxStore();
125
+ const newEntry = {
126
+ id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
127
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
128
+ status: "pending",
129
+ pageUrl: payload.pageUrl,
130
+ panelKind: payload.panelKind,
131
+ scopeLabel: payload.scopeLabel,
132
+ selector: payload.selector,
133
+ targetLabel: payload.targetLabel,
134
+ note: payload.note,
135
+ entries: payload.entries
136
+ };
137
+ store.entries.unshift(newEntry);
138
+ writeStyleInboxStore(store);
139
+ const mergedStore = readStyleInboxStore();
140
+ const mergeKey = getStyleIntentMergeKey(newEntry);
141
+ const entry = mergedStore.entries.find((item) => item.status === "pending" && getStyleIntentMergeKey(item) === mergeKey) ?? newEntry;
142
+ const cssBlocks = payload.entries.map(({ selector, changes }) => {
143
+ const lines2 = changes.map(({ prop, val }) => ` ${prop}: ${val};`);
144
+ return `${selector} {
145
+ ${lines2.join("\n")}
146
+ }`;
147
+ }).join("\n\n");
148
+ const lines = [
149
+ `
150
+ ## ${(/* @__PURE__ */ new Date()).toLocaleString("zh-CN")}`,
151
+ "- \u72B6\u6001\uFF1A\u5F85 AI \u56FA\u5316",
152
+ payload.pageUrl ? `- \u9875\u9762\uFF1A${payload.pageUrl}` : "",
153
+ payload.panelKind ? `- \u9762\u677F\uFF1A${payload.panelKind}` : "",
154
+ payload.scopeLabel ? `- \u4F5C\u7528\u8303\u56F4\uFF1A${payload.scopeLabel}` : "",
155
+ payload.targetLabel ? `- \u76EE\u6807\uFF1A${payload.targetLabel}` : "",
156
+ payload.selector ? `- \u9009\u62E9\u5668\uFF1A\`${payload.selector}\`` : "",
157
+ payload.note ? `- \u5907\u6CE8\uFF1A${payload.note}` : "",
158
+ "",
159
+ "```css",
160
+ cssBlocks,
161
+ "```",
162
+ ""
163
+ ].filter(Boolean);
164
+ fs.appendFileSync(styleInboxMarkdownFile, lines.join("\n"));
165
+ return entry;
166
+ }
167
+ function getStyleIntentSummary() {
168
+ const store = readStyleInboxStore();
169
+ const pending = store.entries.filter((entry) => entry.status === "pending");
170
+ return {
171
+ pendingCount: pending.length,
172
+ latestPending: pending[0] ?? null,
173
+ pendingEntries: pending
174
+ };
175
+ }
176
+ function deleteStyleIntent(payload) {
177
+ const store = readStyleInboxStore();
178
+ let changed = false;
179
+ const nextEntries = store.entries.map((entry) => {
180
+ if (entry.id !== payload.id) return entry;
181
+ changed = true;
182
+ if (!payload.selector || !payload.prop) {
183
+ return { ...entry, status: "resolved" };
184
+ }
185
+ const nextGroups = entry.entries.map((group) => {
186
+ if (group.selector !== payload.selector) return group;
187
+ return {
188
+ ...group,
189
+ changes: group.changes.filter((change) => change.prop !== payload.prop)
190
+ };
191
+ }).filter((group) => group.changes.length > 0);
192
+ if (nextGroups.length === 0) {
193
+ return { ...entry, status: "resolved", entries: [] };
194
+ }
195
+ return { ...entry, entries: nextGroups };
196
+ });
197
+ if (!changed) return { ok: false, error: "NOT_FOUND" };
198
+ writeStyleInboxStore({ entries: nextEntries });
199
+ return { ok: true, ...getStyleIntentSummary() };
200
+ }
201
+ return {
202
+ name: "dev-inspector-server",
203
+ configureServer(server) {
204
+ server.middlewares.use("/__dev/apply-css", (req, res) => {
205
+ if (req.method !== "POST") {
206
+ res.statusCode = 405;
207
+ res.end();
208
+ return;
209
+ }
210
+ let body = "";
211
+ req.on("data", (c) => body += c);
212
+ req.on("end", () => {
213
+ try {
214
+ const payload = JSON.parse(body);
215
+ const entries = Array.isArray(payload.entries) ? payload.entries : [{ selector: payload.selector, changes: payload.changes, note: payload.note }];
216
+ const block = buildCssBlock(entries);
217
+ fs.appendFileSync(cssFile, block);
218
+ try {
219
+ const firstEntry = entries[0];
220
+ const msg = firstEntry?.note ? `style(DevInspector): ${firstEntry.selector} \u2014 ${firstEntry.note}` : `style(DevInspector): ${firstEntry?.selector ?? "multi-selectors"}`;
221
+ execSync(`cd "${projectRoot}" && git add ${commitTargetFile} && git commit -m ${JSON.stringify(msg)} --allow-empty`, { stdio: "pipe" });
222
+ } catch {
223
+ }
224
+ res.setHeader("Content-Type", "application/json");
225
+ res.end(JSON.stringify({ ok: true }));
226
+ } catch (e) {
227
+ res.statusCode = 500;
228
+ res.end(JSON.stringify({ ok: false, error: String(e) }));
229
+ }
230
+ });
231
+ });
232
+ server.middlewares.use("/__dev/submit-style-intent", (req, res) => {
233
+ if (req.method !== "POST") {
234
+ res.statusCode = 405;
235
+ res.end();
236
+ return;
237
+ }
238
+ let body = "";
239
+ req.on("data", (c) => body += c);
240
+ req.on("end", () => {
241
+ try {
242
+ const payload = JSON.parse(body);
243
+ const entry = appendStyleInbox(payload);
244
+ res.setHeader("Content-Type", "application/json");
245
+ res.end(JSON.stringify({ ok: true, entry, ...getStyleIntentSummary() }));
246
+ } catch (e) {
247
+ res.statusCode = 500;
248
+ res.setHeader("Content-Type", "application/json");
249
+ res.end(JSON.stringify({ ok: false, error: String(e) }));
250
+ }
251
+ });
252
+ });
253
+ server.middlewares.use("/__dev/style-intents/delete", (req, res) => {
254
+ if (req.method !== "POST") {
255
+ res.statusCode = 405;
256
+ res.end();
257
+ return;
258
+ }
259
+ let body = "";
260
+ req.on("data", (c) => body += c);
261
+ req.on("end", () => {
262
+ try {
263
+ const payload = JSON.parse(body);
264
+ const result = deleteStyleIntent(payload);
265
+ res.setHeader("Content-Type", "application/json");
266
+ res.end(JSON.stringify(result));
267
+ } catch (e) {
268
+ res.statusCode = 500;
269
+ res.setHeader("Content-Type", "application/json");
270
+ res.end(JSON.stringify({ ok: false, error: String(e) }));
271
+ }
272
+ });
273
+ });
274
+ server.middlewares.use("/__dev/style-intents", (req, res) => {
275
+ if (req.method !== "GET") {
276
+ res.statusCode = 405;
277
+ res.end();
278
+ return;
279
+ }
280
+ try {
281
+ res.setHeader("Content-Type", "application/json");
282
+ res.end(JSON.stringify({ ok: true, ...getStyleIntentSummary() }));
283
+ } catch (e) {
284
+ res.statusCode = 500;
285
+ res.setHeader("Content-Type", "application/json");
286
+ res.end(JSON.stringify({ ok: false, error: String(e) }));
287
+ }
288
+ });
289
+ }
290
+ };
291
+ }
292
+ function createDevHandoffPlugin(projectRoot) {
293
+ return {
294
+ name: "dev-handoff",
295
+ configureServer(server) {
296
+ server.middlewares.use("/__dev/handoff", (req, res) => {
297
+ const url = new URL(req.url, "http://localhost");
298
+ const includeCode = url.searchParams.get("code") !== "0";
299
+ const includeProduct = url.searchParams.get("product") !== "0";
300
+ const includeDesign = url.searchParams.get("design") !== "0";
301
+ const projectName = path.basename(projectRoot);
302
+ const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10).replace(/-/g, "");
303
+ const copyDir = fs.mkdtempSync(path.join(os.tmpdir(), "handoff-"));
304
+ try {
305
+ const excludes = [
306
+ "node_modules/",
307
+ "dist/",
308
+ ".git/",
309
+ ".DS_Store",
310
+ "src/dev/",
311
+ "CLAUDE.md",
312
+ "AGENTS.md",
313
+ "*_TEMPLATE.md",
314
+ "*_PROMPT.md",
315
+ "README.md",
316
+ "docs/MEMORY_RULES.md",
317
+ "docs/USER_CONTEXT.md",
318
+ "docs/HANDOFF.md",
319
+ "docs/LESSONS.md"
320
+ ];
321
+ if (!includeCode) excludes.push("src/");
322
+ if (!includeDesign) excludes.push("docs/design/");
323
+ if (!includeProduct && !includeDesign) {
324
+ excludes.push("docs/");
325
+ } else if (!includeProduct) {
326
+ [
327
+ "CHANGELOG.md",
328
+ "CODE_STRUCTURE.md",
329
+ "DECISIONS.md",
330
+ "DESIGN_STANDARDS.md",
331
+ "PRODUCT_PLAN.md",
332
+ "PROJECT.md"
333
+ ].forEach((file) => excludes.push(`docs/${file}`));
334
+ }
335
+ const flags = excludes.map((exclude) => `--exclude='${exclude}'`).join(" ");
336
+ execSync(`rsync -a ${flags} "${projectRoot}/" "${copyDir}/"`);
337
+ if (includeCode) {
338
+ const mainTsx = path.join(copyDir, "src", "main.tsx");
339
+ const stripScript = path.join(os.homedir(), ".claude/skills/handoff/scripts/strip_dev_block.py");
340
+ if (fs.existsSync(mainTsx) && fs.existsSync(stripScript)) {
341
+ execSync(`python3 "${stripScript}" "${mainTsx}"`);
342
+ }
343
+ }
344
+ const desktop = path.join(os.homedir(), "Desktop");
345
+ const filename = `${projectName}_handoff_${date}.zip`;
346
+ const destZip = path.join(desktop, filename);
347
+ execSync(`cd "${copyDir}" && zip -r "${destZip}" . -x "*.DS_Store"`, { stdio: "pipe" });
348
+ res.setHeader("Content-Type", "application/json");
349
+ res.end(JSON.stringify({ ok: true, path: destZip }));
350
+ } catch (e) {
351
+ res.statusCode = 500;
352
+ res.setHeader("Content-Type", "application/json");
353
+ res.end(JSON.stringify({ ok: false, error: String(e) }));
354
+ } finally {
355
+ try {
356
+ execSync(`rm -rf "${copyDir}"`);
357
+ } catch {
358
+ }
359
+ }
360
+ });
361
+ server.middlewares.use("/__dev/reveal", (req, res) => {
362
+ const url = new URL(req.url, "http://localhost");
363
+ const filePath = url.searchParams.get("path") ?? "";
364
+ try {
365
+ execSync(`open -R "${filePath}"`);
366
+ res.end("ok");
367
+ } catch {
368
+ res.statusCode = 500;
369
+ res.end("error");
370
+ }
371
+ });
372
+ }
373
+ };
374
+ }
375
+ export {
376
+ createDevHandoffPlugin,
377
+ createDevInspectorServerPlugin
378
+ };
379
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { execSync } from 'node:child_process';\nimport os from 'node:os';\n\ntype StyleIntentEntry = {\n id: string;\n createdAt: string;\n status: 'pending' | 'resolved';\n pageUrl?: string;\n panelKind?: string;\n scopeLabel?: string;\n selector?: string;\n targetLabel?: string;\n note?: string;\n entries: { selector: string; changes: { prop: string; val: string; from?: string }[] }[];\n};\n\ntype DevInspectorServerOptions = {\n projectRoot: string;\n cssFile?: string;\n styleInboxJsonFile?: string;\n styleInboxMarkdownFile?: string;\n commitTargetFile?: string;\n};\n\nfunction getStyleIntentMergeKey(entry: StyleIntentEntry) {\n return [\n entry.panelKind ?? '',\n entry.scopeLabel ?? '',\n entry.selector ?? '',\n entry.targetLabel ?? '',\n ].join('||');\n}\n\nfunction mergeEntryGroups(\n primary: StyleIntentEntry['entries'],\n secondary: StyleIntentEntry['entries'],\n) {\n const groupMap = new Map<string, { selector: string; changes: { prop: string; val: string; from?: string }[] }>();\n\n const appendGroups = (groups: StyleIntentEntry['entries']) => {\n groups.forEach((group) => {\n const selector = group.selector;\n if (!selector) return;\n if (!groupMap.has(selector)) {\n groupMap.set(selector, { selector, changes: [] });\n }\n const targetGroup = groupMap.get(selector)!;\n group.changes.forEach((change) => {\n if (!change.prop || !change.val) return;\n if (!targetGroup.changes.some((item) => item.prop === change.prop)) {\n targetGroup.changes.push(change);\n }\n });\n });\n };\n\n appendGroups(primary);\n appendGroups(secondary);\n\n return Array.from(groupMap.values()).filter((group) => group.changes.length > 0);\n}\n\nfunction compactStyleIntentEntries(entries: StyleIntentEntry[]) {\n const merged: StyleIntentEntry[] = [];\n const pendingIndexByKey = new Map<string, number>();\n\n entries.forEach((entry) => {\n if (entry.status !== 'pending') {\n merged.push(entry);\n return;\n }\n\n const mergeKey = getStyleIntentMergeKey(entry);\n const existingIndex = pendingIndexByKey.get(mergeKey);\n if (existingIndex === undefined) {\n pendingIndexByKey.set(mergeKey, merged.length);\n merged.push({\n ...entry,\n entries: mergeEntryGroups(entry.entries, []),\n });\n return;\n }\n\n const existing = merged[existingIndex];\n merged[existingIndex] = {\n ...existing,\n note: existing.note || entry.note,\n entries: mergeEntryGroups(existing.entries, entry.entries),\n };\n });\n\n return merged;\n}\n\nfunction normalizeAndCompactStore(store: { entries: StyleIntentEntry[] }) {\n const normalized = normalizeStyleIntentStore(store);\n return {\n entries: compactStyleIntentEntries(normalized.entries),\n };\n}\n\nfunction normalizeStyleIntentStore(store: { entries: StyleIntentEntry[] }) {\n return {\n entries: (store.entries || []).map((entry) => ({\n ...entry,\n entries: (entry.entries || [])\n .map((group) => ({\n ...group,\n changes: (group.changes || []).filter((change) => change.prop && change.val),\n }))\n .filter((group) => group.selector && group.changes.length > 0),\n })),\n };\n}\n\nfunction buildCssBlock(entries: { selector: string; changes: { prop: string; val: string }[]; note?: string }[]) {\n return entries.map(({ selector, changes, note }) => {\n const lines = changes.map((c) => ` ${c.prop}: ${c.val};`);\n return [\n `\\n/* DevInspector: ${new Date().toLocaleString('zh-CN')} */`,\n note ? `/* ${note} */` : '',\n `${selector} {`,\n ...lines,\n '}',\n ].filter(Boolean).join('\\n');\n }).join('\\n') + '\\n';\n}\n\nexport function createDevInspectorServerPlugin(options: DevInspectorServerOptions) {\n const projectRoot = options.projectRoot;\n const cssFile = options.cssFile ?? path.resolve(projectRoot, 'src/styles/index.css');\n const styleInboxJsonFile = options.styleInboxJsonFile ?? path.resolve(projectRoot, 'docs/style-inbox.json');\n const styleInboxMarkdownFile = options.styleInboxMarkdownFile ?? path.resolve(projectRoot, 'docs/STYLE_INBOX.md');\n const commitTargetFile = options.commitTargetFile ?? 'src/styles/dev-overrides.css';\n\n function ensureStyleInboxStore() {\n if (!fs.existsSync(styleInboxJsonFile)) {\n fs.writeFileSync(styleInboxJsonFile, JSON.stringify({ entries: [] }, null, 2));\n }\n }\n\n function readStyleInboxStore(): { entries: StyleIntentEntry[] } {\n ensureStyleInboxStore();\n const raw = JSON.parse(fs.readFileSync(styleInboxJsonFile, 'utf-8'));\n const normalized = normalizeStyleIntentStore(raw);\n const compacted = normalizeAndCompactStore(raw);\n if (JSON.stringify(normalized) !== JSON.stringify(compacted)) {\n fs.writeFileSync(styleInboxJsonFile, JSON.stringify(compacted, null, 2));\n }\n return compacted;\n }\n\n function writeStyleInboxStore(data: { entries: StyleIntentEntry[] }) {\n fs.writeFileSync(styleInboxJsonFile, JSON.stringify(normalizeAndCompactStore(data), null, 2));\n }\n\n function appendStyleInbox(payload: {\n pageUrl?: string;\n panelKind?: string;\n scopeLabel?: string;\n selector?: string;\n targetLabel?: string;\n note?: string;\n entries: { selector: string; changes: { prop: string; val: string; from?: string }[] }[];\n }): StyleIntentEntry {\n if (!fs.existsSync(styleInboxMarkdownFile)) {\n fs.writeFileSync(\n styleInboxMarkdownFile,\n '# Style Inbox\\n\\n> 用户通过 DevInspector 提交给 AI 助手的样式意图收集处。\\n> 这里记录的是“待固化”的设计改动,不等于已经完成正式代码收敛。\\n\\n',\n );\n }\n\n const store = readStyleInboxStore();\n const newEntry: StyleIntentEntry = {\n id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n createdAt: new Date().toISOString(),\n status: 'pending',\n pageUrl: payload.pageUrl,\n panelKind: payload.panelKind,\n scopeLabel: payload.scopeLabel,\n selector: payload.selector,\n targetLabel: payload.targetLabel,\n note: payload.note,\n entries: payload.entries,\n };\n store.entries.unshift(newEntry);\n writeStyleInboxStore(store);\n const mergedStore = readStyleInboxStore();\n const mergeKey = getStyleIntentMergeKey(newEntry);\n const entry = mergedStore.entries.find((item) => item.status === 'pending' && getStyleIntentMergeKey(item) === mergeKey) ?? newEntry;\n\n const cssBlocks = payload.entries.map(({ selector, changes }) => {\n const lines = changes.map(({ prop, val }) => ` ${prop}: ${val};`);\n return `${selector} {\\n${lines.join('\\n')}\\n}`;\n }).join('\\n\\n');\n\n const lines = [\n `\\n## ${new Date().toLocaleString('zh-CN')}`,\n '- 状态:待 AI 固化',\n payload.pageUrl ? `- 页面:${payload.pageUrl}` : '',\n payload.panelKind ? `- 面板:${payload.panelKind}` : '',\n payload.scopeLabel ? `- 作用范围:${payload.scopeLabel}` : '',\n payload.targetLabel ? `- 目标:${payload.targetLabel}` : '',\n payload.selector ? `- 选择器:\\`${payload.selector}\\`` : '',\n payload.note ? `- 备注:${payload.note}` : '',\n '',\n '```css',\n cssBlocks,\n '```',\n '',\n ].filter(Boolean);\n\n fs.appendFileSync(styleInboxMarkdownFile, lines.join('\\n'));\n return entry;\n }\n\n function getStyleIntentSummary() {\n const store = readStyleInboxStore();\n const pending = store.entries.filter((entry) => entry.status === 'pending');\n return {\n pendingCount: pending.length,\n latestPending: pending[0] ?? null,\n pendingEntries: pending,\n };\n }\n\n function deleteStyleIntent(payload: { id: string; selector?: string; prop?: string }) {\n const store = readStyleInboxStore();\n let changed = false;\n const nextEntries = store.entries.map((entry) => {\n if (entry.id !== payload.id) return entry;\n changed = true;\n\n if (!payload.selector || !payload.prop) {\n return { ...entry, status: 'resolved' as const };\n }\n\n const nextGroups = entry.entries\n .map((group) => {\n if (group.selector !== payload.selector) return group;\n return {\n ...group,\n changes: group.changes.filter((change) => change.prop !== payload.prop),\n };\n })\n .filter((group) => group.changes.length > 0);\n\n if (nextGroups.length === 0) {\n return { ...entry, status: 'resolved' as const, entries: [] };\n }\n\n return { ...entry, entries: nextGroups };\n });\n\n if (!changed) return { ok: false, error: 'NOT_FOUND' };\n writeStyleInboxStore({ entries: nextEntries });\n return { ok: true, ...getStyleIntentSummary() };\n }\n\n return {\n name: 'dev-inspector-server',\n configureServer(server: any) {\n server.middlewares.use('/__dev/apply-css', (req: any, res: any) => {\n if (req.method !== 'POST') { res.statusCode = 405; res.end(); return; }\n let body = '';\n req.on('data', (c: any) => body += c);\n req.on('end', () => {\n try {\n const payload = JSON.parse(body);\n const entries = Array.isArray(payload.entries)\n ? payload.entries\n : [{ selector: payload.selector, changes: payload.changes, note: payload.note }];\n const block = buildCssBlock(entries);\n fs.appendFileSync(cssFile, block);\n\n try {\n const firstEntry = entries[0];\n const msg = firstEntry?.note\n ? `style(DevInspector): ${firstEntry.selector} — ${firstEntry.note}`\n : `style(DevInspector): ${firstEntry?.selector ?? 'multi-selectors'}`;\n execSync(`cd \"${projectRoot}\" && git add ${commitTargetFile} && git commit -m ${JSON.stringify(msg)} --allow-empty`, { stdio: 'pipe' });\n } catch {}\n\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ ok: true }));\n } catch (e) {\n res.statusCode = 500;\n res.end(JSON.stringify({ ok: false, error: String(e) }));\n }\n });\n });\n\n server.middlewares.use('/__dev/submit-style-intent', (req: any, res: any) => {\n if (req.method !== 'POST') { res.statusCode = 405; res.end(); return; }\n let body = '';\n req.on('data', (c: any) => body += c);\n req.on('end', () => {\n try {\n const payload = JSON.parse(body);\n const entry = appendStyleInbox(payload);\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ ok: true, entry, ...getStyleIntentSummary() }));\n } catch (e) {\n res.statusCode = 500;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ ok: false, error: String(e) }));\n }\n });\n });\n\n server.middlewares.use('/__dev/style-intents/delete', (req: any, res: any) => {\n if (req.method !== 'POST') { res.statusCode = 405; res.end(); return; }\n let body = '';\n req.on('data', (c: any) => body += c);\n req.on('end', () => {\n try {\n const payload = JSON.parse(body);\n const result = deleteStyleIntent(payload);\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify(result));\n } catch (e) {\n res.statusCode = 500;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ ok: false, error: String(e) }));\n }\n });\n });\n\n server.middlewares.use('/__dev/style-intents', (req: any, res: any) => {\n if (req.method !== 'GET') { res.statusCode = 405; res.end(); return; }\n try {\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ ok: true, ...getStyleIntentSummary() }));\n } catch (e) {\n res.statusCode = 500;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ ok: false, error: String(e) }));\n }\n });\n },\n };\n}\n\nexport function createDevHandoffPlugin(projectRoot: string) {\n return {\n name: 'dev-handoff',\n configureServer(server: any) {\n server.middlewares.use('/__dev/handoff', (req: any, res: any) => {\n const url = new URL(req.url, 'http://localhost');\n const includeCode = url.searchParams.get('code') !== '0';\n const includeProduct = url.searchParams.get('product') !== '0';\n const includeDesign = url.searchParams.get('design') !== '0';\n\n const projectName = path.basename(projectRoot);\n const date = new Date().toISOString().slice(0, 10).replace(/-/g, '');\n const copyDir = fs.mkdtempSync(path.join(os.tmpdir(), 'handoff-'));\n\n try {\n const excludes: string[] = [\n 'node_modules/', 'dist/', '.git/', '.DS_Store',\n 'src/dev/', 'CLAUDE.md', 'AGENTS.md',\n '*_TEMPLATE.md', '*_PROMPT.md',\n 'README.md',\n 'docs/MEMORY_RULES.md', 'docs/USER_CONTEXT.md',\n 'docs/HANDOFF.md', 'docs/LESSONS.md',\n ];\n\n if (!includeCode) excludes.push('src/');\n if (!includeDesign) excludes.push('docs/design/');\n if (!includeProduct && !includeDesign) {\n excludes.push('docs/');\n } else if (!includeProduct) {\n ['CHANGELOG.md', 'CODE_STRUCTURE.md', 'DECISIONS.md',\n 'DESIGN_STANDARDS.md', 'PRODUCT_PLAN.md', 'PROJECT.md']\n .forEach((file) => excludes.push(`docs/${file}`));\n }\n\n const flags = excludes.map((exclude) => `--exclude='${exclude}'`).join(' ');\n execSync(`rsync -a ${flags} \"${projectRoot}/\" \"${copyDir}/\"`);\n\n if (includeCode) {\n const mainTsx = path.join(copyDir, 'src', 'main.tsx');\n const stripScript = path.join(os.homedir(), '.claude/skills/handoff/scripts/strip_dev_block.py');\n if (fs.existsSync(mainTsx) && fs.existsSync(stripScript)) {\n execSync(`python3 \"${stripScript}\" \"${mainTsx}\"`);\n }\n }\n\n const desktop = path.join(os.homedir(), 'Desktop');\n const filename = `${projectName}_handoff_${date}.zip`;\n const destZip = path.join(desktop, filename);\n\n execSync(`cd \"${copyDir}\" && zip -r \"${destZip}\" . -x \"*.DS_Store\"`, { stdio: 'pipe' });\n\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ ok: true, path: destZip }));\n } catch (e) {\n res.statusCode = 500;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ ok: false, error: String(e) }));\n } finally {\n try { execSync(`rm -rf \"${copyDir}\"`); } catch {}\n }\n });\n\n server.middlewares.use('/__dev/reveal', (req: any, res: any) => {\n const url = new URL(req.url, 'http://localhost');\n const filePath = url.searchParams.get('path') ?? '';\n try {\n execSync(`open -R \"${filePath}\"`);\n res.end('ok');\n } catch {\n res.statusCode = 500;\n res.end('error');\n }\n });\n },\n };\n}\n"],"mappings":"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","names":["lines"]}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@lijinmei-810/dev-inspector-vite",
3
+ "version": "0.1.0",
4
+ "description": "Dev Inspector 配套 Vite 插件:提供 CSS 落盘、style-intent 收集、handoff 打包等服务端 hook",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.cjs",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js",
14
+ "require": "./dist/index.cjs"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "README.md"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsup",
23
+ "dev": "tsup --watch"
24
+ },
25
+ "peerDependencies": {
26
+ "vite": ">=5"
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "keywords": ["vite-plugin", "devtools", "css-inspector"],
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/lijinmei915/dev-inspector.git",
35
+ "directory": "packages/dev-inspector-vite"
36
+ }
37
+ }