digdesign 0.6.1 → 0.7.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.js +284 -145
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2054,13 +2054,234 @@ async function impactCommand(name, options) {
|
|
|
2054
2054
|
}
|
|
2055
2055
|
}
|
|
2056
2056
|
|
|
2057
|
+
// src/commands/review.ts
|
|
2058
|
+
import { readFile as readFile8 } from "fs/promises";
|
|
2059
|
+
import path11 from "path";
|
|
2060
|
+
|
|
2061
|
+
// src/lib/version.ts
|
|
2062
|
+
var CLI_VERSION = "0.7.0";
|
|
2063
|
+
|
|
2064
|
+
// src/commands/mcp.ts
|
|
2065
|
+
import { createInterface as createInterface2 } from "readline";
|
|
2066
|
+
var DEFAULT_MCP_URL = "https://docs.digdesign.ir/api/mcp";
|
|
2067
|
+
function parseSse(body) {
|
|
2068
|
+
const messages = [];
|
|
2069
|
+
for (const event of body.split(/\r?\n\r?\n/)) {
|
|
2070
|
+
const data = event.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).replace(/^ /, "")).join("\n");
|
|
2071
|
+
if (!data) continue;
|
|
2072
|
+
try {
|
|
2073
|
+
messages.push(JSON.parse(data));
|
|
2074
|
+
} catch {
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
return messages;
|
|
2078
|
+
}
|
|
2079
|
+
function requestIds(message) {
|
|
2080
|
+
const list = Array.isArray(message) ? message : [message];
|
|
2081
|
+
return list.filter((item) => typeof item === "object" && item !== null).filter((item) => item.method !== void 0 && item.id !== void 0 && item.id !== null).map((item) => item.id);
|
|
2082
|
+
}
|
|
2083
|
+
function createBridge(url, fetchImpl = fetch) {
|
|
2084
|
+
let sessionId;
|
|
2085
|
+
let protocolVersion;
|
|
2086
|
+
return {
|
|
2087
|
+
async handle(line) {
|
|
2088
|
+
let message;
|
|
2089
|
+
try {
|
|
2090
|
+
message = JSON.parse(line);
|
|
2091
|
+
} catch {
|
|
2092
|
+
return [{ jsonrpc: "2.0", id: null, error: { code: -32700, message: "Parse error" } }];
|
|
2093
|
+
}
|
|
2094
|
+
const ids = requestIds(message);
|
|
2095
|
+
const fail = (reason) => ids.map((id) => ({ jsonrpc: "2.0", id, error: { code: -32603, message: `Dig MCP (${url}): ${reason}` } }));
|
|
2096
|
+
let response;
|
|
2097
|
+
try {
|
|
2098
|
+
response = await fetchImpl(url, {
|
|
2099
|
+
method: "POST",
|
|
2100
|
+
headers: {
|
|
2101
|
+
"content-type": "application/json",
|
|
2102
|
+
accept: "application/json, text/event-stream",
|
|
2103
|
+
"user-agent": `digdesign-cli/${CLI_VERSION}`,
|
|
2104
|
+
...sessionId && { "mcp-session-id": sessionId },
|
|
2105
|
+
...protocolVersion && { "mcp-protocol-version": protocolVersion }
|
|
2106
|
+
},
|
|
2107
|
+
body: line
|
|
2108
|
+
});
|
|
2109
|
+
} catch (error) {
|
|
2110
|
+
return fail(`network error: ${error.message}`);
|
|
2111
|
+
}
|
|
2112
|
+
sessionId = response.headers.get("mcp-session-id") ?? sessionId;
|
|
2113
|
+
if (response.status === 202) return [];
|
|
2114
|
+
const body = await response.text();
|
|
2115
|
+
if (!response.ok) return fail(`HTTP ${response.status} ${body.slice(0, 200)}`);
|
|
2116
|
+
let replies;
|
|
2117
|
+
if ((response.headers.get("content-type") ?? "").includes("text/event-stream")) replies = parseSse(body);
|
|
2118
|
+
else {
|
|
2119
|
+
try {
|
|
2120
|
+
replies = body.trim() ? [JSON.parse(body)] : [];
|
|
2121
|
+
} catch {
|
|
2122
|
+
return fail(`invalid JSON response: ${body.slice(0, 200)}`);
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
for (const reply of replies.flat()) {
|
|
2126
|
+
const result = reply?.result;
|
|
2127
|
+
if (result?.protocolVersion) protocolVersion = result.protocolVersion;
|
|
2128
|
+
}
|
|
2129
|
+
return replies;
|
|
2130
|
+
}
|
|
2131
|
+
};
|
|
2132
|
+
}
|
|
2133
|
+
async function mcpCommand(options) {
|
|
2134
|
+
const url = options.url ?? process.env.DIG_MCP_URL ?? DEFAULT_MCP_URL;
|
|
2135
|
+
const bridge = createBridge(url);
|
|
2136
|
+
const pending = /* @__PURE__ */ new Set();
|
|
2137
|
+
process.stderr.write(`dig mcp: stdio bridge to ${url}
|
|
2138
|
+
`);
|
|
2139
|
+
const input = createInterface2({ input: process.stdin, crlfDelay: Infinity });
|
|
2140
|
+
for await (const line of input) {
|
|
2141
|
+
if (!line.trim()) continue;
|
|
2142
|
+
const task = bridge.handle(line).then((replies) => {
|
|
2143
|
+
for (const reply of replies) process.stdout.write(`${JSON.stringify(reply)}
|
|
2144
|
+
`);
|
|
2145
|
+
});
|
|
2146
|
+
pending.add(task);
|
|
2147
|
+
void task.finally(() => pending.delete(task));
|
|
2148
|
+
}
|
|
2149
|
+
await Promise.all(pending);
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2152
|
+
// src/commands/review.ts
|
|
2153
|
+
var MAX_FILE_CHARS = 2e5;
|
|
2154
|
+
var MAX_FILES_PER_CALL = 25;
|
|
2155
|
+
async function readReviewFiles(paths, cwd) {
|
|
2156
|
+
const files = [];
|
|
2157
|
+
for (const input of paths) {
|
|
2158
|
+
const absolute = path11.resolve(cwd, input);
|
|
2159
|
+
let code;
|
|
2160
|
+
try {
|
|
2161
|
+
code = await readFile8(absolute, "utf8");
|
|
2162
|
+
} catch {
|
|
2163
|
+
throw new DigError(`\u0641\u0627\u06CC\u0644 \u062E\u0648\u0627\u0646\u062F\u0647 \u0646\u0634\u062F: ${input}`);
|
|
2164
|
+
}
|
|
2165
|
+
if (code.length > MAX_FILE_CHARS) throw new DigError(`${input} \u0628\u0632\u0631\u06AF\u200C\u062A\u0631 \u0627\u0632 ${MAX_FILE_CHARS} \u0646\u0648\u06CC\u0633\u0647 \u0627\u0633\u062A\u061B \u0628\u0647 \u0641\u0627\u06CC\u0644\u200C\u0647\u0627\u06CC \u06A9\u0648\u0686\u06A9\u200C\u062A\u0631 \u0628\u0634\u06A9\u0646.`);
|
|
2166
|
+
files.push({ path: path11.relative(cwd, absolute) || input, code });
|
|
2167
|
+
}
|
|
2168
|
+
return files;
|
|
2169
|
+
}
|
|
2170
|
+
async function callReview(url, files, fetchImpl = fetch) {
|
|
2171
|
+
let response;
|
|
2172
|
+
try {
|
|
2173
|
+
response = await fetchImpl(url, {
|
|
2174
|
+
method: "POST",
|
|
2175
|
+
headers: {
|
|
2176
|
+
"content-type": "application/json",
|
|
2177
|
+
accept: "application/json, text/event-stream",
|
|
2178
|
+
"user-agent": `digdesign-cli/${CLI_VERSION}`
|
|
2179
|
+
},
|
|
2180
|
+
body: JSON.stringify({
|
|
2181
|
+
jsonrpc: "2.0",
|
|
2182
|
+
id: 1,
|
|
2183
|
+
method: "tools/call",
|
|
2184
|
+
params: { name: "review_code", arguments: { files } }
|
|
2185
|
+
})
|
|
2186
|
+
});
|
|
2187
|
+
} catch (error) {
|
|
2188
|
+
throw new DigError(`\u0627\u062A\u0635\u0627\u0644 \u0628\u0647 ${url} \u0628\u0631\u0642\u0631\u0627\u0631 \u0646\u0634\u062F: ${error.message}`);
|
|
2189
|
+
}
|
|
2190
|
+
const body = await response.text();
|
|
2191
|
+
if (!response.ok) throw new DigError(`\u0628\u0627\u0632\u0628\u06CC\u0646\u06CC \u0634\u06A9\u0633\u062A \u062E\u0648\u0631\u062F (HTTP ${response.status}).`);
|
|
2192
|
+
const message = (response.headers.get("content-type") ?? "").includes("text/event-stream") ? parseSse(body)[0] : JSON.parse(body);
|
|
2193
|
+
const text = message?.result?.content?.[0]?.text;
|
|
2194
|
+
if (!text) throw new DigError("\u067E\u0627\u0633\u062E\u0650 \u0646\u0627\u0645\u0639\u062A\u0628\u0631 \u0627\u0632 \u0633\u0631\u0648\u0631 MCP.");
|
|
2195
|
+
return JSON.parse(text);
|
|
2196
|
+
}
|
|
2197
|
+
async function reviewCommand(paths, options) {
|
|
2198
|
+
if (paths.length === 0) throw new DigError("\u062D\u062F\u0627\u0642\u0644 \u06CC\u06A9 \u0645\u0633\u06CC\u0631 \u0641\u0627\u06CC\u0644 \u0628\u062F\u0647: dig review src/app/page.tsx");
|
|
2199
|
+
const url = options.url ?? process.env.DIG_MCP_URL ?? DEFAULT_MCP_URL;
|
|
2200
|
+
const files = await readReviewFiles(paths, process.cwd());
|
|
2201
|
+
const merged = [];
|
|
2202
|
+
const reviewed = [];
|
|
2203
|
+
for (let i = 0; i < files.length; i += MAX_FILES_PER_CALL) {
|
|
2204
|
+
const result = await callReview(url, files.slice(i, i + MAX_FILES_PER_CALL));
|
|
2205
|
+
if (result.status === "invalid_input") throw new DigError(result.message ?? "\u0648\u0631\u0648\u062F\u06CC\u0650 \u0628\u0627\u0632\u0628\u06CC\u0646\u06CC \u0646\u0627\u0645\u0639\u062A\u0628\u0631 \u0627\u0633\u062A.");
|
|
2206
|
+
merged.push(...result.findings ?? []);
|
|
2207
|
+
reviewed.push(...result.reviewed ?? []);
|
|
2208
|
+
}
|
|
2209
|
+
const errors = merged.filter((finding) => finding.severity !== "warning").length;
|
|
2210
|
+
const status = errors > 0 ? "issues" : merged.length > 0 ? "warnings" : "ok";
|
|
2211
|
+
if (options.json) {
|
|
2212
|
+
console.log(JSON.stringify({ status, findings: merged, reviewed }, null, 2));
|
|
2213
|
+
} else {
|
|
2214
|
+
for (const finding of merged) {
|
|
2215
|
+
const where = `${finding.file ?? ""}:${finding.line}`;
|
|
2216
|
+
console.log(`${where} [${finding.severity ?? "error"}] ${finding.rule}
|
|
2217
|
+
${finding.found}
|
|
2218
|
+
\u2190 ${finding.fix}`);
|
|
2219
|
+
}
|
|
2220
|
+
const lines = reviewed.reduce((sum, file) => sum + file.lines, 0);
|
|
2221
|
+
console.log(merged.length === 0 ? `\u062A\u062E\u0644\u0641\u06CC \u067E\u06CC\u062F\u0627 \u0646\u0634\u062F (${files.length} \u0641\u0627\u06CC\u0644\u060C ${lines} \u062E\u0637).` : `${merged.length} \u06CC\u0627\u0641\u062A\u0647 \u062F\u0631 ${files.length} \u0641\u0627\u06CC\u0644 (${lines} \u062E\u0637).`);
|
|
2222
|
+
}
|
|
2223
|
+
if (errors > 0) process.exitCode = 1;
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2226
|
+
// src/commands/skill.ts
|
|
2227
|
+
import { mkdir as mkdir4, writeFile as writeFile6 } from "fs/promises";
|
|
2228
|
+
import path12 from "path";
|
|
2229
|
+
var SKILL_PATH = ".claude/skills/dig-design-system/SKILL.md";
|
|
2230
|
+
async function skillCommand() {
|
|
2231
|
+
const cwd = process.cwd();
|
|
2232
|
+
const registryUrl = await configExists(cwd) ? (await readConfig(cwd)).registryUrl : defaultConfig().registryUrl;
|
|
2233
|
+
const url = new URL("/api/skill", registryUrl);
|
|
2234
|
+
let response;
|
|
2235
|
+
try {
|
|
2236
|
+
response = await fetch(url);
|
|
2237
|
+
} catch {
|
|
2238
|
+
throw new DigError(`\u0627\u062A\u0635\u0627\u0644 \u0628\u0647 ${url.origin} \u0628\u0631\u0627\u06CC \u06AF\u0631\u0641\u062A\u0646\u0650 Skill \u0628\u0631\u0642\u0631\u0627\u0631 \u0646\u0634\u062F.`);
|
|
2239
|
+
}
|
|
2240
|
+
if (!response.ok) throw new DigError(`Skill \u06AF\u0631\u0641\u062A\u0647 \u0646\u0634\u062F: ${response.status}`);
|
|
2241
|
+
const target = path12.join(cwd, SKILL_PATH);
|
|
2242
|
+
await mkdir4(path12.dirname(target), { recursive: true });
|
|
2243
|
+
await writeFile6(target, await response.text(), "utf8");
|
|
2244
|
+
console.log(`\u2713 ${SKILL_PATH} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F (Skill\u0650 \u0631\u0633\u0645\u06CC\u0650 \u062F\u06CC\u06AF \u0628\u0631\u0627\u06CC Claude Code).`);
|
|
2245
|
+
}
|
|
2246
|
+
|
|
2247
|
+
// src/commands/tokens.ts
|
|
2248
|
+
import { mkdir as mkdir5, readFile as readFile9, writeFile as writeFile7 } from "fs/promises";
|
|
2249
|
+
import path13 from "path";
|
|
2250
|
+
async function tokensCommand(options) {
|
|
2251
|
+
const cwd = process.cwd();
|
|
2252
|
+
const registryUrl = await configExists(cwd) ? (await readConfig(cwd)).registryUrl : defaultConfig().registryUrl;
|
|
2253
|
+
const designMd = await readFile9(path13.join(cwd, DESIGN_MD_FILE), "utf8").catch(() => "");
|
|
2254
|
+
const brand = options.brand ?? readDesignMdSettings(designMd).brand;
|
|
2255
|
+
const outDir = path13.join(cwd, options.out ?? "tokens");
|
|
2256
|
+
await mkdir5(outDir, { recursive: true });
|
|
2257
|
+
for (const mode of ["light", "dark"]) {
|
|
2258
|
+
const url = new URL("/api/tokens", registryUrl);
|
|
2259
|
+
url.searchParams.set("mode", mode);
|
|
2260
|
+
if (brand) url.searchParams.set("brand", brand);
|
|
2261
|
+
let response;
|
|
2262
|
+
try {
|
|
2263
|
+
response = await fetch(url);
|
|
2264
|
+
} catch {
|
|
2265
|
+
throw new DigError(`\u0627\u062A\u0635\u0627\u0644 \u0628\u0647 ${url.origin} \u0628\u0631\u0627\u06CC \u06AF\u0631\u0641\u062A\u0646\u0650 \u062A\u0648\u06A9\u0646\u200C\u0647\u0627 \u0628\u0631\u0642\u0631\u0627\u0631 \u0646\u0634\u062F.`);
|
|
2266
|
+
}
|
|
2267
|
+
if (!response.ok) {
|
|
2268
|
+
const body = await response.json().catch(() => null);
|
|
2269
|
+
throw new DigError(`\u062A\u0648\u06A9\u0646\u200C\u0647\u0627 \u06AF\u0631\u0641\u062A\u0647 \u0646\u0634\u062F: ${body?.error ?? response.status}`);
|
|
2270
|
+
}
|
|
2271
|
+
const file = path13.join(outDir, `dig-${mode}.tokens.json`);
|
|
2272
|
+
await writeFile7(file, await response.text(), "utf8");
|
|
2273
|
+
console.log(`\u2713 ${path13.relative(cwd, file)} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F${brand ? ` (\u0628\u0631\u0646\u062F ${brand})` : ""}.`);
|
|
2274
|
+
}
|
|
2275
|
+
console.log("\n\u062F\u0631 \u0641\u06CC\u06AF\u0645\u0627 \u0647\u0631 \u0641\u0627\u06CC\u0644 \u0631\u0627 \u06CC\u06A9 mode \u0627\u0632 Variables \u0648\u0627\u0631\u062F \u06A9\u0646\u06CC\u062F (\u0631\u0648\u0634\u0646 \u0648 \u062A\u06CC\u0631\u0647).");
|
|
2276
|
+
}
|
|
2277
|
+
|
|
2057
2278
|
// src/commands/init.ts
|
|
2058
|
-
import { readFile as
|
|
2059
|
-
import
|
|
2279
|
+
import { readFile as readFile12, writeFile as writeFile10 } from "fs/promises";
|
|
2280
|
+
import path17 from "path";
|
|
2060
2281
|
|
|
2061
2282
|
// src/lib/agent-instructions.ts
|
|
2062
|
-
import { readFile as
|
|
2063
|
-
import
|
|
2283
|
+
import { mkdir as mkdir6, readFile as readFile10, writeFile as writeFile8 } from "fs/promises";
|
|
2284
|
+
import path14 from "path";
|
|
2064
2285
|
var AGENT_CLIENTS = [
|
|
2065
2286
|
{ value: "claude-code", label: "Claude Code (CLAUDE.md)" },
|
|
2066
2287
|
{ value: "codex", label: "Codex (AGENTS.md)" },
|
|
@@ -2075,7 +2296,7 @@ var FONTS = [
|
|
|
2075
2296
|
];
|
|
2076
2297
|
var BLOCK_START = "<!-- dig:start";
|
|
2077
2298
|
var BLOCK_END = "<!-- dig:end -->";
|
|
2078
|
-
async function
|
|
2299
|
+
async function fetchSetupFiles(registryUrl, options) {
|
|
2079
2300
|
const url = new URL("/api/agent-setup", registryUrl);
|
|
2080
2301
|
if (options.agent) url.searchParams.set("client", options.agent);
|
|
2081
2302
|
for (const key2 of ["brand", "font", "name"]) {
|
|
@@ -2089,11 +2310,10 @@ async function fetchInstructionsFile(registryUrl, options) {
|
|
|
2089
2310
|
throw new DigError(`\u0627\u062A\u0635\u0627\u0644 \u0628\u0647 ${url.origin} \u0628\u0631\u0627\u06CC \u0633\u0627\u062E\u062A\u0646\u0650 \u0641\u0627\u06CC\u0644\u0650 \u0627\u06CC\u062C\u0646\u062A \u0628\u0631\u0642\u0631\u0627\u0631 \u0646\u0634\u062F.`);
|
|
2090
2311
|
}
|
|
2091
2312
|
const body = await response.json().catch(() => null);
|
|
2092
|
-
|
|
2093
|
-
if (!response.ok || !file) {
|
|
2313
|
+
if (!response.ok || !body?.files?.length) {
|
|
2094
2314
|
throw new DigError(`\u0641\u0627\u06CC\u0644\u0650 \u0627\u06CC\u062C\u0646\u062A \u0633\u0627\u062E\u062A\u0647 \u0646\u0634\u062F: ${body?.error ?? response.status}`);
|
|
2095
2315
|
}
|
|
2096
|
-
return
|
|
2316
|
+
return body.files;
|
|
2097
2317
|
}
|
|
2098
2318
|
function mergeInstructions(existing, block) {
|
|
2099
2319
|
const trimmed = block.trim();
|
|
@@ -2110,19 +2330,28 @@ ${trimmed}
|
|
|
2110
2330
|
`;
|
|
2111
2331
|
}
|
|
2112
2332
|
async function writeAgentInstructions(cwd, registryUrl, options) {
|
|
2113
|
-
const
|
|
2114
|
-
const
|
|
2115
|
-
|
|
2116
|
-
|
|
2333
|
+
const files = await fetchSetupFiles(registryUrl, options);
|
|
2334
|
+
const instructions = files.find((item) => /^[A-Z]+\.md$/.test(item.path) && item.path !== "DESIGN.md");
|
|
2335
|
+
if (!instructions) throw new DigError("\u0641\u0627\u06CC\u0644\u0650 \u0627\u06CC\u062C\u0646\u062A \u062F\u0631 \u067E\u0627\u0633\u062E\u0650 \u0633\u0631\u0648\u0631 \u0646\u0628\u0648\u062F.");
|
|
2336
|
+
const target = path14.join(cwd, instructions.path);
|
|
2337
|
+
const existing = await readFile10(target, "utf8").catch(() => null);
|
|
2338
|
+
await writeFile8(target, mergeInstructions(existing, instructions.content), "utf8");
|
|
2117
2339
|
console.log(
|
|
2118
|
-
existing === null ? `\u2713 ${
|
|
2340
|
+
existing === null ? `\u2713 ${instructions.path} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F (\u0627\u06CC\u062C\u0646\u062A \u0641\u0648\u0646\u062A \u0648 \u0631\u0646\u06AF \u0631\u0627 \u0627\u0632 \u0627\u06CC\u0646 \u0641\u0627\u06CC\u0644 \u0645\u06CC\u200C\u062E\u0648\u0627\u0646\u062F \u0648 \u062F\u0648\u0628\u0627\u0631\u0647 \u0646\u0645\u06CC\u200C\u067E\u0631\u0633\u062F).` : `\u2713 \u0628\u062E\u0634\u0650 \u062F\u06CC\u06AF \u062F\u0631 ${instructions.path} \u0628\u0647\u200C\u0631\u0648\u0632 \u0634\u062F\u061B \u0628\u0642\u06CC\u0647\u0654 \u0641\u0627\u06CC\u0644 \u062F\u0633\u062A \u0646\u062E\u0648\u0631\u062F.`
|
|
2119
2341
|
);
|
|
2120
|
-
|
|
2342
|
+
const skill = files.find((item) => item.path.endsWith("/SKILL.md"));
|
|
2343
|
+
if (skill) {
|
|
2344
|
+
const skillTarget = path14.join(cwd, skill.path);
|
|
2345
|
+
await mkdir6(path14.dirname(skillTarget), { recursive: true });
|
|
2346
|
+
await writeFile8(skillTarget, skill.content, "utf8");
|
|
2347
|
+
console.log(`\u2713 ${skill.path} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F (Skill\u0650 \u0631\u0633\u0645\u06CC\u0650 \u062F\u06CC\u06AF \u0628\u0631\u0627\u06CC \u0633\u0627\u062E\u062A\u0646\u0650 \u0635\u0641\u062D\u0647).`);
|
|
2348
|
+
}
|
|
2349
|
+
return instructions.path;
|
|
2121
2350
|
}
|
|
2122
2351
|
|
|
2123
2352
|
// src/commands/theme.ts
|
|
2124
|
-
import { access as access5, mkdir as
|
|
2125
|
-
import
|
|
2353
|
+
import { access as access5, mkdir as mkdir7, readFile as readFile11, writeFile as writeFile9 } from "fs/promises";
|
|
2354
|
+
import path16 from "path";
|
|
2126
2355
|
|
|
2127
2356
|
// src/lib/brand-ramp.ts
|
|
2128
2357
|
var RAMP_STEPS = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
|
|
@@ -2226,9 +2455,9 @@ function buildBrandRamp(hex) {
|
|
|
2226
2455
|
}
|
|
2227
2456
|
|
|
2228
2457
|
// src/lib/theme-files.ts
|
|
2229
|
-
import
|
|
2458
|
+
import path15 from "path";
|
|
2230
2459
|
function importPath(fromFile, toFile) {
|
|
2231
|
-
const rel = toPosixPath(
|
|
2460
|
+
const rel = toPosixPath(path15.relative(path15.dirname(fromFile), toFile));
|
|
2232
2461
|
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
2233
2462
|
}
|
|
2234
2463
|
function globalsCss(paths, extraStatements = []) {
|
|
@@ -2393,7 +2622,7 @@ function splitTheme(projectCss, digThemeCss) {
|
|
|
2393
2622
|
var THEME_ITEM = "theme";
|
|
2394
2623
|
async function readIfExists2(target) {
|
|
2395
2624
|
try {
|
|
2396
|
-
return await
|
|
2625
|
+
return await readFile11(target, "utf8");
|
|
2397
2626
|
} catch {
|
|
2398
2627
|
return null;
|
|
2399
2628
|
}
|
|
@@ -2407,7 +2636,7 @@ async function exists(target) {
|
|
|
2407
2636
|
}
|
|
2408
2637
|
}
|
|
2409
2638
|
function themePaths(config) {
|
|
2410
|
-
const dir =
|
|
2639
|
+
const dir = path16.posix.dirname(toPosixPath(config.tailwind.css));
|
|
2411
2640
|
return {
|
|
2412
2641
|
css: config.tailwind.css,
|
|
2413
2642
|
theme: config.tailwind.theme ?? `${dir}/dig-theme.css`,
|
|
@@ -2441,9 +2670,9 @@ async function recordTheme(cwd, config, themeRel, item) {
|
|
|
2441
2670
|
await writeLock(lock, cwd);
|
|
2442
2671
|
}
|
|
2443
2672
|
async function writeText(cwd, rel, content) {
|
|
2444
|
-
const target =
|
|
2445
|
-
await
|
|
2446
|
-
await
|
|
2673
|
+
const target = path16.join(cwd, rel);
|
|
2674
|
+
await mkdir7(path16.dirname(target), { recursive: true });
|
|
2675
|
+
await writeFile9(target, content, "utf8");
|
|
2447
2676
|
}
|
|
2448
2677
|
async function installTheme(cwd, config, options) {
|
|
2449
2678
|
const paths = themePaths(config);
|
|
@@ -2451,7 +2680,7 @@ async function installTheme(cwd, config, options) {
|
|
|
2451
2680
|
const ramp = options.brand ? buildBrandRamp(options.brand) : void 0;
|
|
2452
2681
|
await writeText(cwd, paths.theme, item.content);
|
|
2453
2682
|
console.log(`\u2713 \u062A\u0645\u0650 \u062F\u06CC\u06AF \u062F\u0631 ${paths.theme} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F (\u0645\u0627\u0644\u0650 \u062F\u06CC\u06AF\u061B \u0628\u0627 \xABdig update theme\xBB \u0628\u0647\u200C\u0631\u0648\u0632 \u0645\u06CC\u200C\u0634\u0648\u062F).`);
|
|
2454
|
-
const existingBrand = await readIfExists2(
|
|
2683
|
+
const existingBrand = await readIfExists2(path16.join(cwd, paths.brand));
|
|
2455
2684
|
if (existingBrand === null) {
|
|
2456
2685
|
await writeText(cwd, paths.brand, brandCss({ ramp, hex: options.brand }));
|
|
2457
2686
|
console.log(`\u2713 ${paths.brand} \u0633\u0627\u062E\u062A\u0647 \u0634\u062F (\u0645\u0627\u0644\u0650 \u067E\u0631\u0648\u0698\u0647\u061B \u062F\u06CC\u06AF \u0647\u0631\u06AF\u0632 \u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC\u200C\u0627\u0634 \u0646\u0645\u06CC\u200C\u06A9\u0646\u062F).`);
|
|
@@ -2462,10 +2691,10 @@ async function installTheme(cwd, config, options) {
|
|
|
2462
2691
|
console.log(`- ${paths.brand} \u0627\u0632 \u0642\u0628\u0644 \u0647\u0633\u062A\u061B \u062F\u0633\u062A \u0646\u062E\u0648\u0631\u062F.`);
|
|
2463
2692
|
}
|
|
2464
2693
|
if (ramp) reportContrast(ramp.primaryContrast);
|
|
2465
|
-
const cssTarget =
|
|
2694
|
+
const cssTarget = path16.join(cwd, paths.css);
|
|
2466
2695
|
const existingCss = await readIfExists2(cssTarget);
|
|
2467
2696
|
if (!isBoilerplateCss(existingCss) && existingCss !== null) {
|
|
2468
|
-
await
|
|
2697
|
+
await writeFile9(`${cssTarget}.backup`, existingCss, "utf8");
|
|
2469
2698
|
console.log(` \u0646\u0633\u062E\u0647\u0654 \u0642\u0628\u0644\u06CC\u0650 ${paths.css} \u062F\u0631 ${paths.css}.backup \u0646\u06AF\u0647 \u062F\u0627\u0634\u062A\u0647 \u0634\u062F.`);
|
|
2470
2699
|
console.log(` \u0627\u06AF\u0631 \u0622\u0646 \u0641\u0627\u06CC\u0644 \u062A\u0645\u0650 \u0642\u062F\u06CC\u0645\u06CC\u0650 \u062F\u06CC\u06AF \u0628\u0648\u062F\u060C \u0628\u0647\u200C\u062C\u0627\u06CC init \u0627\u0632 \xABdig theme split\xBB \u0627\u0633\u062A\u0641\u0627\u062F\u0647 \u06A9\u0646\u06CC\u062F.`);
|
|
2471
2700
|
}
|
|
@@ -2498,11 +2727,11 @@ async function themeSplitCommand(options) {
|
|
|
2498
2727
|
return;
|
|
2499
2728
|
}
|
|
2500
2729
|
const paths = themePaths(config);
|
|
2501
|
-
const current = await readIfExists2(
|
|
2730
|
+
const current = await readIfExists2(path16.join(cwd, paths.css));
|
|
2502
2731
|
if (current === null || isBoilerplateCss(current)) {
|
|
2503
2732
|
throw new DigError(`${paths.css} \u062A\u0645\u06CC \u0646\u062F\u0627\u0631\u062F\u061B \u0628\u0631\u0627\u06CC \u0646\u0635\u0628\u0650 \u062A\u0627\u0632\u0647 \xABdig init\xBB \u0631\u0627 \u0627\u062C\u0631\u0627 \u06A9\u0646\u06CC\u062F.`);
|
|
2504
2733
|
}
|
|
2505
|
-
if (await exists(
|
|
2734
|
+
if (await exists(path16.join(cwd, paths.brand))) {
|
|
2506
2735
|
throw new DigError(`${paths.brand} \u0627\u0632 \u0642\u0628\u0644 \u0648\u062C\u0648\u062F \u062F\u0627\u0631\u062F\u061B \u0628\u0631\u0627\u06CC \u062C\u0644\u0648\u06AF\u06CC\u0631\u06CC \u0627\u0632 \u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC\u060C \u0627\u0648\u0644 \u062C\u0627\u0628\u0647\u200C\u062C\u0627\u06CC\u0634 \u06A9\u0646\u06CC\u062F.`);
|
|
2507
2736
|
}
|
|
2508
2737
|
console.log(`\u062F\u0631\u06CC\u0627\u0641\u062A\u0650 \u062A\u0645\u0650 \u062F\u06CC\u06AF \u0627\u0632 ${config.registryUrl} \u2026`);
|
|
@@ -2521,7 +2750,7 @@ ${split.changed} \u062A\u0648\u06A9\u0646\u0650 \u0639\u0648\u0636\u200C\u0634\u
|
|
|
2521
2750
|
console.log(split.body || "(\u062E\u0627\u0644\u06CC: \u067E\u0631\u0648\u0698\u0647 \u0686\u06CC\u0632\u06CC \u062F\u0631 \u062A\u0645 \u0639\u0648\u0636 \u0646\u06A9\u0631\u062F\u0647)");
|
|
2522
2751
|
return;
|
|
2523
2752
|
}
|
|
2524
|
-
await
|
|
2753
|
+
await writeFile9(path16.join(cwd, `${paths.css}.backup`), current, "utf8");
|
|
2525
2754
|
await writeText(cwd, paths.theme, item.content);
|
|
2526
2755
|
await writeText(cwd, paths.brand, brandCss({ body: split.body }));
|
|
2527
2756
|
await writeText(cwd, paths.css, globalsCss(paths, split.extraStatements));
|
|
@@ -2545,7 +2774,7 @@ async function themeBrandCommand(hex) {
|
|
|
2545
2774
|
}
|
|
2546
2775
|
const paths = themePaths(config);
|
|
2547
2776
|
const ramp = buildBrandRamp(hex);
|
|
2548
|
-
const existing = await readIfExists2(
|
|
2777
|
+
const existing = await readIfExists2(path16.join(cwd, paths.brand)) ?? brandCss({});
|
|
2549
2778
|
const next = replaceBrandRamp(existing, ramp, hex);
|
|
2550
2779
|
await writeText(cwd, paths.brand, next);
|
|
2551
2780
|
console.log(`\u2713 \u0631\u0645\u067E\u0650 \u0628\u0631\u0646\u062F \u062F\u0631 ${paths.brand} \u0627\u0632 ${hex} \u0633\u0627\u062E\u062A\u0647 \u0634\u062F (Shade \u06F6\u06F0\u06F0 = \u0631\u0646\u06AF\u0650 \u062F\u0627\u062F\u0647\u200C\u0634\u062F\u0647).`);
|
|
@@ -2563,14 +2792,14 @@ async function themeBrandCommand(hex) {
|
|
|
2563
2792
|
// src/commands/init.ts
|
|
2564
2793
|
async function readIfExists3(target) {
|
|
2565
2794
|
try {
|
|
2566
|
-
return await
|
|
2795
|
+
return await readFile12(target, "utf8");
|
|
2567
2796
|
} catch {
|
|
2568
2797
|
return null;
|
|
2569
2798
|
}
|
|
2570
2799
|
}
|
|
2571
2800
|
async function writeTheme(config, cwd, options) {
|
|
2572
2801
|
const paths = themePaths(config);
|
|
2573
|
-
const existing = await readIfExists3(
|
|
2802
|
+
const existing = await readIfExists3(path17.join(cwd, paths.css));
|
|
2574
2803
|
if (!isBoilerplateCss(existing) && !options.yes) {
|
|
2575
2804
|
console.log(`
|
|
2576
2805
|
${paths.css} \u0627\u0632 \u0642\u0628\u0644 \u0645\u062D\u062A\u0648\u0627 \u062F\u0627\u0631\u062F.`);
|
|
@@ -2595,7 +2824,7 @@ ${paths.css} \u0627\u0632 \u0642\u0628\u0644 \u0645\u062D\u062A\u0648\u0627 \u06
|
|
|
2595
2824
|
}
|
|
2596
2825
|
async function applyRtl(cwd) {
|
|
2597
2826
|
for (const candidate of ["src/app/layout.tsx", "app/layout.tsx"]) {
|
|
2598
|
-
const target =
|
|
2827
|
+
const target = path17.join(cwd, candidate);
|
|
2599
2828
|
const source = await readIfExists3(target);
|
|
2600
2829
|
if (source === null) continue;
|
|
2601
2830
|
if (/<html[^>]*\sdir=/.test(source)) {
|
|
@@ -2608,7 +2837,7 @@ async function applyRtl(cwd) {
|
|
|
2608
2837
|
match[0],
|
|
2609
2838
|
`<html${match[1]} dir="rtl">`.replace(/\s+dir="rtl">$/, ' dir="rtl">')
|
|
2610
2839
|
);
|
|
2611
|
-
await
|
|
2840
|
+
await writeFile10(target, updated, "utf8");
|
|
2612
2841
|
console.log(`\u2713 dir="rtl" \u0628\u0647 ${candidate} \u0627\u0636\u0627\u0641\u0647 \u0634\u062F.`);
|
|
2613
2842
|
return;
|
|
2614
2843
|
}
|
|
@@ -2640,14 +2869,14 @@ async function initCommand(options) {
|
|
|
2640
2869
|
rtl: await confirm("\u067E\u0631\u0648\u0698\u0647 \u0631\u0627\u0633\u062A\u200C\u0628\u0647\u200C\u0686\u067E (RTL) \u0627\u0633\u062A\u061F", base.rtl),
|
|
2641
2870
|
tailwind: await (async () => {
|
|
2642
2871
|
const css = await ask("\u0645\u0633\u06CC\u0631 \u0641\u0627\u06CC\u0644 CSS \u0627\u0635\u0644\u06CC \u062A\u06CC\u0644\u0648\u06CC\u0646\u062F\u061F", base.tailwind.css);
|
|
2643
|
-
const dir =
|
|
2872
|
+
const dir = path17.posix.dirname(css.split(path17.sep).join("/"));
|
|
2644
2873
|
return { ...base.tailwind, css, theme: `${dir}/dig-theme.css`, brand: `${dir}/brand.css` };
|
|
2645
2874
|
})()
|
|
2646
2875
|
};
|
|
2647
2876
|
const decisions = await askProjectDecisions(options);
|
|
2648
2877
|
options = { ...options, brand: decisions.brand };
|
|
2649
2878
|
await writeConfig(config, cwd);
|
|
2650
|
-
console.log(`\u2713 ${
|
|
2879
|
+
console.log(`\u2713 ${path17.join(cwd, "dig.json")} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F.`);
|
|
2651
2880
|
const theme2 = await writeTheme(config, cwd, options);
|
|
2652
2881
|
if (config.rtl) {
|
|
2653
2882
|
await applyRtl(cwd);
|
|
@@ -2671,102 +2900,9 @@ async function initCommand(options) {
|
|
|
2671
2900
|
}
|
|
2672
2901
|
}
|
|
2673
2902
|
|
|
2674
|
-
// src/commands/mcp.ts
|
|
2675
|
-
import { createInterface as createInterface2 } from "readline";
|
|
2676
|
-
|
|
2677
|
-
// src/lib/version.ts
|
|
2678
|
-
var CLI_VERSION = "0.6.1";
|
|
2679
|
-
|
|
2680
|
-
// src/commands/mcp.ts
|
|
2681
|
-
var DEFAULT_MCP_URL = "https://docs.digdesign.ir/api/mcp";
|
|
2682
|
-
function parseSse(body) {
|
|
2683
|
-
const messages = [];
|
|
2684
|
-
for (const event of body.split(/\r?\n\r?\n/)) {
|
|
2685
|
-
const data = event.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).replace(/^ /, "")).join("\n");
|
|
2686
|
-
if (!data) continue;
|
|
2687
|
-
try {
|
|
2688
|
-
messages.push(JSON.parse(data));
|
|
2689
|
-
} catch {
|
|
2690
|
-
}
|
|
2691
|
-
}
|
|
2692
|
-
return messages;
|
|
2693
|
-
}
|
|
2694
|
-
function requestIds(message) {
|
|
2695
|
-
const list = Array.isArray(message) ? message : [message];
|
|
2696
|
-
return list.filter((item) => typeof item === "object" && item !== null).filter((item) => item.method !== void 0 && item.id !== void 0 && item.id !== null).map((item) => item.id);
|
|
2697
|
-
}
|
|
2698
|
-
function createBridge(url, fetchImpl = fetch) {
|
|
2699
|
-
let sessionId;
|
|
2700
|
-
let protocolVersion;
|
|
2701
|
-
return {
|
|
2702
|
-
async handle(line) {
|
|
2703
|
-
let message;
|
|
2704
|
-
try {
|
|
2705
|
-
message = JSON.parse(line);
|
|
2706
|
-
} catch {
|
|
2707
|
-
return [{ jsonrpc: "2.0", id: null, error: { code: -32700, message: "Parse error" } }];
|
|
2708
|
-
}
|
|
2709
|
-
const ids = requestIds(message);
|
|
2710
|
-
const fail = (reason) => ids.map((id) => ({ jsonrpc: "2.0", id, error: { code: -32603, message: `Dig MCP (${url}): ${reason}` } }));
|
|
2711
|
-
let response;
|
|
2712
|
-
try {
|
|
2713
|
-
response = await fetchImpl(url, {
|
|
2714
|
-
method: "POST",
|
|
2715
|
-
headers: {
|
|
2716
|
-
"content-type": "application/json",
|
|
2717
|
-
accept: "application/json, text/event-stream",
|
|
2718
|
-
"user-agent": `digdesign-cli/${CLI_VERSION}`,
|
|
2719
|
-
...sessionId && { "mcp-session-id": sessionId },
|
|
2720
|
-
...protocolVersion && { "mcp-protocol-version": protocolVersion }
|
|
2721
|
-
},
|
|
2722
|
-
body: line
|
|
2723
|
-
});
|
|
2724
|
-
} catch (error) {
|
|
2725
|
-
return fail(`network error: ${error.message}`);
|
|
2726
|
-
}
|
|
2727
|
-
sessionId = response.headers.get("mcp-session-id") ?? sessionId;
|
|
2728
|
-
if (response.status === 202) return [];
|
|
2729
|
-
const body = await response.text();
|
|
2730
|
-
if (!response.ok) return fail(`HTTP ${response.status} ${body.slice(0, 200)}`);
|
|
2731
|
-
let replies;
|
|
2732
|
-
if ((response.headers.get("content-type") ?? "").includes("text/event-stream")) replies = parseSse(body);
|
|
2733
|
-
else {
|
|
2734
|
-
try {
|
|
2735
|
-
replies = body.trim() ? [JSON.parse(body)] : [];
|
|
2736
|
-
} catch {
|
|
2737
|
-
return fail(`invalid JSON response: ${body.slice(0, 200)}`);
|
|
2738
|
-
}
|
|
2739
|
-
}
|
|
2740
|
-
for (const reply of replies.flat()) {
|
|
2741
|
-
const result = reply?.result;
|
|
2742
|
-
if (result?.protocolVersion) protocolVersion = result.protocolVersion;
|
|
2743
|
-
}
|
|
2744
|
-
return replies;
|
|
2745
|
-
}
|
|
2746
|
-
};
|
|
2747
|
-
}
|
|
2748
|
-
async function mcpCommand(options) {
|
|
2749
|
-
const url = options.url ?? process.env.DIG_MCP_URL ?? DEFAULT_MCP_URL;
|
|
2750
|
-
const bridge = createBridge(url);
|
|
2751
|
-
const pending = /* @__PURE__ */ new Set();
|
|
2752
|
-
process.stderr.write(`dig mcp: stdio bridge to ${url}
|
|
2753
|
-
`);
|
|
2754
|
-
const input = createInterface2({ input: process.stdin, crlfDelay: Infinity });
|
|
2755
|
-
for await (const line of input) {
|
|
2756
|
-
if (!line.trim()) continue;
|
|
2757
|
-
const task = bridge.handle(line).then((replies) => {
|
|
2758
|
-
for (const reply of replies) process.stdout.write(`${JSON.stringify(reply)}
|
|
2759
|
-
`);
|
|
2760
|
-
});
|
|
2761
|
-
pending.add(task);
|
|
2762
|
-
void task.finally(() => pending.delete(task));
|
|
2763
|
-
}
|
|
2764
|
-
await Promise.all(pending);
|
|
2765
|
-
}
|
|
2766
|
-
|
|
2767
2903
|
// src/lib/migration-apply.ts
|
|
2768
|
-
import { readFile as
|
|
2769
|
-
import
|
|
2904
|
+
import { readFile as readFile13, writeFile as writeFile11 } from "fs/promises";
|
|
2905
|
+
import path18 from "path";
|
|
2770
2906
|
|
|
2771
2907
|
// src/lib/migration-strategy.ts
|
|
2772
2908
|
var TextReplaceStrategy = class {
|
|
@@ -2843,7 +2979,7 @@ function looksBinary2(buffer) {
|
|
|
2843
2979
|
async function readTextFileSafely2(target) {
|
|
2844
2980
|
let buffer;
|
|
2845
2981
|
try {
|
|
2846
|
-
buffer = await
|
|
2982
|
+
buffer = await readFile13(target);
|
|
2847
2983
|
} catch (error) {
|
|
2848
2984
|
if (error.code === "ENOENT") return void 0;
|
|
2849
2985
|
throw error;
|
|
@@ -2888,8 +3024,8 @@ async function planOrApplyMigrations(params) {
|
|
|
2888
3024
|
};
|
|
2889
3025
|
}
|
|
2890
3026
|
const fileTargets = registryItem.files.map((file) => {
|
|
2891
|
-
const target =
|
|
2892
|
-
return { relPath: toPosixPath(
|
|
3027
|
+
const target = path18.join(cwd, resolveTargetPath(file.path, aliases, paths));
|
|
3028
|
+
return { relPath: toPosixPath(path18.relative(cwd, target)), target };
|
|
2893
3029
|
});
|
|
2894
3030
|
const currentContents = /* @__PURE__ */ new Map();
|
|
2895
3031
|
for (const ft of fileTargets) {
|
|
@@ -2955,12 +3091,12 @@ async function planOrApplyMigrations(params) {
|
|
|
2955
3091
|
const written = [];
|
|
2956
3092
|
try {
|
|
2957
3093
|
for (const item of pending) {
|
|
2958
|
-
await
|
|
3094
|
+
await writeFile11(item.target, item.newContent, "utf8");
|
|
2959
3095
|
written.push(item);
|
|
2960
3096
|
}
|
|
2961
3097
|
} catch (error) {
|
|
2962
3098
|
for (const item of written) {
|
|
2963
|
-
await
|
|
3099
|
+
await writeFile11(item.target, item.originalContent, "utf8");
|
|
2964
3100
|
}
|
|
2965
3101
|
return {
|
|
2966
3102
|
name,
|
|
@@ -3573,7 +3709,7 @@ ${entry.migrationHint}`);
|
|
|
3573
3709
|
|
|
3574
3710
|
// src/lib/missing-dependencies.ts
|
|
3575
3711
|
import { access as access6 } from "fs/promises";
|
|
3576
|
-
import
|
|
3712
|
+
import path19 from "path";
|
|
3577
3713
|
async function exists2(target) {
|
|
3578
3714
|
try {
|
|
3579
3715
|
await access6(target);
|
|
@@ -3594,7 +3730,7 @@ async function findMissingDependencies(params) {
|
|
|
3594
3730
|
for (const item of tree.values()) {
|
|
3595
3731
|
if (requested.has(item.name) || lock.components[item.name]) continue;
|
|
3596
3732
|
for (const file of item.files) {
|
|
3597
|
-
const target =
|
|
3733
|
+
const target = path19.join(
|
|
3598
3734
|
cwd,
|
|
3599
3735
|
resolveTargetPath(file.path, config.aliases, targetPathOptions(config))
|
|
3600
3736
|
);
|
|
@@ -3608,8 +3744,8 @@ async function findMissingDependencies(params) {
|
|
|
3608
3744
|
}
|
|
3609
3745
|
|
|
3610
3746
|
// src/lib/update.ts
|
|
3611
|
-
import { mkdir as
|
|
3612
|
-
import
|
|
3747
|
+
import { mkdir as mkdir8, readFile as readFile14, rm as rm2, writeFile as writeFile12 } from "fs/promises";
|
|
3748
|
+
import path20 from "path";
|
|
3613
3749
|
function safeFileIndexes(drift) {
|
|
3614
3750
|
const indexes = [];
|
|
3615
3751
|
drift.files.forEach((file, index) => {
|
|
@@ -3629,7 +3765,7 @@ async function applySafeFiles(cwd, aliases, drift, registryItem, dryRun, paths)
|
|
|
3629
3765
|
for (const index of safeIndexes) {
|
|
3630
3766
|
const file = drift.files[index];
|
|
3631
3767
|
const registryFile = registryItem.files[index];
|
|
3632
|
-
const target =
|
|
3768
|
+
const target = path20.join(cwd, resolveTargetPath(registryFile.path, aliases, paths));
|
|
3633
3769
|
const isNewFile = file.status === "new_upstream";
|
|
3634
3770
|
pending.push({
|
|
3635
3771
|
index,
|
|
@@ -3637,14 +3773,14 @@ async function applySafeFiles(cwd, aliases, drift, registryItem, dryRun, paths)
|
|
|
3637
3773
|
newContent: registryFile.content,
|
|
3638
3774
|
newHash: registryFile.hash ?? hashContent(registryFile.content),
|
|
3639
3775
|
isNewFile,
|
|
3640
|
-
originalContent: isNewFile ? void 0 : await
|
|
3776
|
+
originalContent: isNewFile ? void 0 : await readFile14(target, "utf8")
|
|
3641
3777
|
});
|
|
3642
3778
|
}
|
|
3643
3779
|
const written = [];
|
|
3644
3780
|
try {
|
|
3645
3781
|
for (const item of pending) {
|
|
3646
|
-
if (item.isNewFile) await
|
|
3647
|
-
await
|
|
3782
|
+
if (item.isNewFile) await mkdir8(path20.dirname(item.target), { recursive: true });
|
|
3783
|
+
await writeFile12(item.target, item.newContent, "utf8");
|
|
3648
3784
|
written.push(item);
|
|
3649
3785
|
}
|
|
3650
3786
|
} catch (error) {
|
|
@@ -3652,7 +3788,7 @@ async function applySafeFiles(cwd, aliases, drift, registryItem, dryRun, paths)
|
|
|
3652
3788
|
if (item.isNewFile) {
|
|
3653
3789
|
await rm2(item.target, { force: true });
|
|
3654
3790
|
} else {
|
|
3655
|
-
await
|
|
3791
|
+
await writeFile12(item.target, item.originalContent, "utf8");
|
|
3656
3792
|
}
|
|
3657
3793
|
}
|
|
3658
3794
|
return { actions, writtenHashes: {}, rollbackError: error.message };
|
|
@@ -3981,7 +4117,10 @@ program.name("dig").description("CLI \u0631\u0633\u0645\u06CC \u062F\u06CC\u0632
|
|
|
3981
4117
|
program.command("init").description(
|
|
3982
4118
|
'\u0631\u0627\u0647\u200C\u0627\u0646\u062F\u0627\u0632\u06CC \u062F\u06CC\u06AF \u062F\u0631 \u067E\u0631\u0648\u0698\u0647: dig.json\u060C \u062A\u0645 \u0648 \u062A\u0648\u06A9\u0646\u200C\u0647\u0627\u060C dir="rtl"\u060C DESIGN.md \u0648 \u0641\u0627\u06CC\u0644\u0650 \u062F\u0633\u062A\u0648\u0631\u0650 \u06A9\u0627\u0631\u06CC\u0650 \u0627\u06CC\u062C\u0646\u062A'
|
|
3983
4119
|
).option("--yes", "\u067E\u0627\u0633\u062E \u067E\u06CC\u0634\u200C\u0641\u0631\u0636 \u0628\u0647 \u0647\u0645\u0647\u0654 \u0633\u0648\u0627\u0644\u0627\u062A", false).option("--brand <hex>", "\u0633\u0627\u062E\u062A\u0646\u0650 \u0631\u0645\u067E\u0650 \u0628\u0631\u0646\u062F \u0627\u0632 \u06CC\u06A9 \u0631\u0646\u06AF (\u0631\u0648\u06CC Shade \u06F6\u06F0\u06F0 \u0645\u06CC\u200C\u0646\u0634\u06CC\u0646\u062F)\u060C \u0645\u062B\u0644 #2C4C5B").option("--font <font>", "\u0641\u0648\u0646\u062A: iransans\u060C yekan \u06CC\u0627 vazirmatn").option("--agent <agent>", "\u0627\u06CC\u062C\u0646\u062A: claude-code\u060C codex\u060C cursor\u060C vscode \u06CC\u0627 gemini (\u0646\u0627\u0645\u0650 \u0641\u0627\u06CC\u0644\u0650 \u062F\u0633\u062A\u0648\u0631\u0650 \u06A9\u0627\u0631\u06CC \u0631\u0627 \u062A\u0639\u06CC\u06CC\u0646 \u0645\u06CC\u200C\u06A9\u0646\u062F)").action(initCommand);
|
|
4120
|
+
program.command("tokens").description("\u062A\u0648\u06A9\u0646\u200C\u0647\u0627\u06CC \u062F\u06CC\u06AF \u062F\u0631 \u0642\u0627\u0644\u0628\u0650 \u0627\u0633\u062A\u0627\u0646\u062F\u0627\u0631\u062F\u0650 DTCG \u0628\u0631\u0627\u06CC \u0641\u06CC\u06AF\u0645\u0627 \u0648 \u0627\u0628\u0632\u0627\u0631\u0647\u0627\u06CC \u0637\u0631\u0627\u062D\u06CC\u060C \u06CC\u06A9 \u0641\u0627\u06CC\u0644 \u0628\u0631\u0627\u06CC \u0647\u0631 \u062D\u0627\u0644\u062A").option("--brand <hex>", "\u0631\u0646\u06AF \u0628\u0631\u0646\u062F\u061B \u067E\u06CC\u0634\u200C\u0641\u0631\u0636 \u0627\u0632 DESIGN.md\u0650 \u067E\u0631\u0648\u0698\u0647").option("--out <dir>", "\u067E\u0648\u0634\u0647\u0654 \u062E\u0631\u0648\u062C\u06CC (\u067E\u06CC\u0634\u200C\u0641\u0631\u0636 tokens)").action(tokensCommand);
|
|
4121
|
+
program.command("skill").description("\u06AF\u0630\u0627\u0634\u062A\u0646 \u06CC\u0627 \u0628\u0647\u200C\u0631\u0648\u0632\u06A9\u0631\u062F\u0646\u0650 Skill\u0650 \u0631\u0633\u0645\u06CC\u0650 \u062F\u06CC\u06AF \u0628\u0631\u0627\u06CC Claude Code \u062F\u0631 .claude/skills").action(skillCommand);
|
|
3984
4122
|
program.command("design-md").description("\u0633\u0627\u062E\u062A\u0646\u0650 DESIGN.md \u062F\u0631 \u0631\u06CC\u0634\u0647\u0654 \u067E\u0631\u0648\u0698\u0647: \u062A\u0648\u06A9\u0646\u200C\u0647\u0627 \u0648 \u0642\u0627\u0639\u062F\u0647\u200C\u0647\u0627\u06CC \u062F\u06CC\u06AF \u0628\u0631\u0627\u06CC \u0627\u06CC\u062C\u0646\u062A\u200C\u0647\u0627\u06CC \u06A9\u062F\u0646\u0648\u06CC\u0633").option("--brand <hex>", "\u0631\u0646\u06AF \u0628\u0631\u0646\u062F \u062A\u0627 \u0631\u0646\u06AF\u200C\u0647\u0627\u06CC \u0648\u0627\u0642\u0639\u06CC\u0650 \u0628\u0631\u0646\u062F \u062F\u0631 \u0641\u0627\u06CC\u0644 \u0628\u06CC\u0627\u06CC\u062F\u060C \u0645\u062B\u0644 #2C4C5B").option("--secondary <hex>", "\u0631\u0646\u06AF \u062F\u0648\u0645\u0650 \u0628\u0631\u0646\u062F").option("--name <name>", "\u0646\u0627\u0645 \u0645\u062D\u0635\u0648\u0644").option("--font <font>", "\u0641\u0648\u0646\u062A: iransans\u060C yekan \u06CC\u0627 vazirmatn").option("--radius <radius>", "\u0634\u0639\u0627\u0639: none\u060C sm\u060C md\u060C lg\u060C xl \u06CC\u0627 full").option("--force", "\u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC\u0650 DESIGN.md\u0650 \u062F\u0633\u062A\u200C\u0646\u0648\u0634\u062A\u0647", false).action(designMdCommand);
|
|
4123
|
+
program.command("review").description("\u0628\u0627\u0632\u0628\u06CC\u0646\u06CC\u0650 \u0641\u0627\u06CC\u0644\u200C\u0647\u0627\u06CC \u0631\u0627\u0628\u0637 \u0628\u0627 \u0642\u0648\u0627\u0639\u062F \u062F\u06CC\u06AF (\u0647\u0645\u0627\u0646 review_code \u062F\u0631 MCP)\u060C \u0628\u0627 \u0634\u0645\u0627\u0631\u0647\u0654 \u062E\u0637\u0650 \u0647\u0631 \u06CC\u0627\u0641\u062A\u0647").argument("<paths...>", "\u0645\u0633\u06CC\u0631 \u0641\u0627\u06CC\u0644\u200C\u0647\u0627\u06CC tsx/jsx").option("--url <url>", "\u0622\u062F\u0631\u0633 \u0633\u0631\u0648\u0631 MCP (\u067E\u06CC\u0634\u200C\u0641\u0631\u0636 https://docs.digdesign.ir/api/mcp)").option("--json", "\u062E\u0631\u0648\u062C\u06CC JSON \u0628\u0631\u0627\u06CC \u0627\u0633\u06A9\u0631\u06CC\u067E\u062A/\u0627\u0628\u0632\u0627\u0631", false).action(reviewCommand);
|
|
3985
4124
|
var theme = program.command("theme").description("\u062A\u0645 \u0648 \u0628\u0631\u0646\u062F: \u062C\u062F\u0627 \u06A9\u0631\u062F\u0646\u0650 \u062A\u0645\u0650 \u062F\u06CC\u06AF \u0627\u0632 \u0628\u0631\u0646\u062F\u0650 \u067E\u0631\u0648\u0698\u0647");
|
|
3986
4125
|
theme.command("split").description("\u067E\u0631\u0648\u0698\u0647\u0654 \u0642\u062F\u06CC\u0645\u06CC \u0631\u0627 \u0628\u0647 \u0633\u0627\u062E\u062A\u0627\u0631\u0650 \u062F\u0648\u0641\u0627\u06CC\u0644\u06CC \u0645\u06CC\u200C\u0628\u0631\u062F (dig-theme.css \u0645\u0627\u0644\u0650 \u062F\u06CC\u06AF\u060C brand.css \u0645\u0627\u0644\u0650 \u067E\u0631\u0648\u0698\u0647)").option("--dry-run", "\u0641\u0642\u0637 \u0646\u0634\u0627\u0646 \u0628\u062F\u0647 \u0686\u0647 \u0686\u06CC\u0632\u06CC \u0628\u0647 brand.css \u0645\u06CC\u200C\u0631\u0648\u062F\u060C \u0686\u06CC\u0632\u06CC \u0646\u0646\u0648\u06CC\u0633", false).action(themeSplitCommand);
|
|
3987
4126
|
theme.command("brand").description("\u0631\u0645\u067E\u0650 \u0628\u0631\u0646\u062F \u0631\u0627 \u062F\u0631 brand.css \u0627\u0632 \u06CC\u06A9 \u0631\u0646\u06AF \u0645\u06CC\u200C\u0633\u0627\u0632\u062F\u061B \u0628\u0642\u06CC\u0647\u0654 \u0641\u0627\u06CC\u0644 \u062F\u0633\u062A \u0646\u0645\u06CC\u200C\u062E\u0648\u0631\u062F").argument("<hex>", "\u0631\u0646\u06AF\u0650 \u0627\u0635\u0644\u06CC\u0650 \u0628\u0631\u0646\u062F\u060C \u0645\u062B\u0644 #2C4C5B").action(themeBrandCommand);
|