@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 +415 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +17 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +379 -0
- package/dist/index.js.map +1 -0
- package/package.json +37 -0
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"]}
|
package/dist/index.d.cts
ADDED
|
@@ -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.d.ts
ADDED
|
@@ -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
|
+
}
|