synapse-compiler 0.0.0-stage → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -2
- package/dist/causal-build.d.ts +51 -0
- package/dist/causal-graph.d.ts +6 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +1276 -0
- package/dist/core/config.d.ts +16 -0
- package/dist/core/engine.d.ts +17 -0
- package/dist/core/reporter.d.ts +5 -0
- package/dist/i18n.d.ts +281 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +1973 -0
- package/dist/plugins/cpp.d.ts +19 -0
- package/dist/plugins/csharp.d.ts +13 -0
- package/dist/plugins/go.d.ts +15 -0
- package/dist/plugins/java.d.ts +16 -0
- package/dist/plugins/native.d.ts +12 -0
- package/dist/plugins/nsis.d.ts +8 -0
- package/dist/plugins/python.d.ts +21 -0
- package/dist/plugins/rust.d.ts +9 -0
- package/dist/plugins/schema.d.ts +12 -0
- package/dist/plugins/svelte.d.ts +10 -0
- package/dist/plugins/typescript.d.ts +23 -0
- package/dist/types.d.ts +72 -0
- package/package.json +41 -4
package/dist/index.js
ADDED
|
@@ -0,0 +1,1973 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// core/config.ts
|
|
3
|
+
import { resolve } from "path";
|
|
4
|
+
import { existsSync } from "fs";
|
|
5
|
+
function defineConfig(config) {
|
|
6
|
+
return config;
|
|
7
|
+
}
|
|
8
|
+
function createCheckerPlugin(plugin) {
|
|
9
|
+
return plugin;
|
|
10
|
+
}
|
|
11
|
+
var CONFIG_FILENAMES = [
|
|
12
|
+
"synapse.config.ts",
|
|
13
|
+
"synapse.config.js",
|
|
14
|
+
"synapse.config.mjs"
|
|
15
|
+
];
|
|
16
|
+
async function loadSynapseConfig(targetDir = process.cwd()) {
|
|
17
|
+
for (const filename of CONFIG_FILENAMES) {
|
|
18
|
+
const candidate = resolve(targetDir, filename);
|
|
19
|
+
if (existsSync(candidate)) {
|
|
20
|
+
try {
|
|
21
|
+
const imported = await import(candidate);
|
|
22
|
+
const config = imported.default || imported;
|
|
23
|
+
return {
|
|
24
|
+
config: {
|
|
25
|
+
...config,
|
|
26
|
+
rootDir: config.rootDir ? resolve(targetDir, config.rootDir) : targetDir
|
|
27
|
+
},
|
|
28
|
+
configPath: candidate
|
|
29
|
+
};
|
|
30
|
+
} catch (error) {
|
|
31
|
+
throw new Error(`\uC124\uC815 \uD30C\uC77C(${candidate}) \uB85C\uB529 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4: ${error instanceof Error ? error.message : String(error)}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
throw new Error(`\uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8(${targetDir})\uC5D0\uC11C synapse.config.ts \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.
|
|
36
|
+
` + `'synapse init' \uBA85\uB839\uC5B4\uB97C \uC2E4\uD589\uD558\uC5EC \uAE30\uBCF8 \uC124\uC815 \uD30C\uC77C\uC744 \uC0DD\uC131\uD574 \uC8FC\uC138\uC694.`);
|
|
37
|
+
}
|
|
38
|
+
// core/engine.ts
|
|
39
|
+
var {spawn: spawn2 } = globalThis.Bun;
|
|
40
|
+
import { existsSync as existsSync3, readdirSync, watch } from "fs";
|
|
41
|
+
import { resolve as resolve3 } from "path";
|
|
42
|
+
|
|
43
|
+
// causal-build.ts
|
|
44
|
+
var {spawn } = globalThis.Bun;
|
|
45
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync, statSync } from "fs";
|
|
46
|
+
import { resolve as resolve2 } from "path";
|
|
47
|
+
import { createHash } from "crypto";
|
|
48
|
+
function loadBuildCache(rootDir) {
|
|
49
|
+
const cacheFile = resolve2(rootDir, ".synapse/build-cache.json");
|
|
50
|
+
try {
|
|
51
|
+
if (existsSync2(cacheFile)) {
|
|
52
|
+
const content = readFileSync(cacheFile, "utf-8");
|
|
53
|
+
const parsed = JSON.parse(content);
|
|
54
|
+
return {
|
|
55
|
+
lastVerifiedHead: parsed.lastVerifiedHead,
|
|
56
|
+
tracks: parsed.tracks || {},
|
|
57
|
+
sign: parsed.sign
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
} catch {}
|
|
61
|
+
return { tracks: {} };
|
|
62
|
+
}
|
|
63
|
+
function saveBuildCache(rootDir, cache) {
|
|
64
|
+
const cacheDir = resolve2(rootDir, ".synapse");
|
|
65
|
+
const cacheFile = resolve2(cacheDir, "build-cache.json");
|
|
66
|
+
try {
|
|
67
|
+
if (!existsSync2(cacheDir)) {
|
|
68
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
69
|
+
}
|
|
70
|
+
writeFileSync(cacheFile, JSON.stringify(cache, null, 2), "utf-8");
|
|
71
|
+
} catch {}
|
|
72
|
+
}
|
|
73
|
+
async function getGitState(rootDir) {
|
|
74
|
+
try {
|
|
75
|
+
const rootProc = spawn(["git", "rev-parse", "--show-toplevel"], { cwd: rootDir, stdout: "pipe" });
|
|
76
|
+
const repoRoot = (await new Response(rootProc.stdout).text()).trim().replaceAll("\\", "/");
|
|
77
|
+
await rootProc.exited;
|
|
78
|
+
const headProc = spawn(["git", "rev-parse", "HEAD"], { cwd: rootDir, stdout: "pipe" });
|
|
79
|
+
const head = (await new Response(headProc.stdout).text()).trim();
|
|
80
|
+
await headProc.exited;
|
|
81
|
+
const statusProc = spawn(["git", "status", "--porcelain", "-uall"], { cwd: rootDir, stdout: "pipe" });
|
|
82
|
+
const statusText = await new Response(statusProc.stdout).text();
|
|
83
|
+
await statusProc.exited;
|
|
84
|
+
const modifiedFiles = statusText.split(`
|
|
85
|
+
`).map((line) => line.slice(3).trim().replaceAll("\\", "/")).filter((line) => line.length > 0 && !line.startsWith(".synapse/") && !line.includes("/.synapse/"));
|
|
86
|
+
return { head, modifiedFiles, repoRoot: repoRoot || rootDir };
|
|
87
|
+
} catch {
|
|
88
|
+
return { head: "unknown", modifiedFiles: [], repoRoot: rootDir };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function shouldSkipBuildTrack(track, rootDir, repoRoot, cache, modifiedFiles, isForce) {
|
|
92
|
+
if (isForce) {
|
|
93
|
+
return { skip: false, reason: "\uAC15\uC81C \uBE4C\uB4DC \uBAA8\uB4DC(--force)" };
|
|
94
|
+
}
|
|
95
|
+
const artifacts = track.artifacts || [];
|
|
96
|
+
if (artifacts.length > 0) {
|
|
97
|
+
for (const art of artifacts) {
|
|
98
|
+
const fullPath = resolve2(track.cwd || rootDir, art);
|
|
99
|
+
if (!existsSync2(fullPath)) {
|
|
100
|
+
return { skip: false, reason: `\uC0B0\uCD9C\uBB3C \uB204\uB77D: ${art}` };
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const record = cache.tracks[track.name];
|
|
105
|
+
if (!record) {
|
|
106
|
+
return { skip: false, reason: "\uCD08\uAE30 \uBE4C\uB4DC \uAE30\uB85D \uC5C6\uC74C" };
|
|
107
|
+
}
|
|
108
|
+
const sources = track.sources || [];
|
|
109
|
+
if (sources.length > 0) {
|
|
110
|
+
const lastBuildEpoch = new Date(record.lastBuildTime).getTime();
|
|
111
|
+
const hasModifiedSource = modifiedFiles.some((file) => {
|
|
112
|
+
const isMatch = sources.some((src) => file.includes(src.replaceAll("\\", "/")));
|
|
113
|
+
if (!isMatch)
|
|
114
|
+
return false;
|
|
115
|
+
const fullPath = resolve2(repoRoot, file);
|
|
116
|
+
if (existsSync2(fullPath)) {
|
|
117
|
+
try {
|
|
118
|
+
const stat = statSync(fullPath);
|
|
119
|
+
return stat.mtimeMs > lastBuildEpoch;
|
|
120
|
+
} catch {
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return true;
|
|
125
|
+
});
|
|
126
|
+
if (hasModifiedSource) {
|
|
127
|
+
return { skip: false, reason: "\uB9C8\uC9C0\uB9C9 \uBE4C\uB4DC \uC774\uD6C4 \uC18C\uC2A4 \uCF54\uB4DC \uBCC0\uACBD \uAC10\uC9C0" };
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return { skip: true, reason: "\uC778\uACFC\uC728 \uBA54\uBAA8\uB9AC \uC77C\uCE58 (\uC18C\uC2A4 \uBCC0\uACBD \uC5C6\uC74C)" };
|
|
131
|
+
}
|
|
132
|
+
function computeFileHash(filePath) {
|
|
133
|
+
try {
|
|
134
|
+
const buffer = readFileSync(filePath);
|
|
135
|
+
return createHash("sha256").update(buffer).digest("hex");
|
|
136
|
+
} catch {
|
|
137
|
+
return "";
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function shouldSkipSign(installerPath, signaturePath, cache, isForce) {
|
|
141
|
+
if (isForce) {
|
|
142
|
+
return { skip: false, reason: "\uAC15\uC81C \uC11C\uBA85 \uBAA8\uB4DC(--force)", currentHash: "" };
|
|
143
|
+
}
|
|
144
|
+
if (!existsSync2(installerPath)) {
|
|
145
|
+
return { skip: false, reason: "\uC11C\uBA85 \uB300\uC0C1 \uC778\uC2A4\uD1A8\uB7EC \uBBF8\uC874\uC7AC", currentHash: "" };
|
|
146
|
+
}
|
|
147
|
+
if (!existsSync2(signaturePath)) {
|
|
148
|
+
return { skip: false, reason: "\uAE30\uC874 \uC11C\uBA85(.sig) \uD30C\uC77C \uBBF8\uC874\uC7AC", currentHash: "" };
|
|
149
|
+
}
|
|
150
|
+
const currentHash = computeFileHash(installerPath);
|
|
151
|
+
if (!currentHash) {
|
|
152
|
+
return { skip: false, reason: "\uC778\uC2A4\uD1A8\uB7EC \uD574\uC2DC \uACC4\uC0B0 \uBD88\uAC00", currentHash: "" };
|
|
153
|
+
}
|
|
154
|
+
const record = cache.sign;
|
|
155
|
+
if (record && record.installerHash === currentHash && record.signaturePath === signaturePath) {
|
|
156
|
+
return { skip: true, reason: "\uC778\uC2A4\uD1A8\uB7EC \uBC14\uC774\uB108\uB9AC \uBD88\uBCC0 (\uC11C\uBA85 \uCE90\uC2DC \uC801\uC911)", currentHash };
|
|
157
|
+
}
|
|
158
|
+
return { skip: false, reason: "\uC778\uC2A4\uD1A8\uB7EC \uBC14\uC774\uB108\uB9AC \uBCC0\uACBD \uAC10\uC9C0", currentHash };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// i18n.ts
|
|
162
|
+
var currentLocale = "en";
|
|
163
|
+
var MESSAGES = {
|
|
164
|
+
ko: {
|
|
165
|
+
cliTitle: "\uD83E\uDDE0 Synapse Kit - AI-Native \uD1B5\uD569 \uCEF4\uD30C\uC77C, \uBE4C\uB4DC & \uD328\uD0A4\uC9D5 \uD504\uB808\uC784\uC6CC\uD06C",
|
|
166
|
+
cliUsage: "\uC0AC\uC6A9\uBC95:",
|
|
167
|
+
cliCommands: "\uD575\uC2EC \uBA85\uB839\uC5B4:",
|
|
168
|
+
cmdCheck: "\uB4F1\uB85D\uB41C \uD50C\uB7EC\uADF8\uC778 \uBB34\uACB0\uC131 \uAC80\uC99D (\uAE30\uBCF8: AI \uC778\uACFC\uC728 \uC2A4\uB9C8\uD2B8 \uAC80\uC0AC)",
|
|
169
|
+
cmdBuild: "\uB4F1\uB85D\uB41C buildTracks \uCD08\uACE0\uC18D \uC778\uACFC\uC728 \uBCD1\uB82C \uC99D\uBD84 \uBE4C\uB4DC (0\uCD08\uB300 \uCE90\uC2DC)",
|
|
170
|
+
cmdPackage: "\uB2E8\uC77C NSIS + zlib \uACE0\uC18D \uC778\uC2A4\uD1A8\uB7EC \uD328\uD0A4\uC9D5 \uBC88\uB4E4\uB7EC",
|
|
171
|
+
cmdSign: "\uC778\uACFC\uC728 \uC554\uD638\uD654 \uC11C\uBA85 \uC5D4\uC9C4 (Minisign / Ed25519)",
|
|
172
|
+
cmdInit: "\uD604\uC7AC \uB514\uB809\uD130\uB9AC\uC5D0 \uCD5C\uC801\uD654\uB41C synapse.config.ts \uC0DD\uC131",
|
|
173
|
+
cmdMemory: "\uC778\uACFC\uC728 \uBA54\uBAA8\uB9AC(Causal Memory) \uCD08\uACBD\uB7C9 \uACF5\uBA85 \uC870\uD68C, \uAD00\uB9AC \uBC0F \uB85C\uCEEC \uB370\uBAAC \uAD6C\uB3D9",
|
|
174
|
+
cliOptions: "\uC635\uC158:",
|
|
175
|
+
optAll: "\uC778\uACFC\uC728 \uC2A4\uD0B5\uC744 \uB044\uACE0 \uC804\uBC29\uC704 \uAC15\uC81C \uAC80\uC0AC",
|
|
176
|
+
optForce: "\uBE4C\uB4DC/\uC11C\uBA85 \uC2DC \uC778\uACFC\uC728 \uCE90\uC2DC\uB97C \uBB34\uC2DC\uD558\uACE0 \uAC15\uC81C \uC7AC\uC2E4\uD589",
|
|
177
|
+
optAgent: "AI \uC5D0\uC774\uC804\uD2B8(Claude Code, Antigravity \uB4F1) \uC5F0\uB3D9\uC6A9 \uAD6C\uC870\uD654\uB41C JSON \uCD9C\uB825",
|
|
178
|
+
optCompact: "AI \uD1A0\uD070 \uADF9\uB2E8\uC801 \uCD5C\uC18C\uD654 \uBAA8\uB4DC (\uC131\uACF5 \uC2DC \uB2E8 11 \uD1A0\uD070)",
|
|
179
|
+
optInteractive: "\uC624\uB958 \uBC1C\uC0DD \uC2DC \uD504\uB85C\uC138\uC2A4\uB97C \uC77C\uC2DC\uC815\uC9C0\uD558\uACE0 \uC2E4\uC2DC\uAC04 \uCF54\uB4DC \uC218\uC815 \uB300\uAE30 (\uC778\uACFC \uD56B\uD53D\uC2A4)",
|
|
180
|
+
optWatch: "\uD30C\uC77C \uBCC0\uACBD \uAC10\uC9C0 \uBC31\uADF8\uB77C\uC6B4\uB4DC \uBAA8\uB4DC",
|
|
181
|
+
optLang: "\uCD9C\uB825 \uC5B8\uC5B4 \uAC15\uC81C \uC9C0\uC815 (ko | en)",
|
|
182
|
+
optHelp: "\uB3C4\uC6C0\uB9D0 \uD45C\uC2DC",
|
|
183
|
+
optVersion: "\uBC84\uC804 \uC815\uBCF4 \uD45C\uC2DC",
|
|
184
|
+
unknownCmd: "\uC54C \uC218 \uC5C6\uB294 \uBA85\uB839\uC5B4:",
|
|
185
|
+
errPrefix: "\uD83D\uDEA8 \uC624\uB958:",
|
|
186
|
+
configExists: "\uC774\uBBF8 \uC124\uC815 \uD30C\uC77C\uC774 \uC874\uC7AC\uD569\uB2C8\uB2E4:",
|
|
187
|
+
configCreated: "synapse.config.ts \uD15C\uD50C\uB9BF\uC774 \uC131\uACF5\uC801\uC73C\uB85C \uC0DD\uC131\uB418\uC5C8\uC2B5\uB2C8\uB2E4.",
|
|
188
|
+
checkHeader: "\uD83E\uDDE0 [Synapse Kit] AI-Native \uD1B5\uD569 \uCEF4\uD30C\uC77C & \uAC80\uC0AC \uD504\uB808\uC784\uC6CC\uD06C",
|
|
189
|
+
causalAll: "\uC804\uCCB4 \uAC80\uC0AC \uBAA8\uB4DC(--all) \uC694\uCCAD: \uBAA8\uB4E0 \uD50C\uB7EC\uADF8\uC778 \uAC80\uC0AC\uAE30\uB97C \uC2E4\uD589\uD569\uB2C8\uB2E4.",
|
|
190
|
+
causalDirty: (count, plugins) => `\uBCC0\uACBD\uB41C ${count}\uAC1C \uD30C\uC77C \uC778\uACFC \uBD84\uC11D \uC644\uB8CC: [${plugins}] \uD50C\uB7EC\uADF8\uC778\uB9CC \uC120\uBCC4 \uC2E4\uD589\uD569\uB2C8\uB2E4.`,
|
|
191
|
+
causalClean: "\uBCC0\uACBD\uB41C \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uBAA8\uB4E0 \uAC80\uC99D \uD50C\uB7EC\uADF8\uC778\uC744 0.00\uCD08 \uC2A4\uD0B5\uD569\uB2C8\uB2E4.",
|
|
192
|
+
causalCleanCacheHit: "\uC791\uC5C5 \uD2B8\uB9AC\uC5D0 \uBCC0\uACBD \uD30C\uC77C\uC774 \uC5C6\uC73C\uBA70 \uC774\uC804 \uAC80\uC99D \uD1B5\uACFC \uCEE4\uBC0B\uACFC \uC77C\uCE58\uD558\uC5EC 0.00\uCD08 \uC2A4\uD0B5\uD569\uB2C8\uB2E4.",
|
|
193
|
+
causalBaseline: "\uC791\uC5C5 \uD2B8\uB9AC\uC5D0 \uBCC0\uACBD\uB41C \uD30C\uC77C\uC774 \uC5C6\uC5B4 \uC804\uCCB4 \uBCA0\uC774\uC2A4\uB77C\uC778 \uAC80\uC99D\uC744 \uC218\uD589\uD569\uB2C8\uB2E4.",
|
|
194
|
+
causalUnrelated: (count) => `\uBCC0\uACBD\uB41C ${count}\uAC1C \uD30C\uC77C\uC774 \uB4F1\uB85D\uB41C \uAC80\uC0AC \uD50C\uB7EC\uADF8\uC778\uC758 \uC601\uD5A5 \uBC94\uC704\uC5D0 \uC18D\uD558\uC9C0 \uC54A\uC544 \uC804\uCCB4 \uAC80\uC0AC\uB97C \uC2A4\uD0B5\uD569\uB2C8\uB2E4.`,
|
|
195
|
+
causalGitFail: "Git \uBCC0\uACBD \uCD94\uC801 \uBD88\uAC00\uB85C \uC548\uC804 \uBAA8\uB4DC(\uC804\uCCB4 \uAC80\uC0AC)\uB97C \uC2E4\uD589\uD569\uB2C8\uB2E4.",
|
|
196
|
+
checkPassed: "\uD1B5\uACFC",
|
|
197
|
+
checkSkipped: "\uC0DD\uB7B5 (\uC778\uACFC\uC728 0\uCD08 \uC2A4\uD0B5)",
|
|
198
|
+
checkFailed: "\uC2E4\uD328",
|
|
199
|
+
checkSuccessSummary: (errs, warns, skips, sec) => `\u2728 \uC2DC\uB0C5\uC2A4 \uAC80\uC99D \uC131\uACF5: ${errs} Errors, ${warns} Warnings, ${skips} Skipped (\uCD1D \uC18C\uC694 \uC2DC\uAC04: ${sec}\uCD08)`,
|
|
200
|
+
checkFailureSummary: (errs, warns, sec) => `\u274C \uC2DC\uB0C5\uC2A4 \uAC80\uC99D \uC2E4\uD328: ${errs}\uAC1C \uAC80\uC0AC\uAE30 \uC624\uB958 \uBC1C\uC0DD (\uCD1D \uC18C\uC694 \uC2DC\uAC04: ${sec}\uCD08)`,
|
|
201
|
+
interactivePause: "\u23F8\uFE0F \uC5D0\uB7EC \uBC1C\uC0DD\uC73C\uB85C \uC77C\uC2DC\uC815\uC9C0\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uD30C\uC77C\uC744 \uC218\uC815\uD55C \uB4A4 \uC800\uC7A5\uD558\uBA74 0.05\uCD08 \uB9CC\uC5D0 \uD56B \uC7AC\uAC80\uC99D\uD569\uB2C8\uB2E4. (\uC885\uB8CC: Ctrl+C)",
|
|
202
|
+
interactiveReload: "\u26A1 \uD30C\uC77C \uBCC0\uACBD \uAC10\uC9C0! \uC778\uBA54\uBAA8\uB9AC \uD56B \uC7AC\uAC80\uC99D\uC744 \uC989\uC2DC \uAC00\uB3D9\uD569\uB2C8\uB2E4...",
|
|
203
|
+
interactiveTitle: "\u23F8\uFE0F [\uB300\uD654\uD615 \uC778\uACFC \uD56B\uD53D\uC2A4 \uBAA8\uB4DC] \uC624\uB958 \uBC1C\uC0DD\uC73C\uB85C \uD504\uB85C\uC138\uC2A4\uB97C \uC77C\uC2DC\uC815\uC9C0\uD588\uC2B5\uB2C8\uB2E4.",
|
|
204
|
+
interactiveTarget: "\uB300\uC0C1 \uD50C\uB7EC\uADF8\uC778",
|
|
205
|
+
interactiveWatching: "\uAC10\uC2DC \uC0C1\uD0DC : \uD83D\uDC40 \uC18C\uC2A4 \uCF54\uB4DC \uC218\uC815 \uB300\uAE30 \uC911... (\uC800\uC7A5 \uC2DC 0.05\uCD08 \uB9CC\uC5D0 \uD56B \uC7AC\uCEF4\uD30C\uC77C)",
|
|
206
|
+
interactiveExit: "\uC138\uC158 \uC885\uB8CC : \uD130\uBBF8\uB110\uC5D0\uC11C Ctrl+C \uC785\uB825",
|
|
207
|
+
interactiveDetected: (time, file) => `\u26A1 [\uC800\uC7A5 \uAC10\uC9C0 ${time}] ${file} \uC218\uC815 \uAC10\uC9C0 \u279C \uD56B \uC7AC\uCEF4\uD30C\uC77C \uC2E4\uD589 \uC911...`,
|
|
208
|
+
interactivePassed: (sec) => `\u2728 [\uD56B \uC7AC\uCEF4\uD30C\uC77C \uD1B5\uACFC] (${sec}s) \uACB0\uD568\uC774 \uC644\uC804\uD788 \uD574\uACB0\uB418\uC5C8\uC2B5\uB2C8\uB2E4!`,
|
|
209
|
+
interactiveResumed: "\u25B6\uFE0F [\uD30C\uC774\uD504\uB77C\uC778 \uC7AC\uAC1C] \uBAA8\uB4E0 \uAC80\uC99D \uD1B5\uACFC \uC644\uB8CC. \uD504\uB85C\uC138\uC2A4\uB97C \uC815\uC0C1 \uC885\uB8CC\uD569\uB2C8\uB2E4.",
|
|
210
|
+
interactiveFailed: "\u274C [\uC7AC\uAC80\uC99D \uC2E4\uD328] \uC5EC\uC804\uD788 \uC624\uB958\uAC00 \uB0A8\uC544\uC788\uC2B5\uB2C8\uB2E4. \uCF54\uB4DC\uB97C \uB2E4\uC2DC \uC218\uC815\uD558\uACE0 \uC800\uC7A5\uD574 \uC8FC\uC138\uC694.",
|
|
211
|
+
buildHeader: "\u26A1 [Synapse Build] \uC778\uACFC\uC728 \uBA40\uD2F0\uD2B8\uB799 \uBCD1\uB82C \uC99D\uBD84 \uBE4C\uB354",
|
|
212
|
+
buildSkipped: "\u23ED\uFE0F \uC18C\uC2A4 \uBBF8\uBCC0\uACBD \uAC10\uC9C0: 0.00\uCD08 \uC2A4\uD0B5",
|
|
213
|
+
buildSuccess: "\u2705 \uBE4C\uB4DC \uC644\uACB0",
|
|
214
|
+
buildFailed: "\u274C \uBE4C\uB4DC \uC2E4\uD328",
|
|
215
|
+
buildAllUpToDate: "\u2728 \uBAA8\uB4E0 \uBE4C\uB4DC \uD2B8\uB799\uC774 \uCD5C\uC2E0 \uC0C1\uD0DC\uC785\uB2C8\uB2E4. (\uC804\uCCB4 \uBE4C\uB4DC \uC0DD\uB7B5: 0.00\uCD08)",
|
|
216
|
+
buildComplete: (sec) => `\u2728 \uC804\uCCB4 \uC778\uACFC\uC728 \uC99D\uBD84 \uBE4C\uB4DC \uC644\uACB0 (\uCD1D \uC18C\uC694 \uC2DC\uAC04: ${sec}\uCD08)`,
|
|
217
|
+
packageHeader: "\uD83D\uDCE6 [Synapse Package] \uCD08\uACE0\uC18D \uC778\uC2A4\uD1A8\uB7EC \uBC88\uB4E4\uB7EC",
|
|
218
|
+
packageSuccess: (sec) => `\u2728 \uC778\uC2A4\uD1A8\uB7EC \uD328\uD0A4\uC9D5 \uC131\uACF5 (\uC18C\uC694 \uC2DC\uAC04: ${sec}\uCD08)`,
|
|
219
|
+
packageFailed: (sec) => `\u274C \uC778\uC2A4\uD1A8\uB7EC \uD328\uD0A4\uC9D5 \uC2E4\uD328 (\uC18C\uC694 \uC2DC\uAC04: ${sec}\uCD08)`,
|
|
220
|
+
signHeader: "\uD83D\uDD10 [Synapse Sign] \uC778\uACFC\uC728 \uC554\uD638\uD654 \uC11C\uBA85 \uD30C\uC774\uD504\uB77C\uC778",
|
|
221
|
+
signSkipped: "\u23ED\uFE0F \uC778\uC2A4\uD1A8\uB7EC \uBC14\uC774\uB108\uB9AC \uD574\uC2DC \uBD88\uBCC0: \uC11C\uBA85 0.00\uCD08 \uC2A4\uD0B5",
|
|
222
|
+
signSuccess: (sec) => `\u2728 \uC778\uC2A4\uD1A8\uB7EC Ed25519 \uB514\uC9C0\uD138 \uC11C\uBA85 \uBC1C\uD589 \uC644\uB8CC (\uC18C\uC694 \uC2DC\uAC04: ${sec}\uCD08)`,
|
|
223
|
+
signFailed: (sec) => `\u274C \uC11C\uBA85 \uC0DD\uC131 \uC2E4\uD328 (\uC18C\uC694 \uC2DC\uAC04: ${sec}\uCD08)`,
|
|
224
|
+
signNoConfig: "\u274C \uC11C\uBA85 \uC124\uC815(sign.privateKeyPath)\uC774 synapse.config.ts\uC5D0 \uC9C0\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.",
|
|
225
|
+
signNoKey: (p) => `\u274C \uC11C\uBA85 \uAC1C\uC778\uD0A4 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${p}`,
|
|
226
|
+
signNoInstaller: "\u274C \uC11C\uBA85 \uB300\uC0C1 \uC778\uC2A4\uD1A8\uB7EC(.exe) \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
227
|
+
signTarget: "\uB300\uC0C1 \uC778\uC2A4\uD1A8\uB7EC",
|
|
228
|
+
signStatus: "\uC11C\uBA85 \uC0C1\uD0DC",
|
|
229
|
+
signFile: "\uC11C\uBA85 \uD30C\uC77C",
|
|
230
|
+
signReasonLabel: "\uC11C\uBA85 \uC0AC\uC720",
|
|
231
|
+
signEngineLabel: "\uC11C\uBA85 \uC5D4\uC9C4",
|
|
232
|
+
signCacheHit: "\uC2A4\uD0B5 [\uC778\uACFC\uC728 \uCE90\uC2DC \uC801\uC911: \uBC14\uC774\uB108\uB9AC \uD574\uC2DC \uBD88\uBCC0]",
|
|
233
|
+
signExistingKeep: (p) => `\uAE30\uC874 \uC11C\uBA85 \uD30C\uC77C \uC720\uC9C0 (${p})`,
|
|
234
|
+
signIntegrityPass: "\u2728 \uC11C\uBA85 \uBB34\uACB0\uC131 \uD655\uC778 \uC644\uB8CC (0.00\uCD08)",
|
|
235
|
+
statusSuccess: "\uD1B5\uACFC",
|
|
236
|
+
statusSkipped: "\uC2A4\uD0B5 (\uC778\uACFC\uC728 \uC0DD\uB7B5)",
|
|
237
|
+
statusWarning: "\uACBD\uACE0",
|
|
238
|
+
statusError: "\uC2E4\uD328",
|
|
239
|
+
causalAnalysis: "\uC778\uACFC \uBA54\uBAA8\uB9AC \uBD84\uC11D",
|
|
240
|
+
trackSkipped: "\uC2A4\uD0B5 [\uC778\uACFC\uC728 \uCE90\uC2DC \uC801\uC911]",
|
|
241
|
+
trackComplete: "\uBE4C\uB4DC \uC644\uB8CC",
|
|
242
|
+
trackFailed: "\uBE4C\uB4DC \uC2E4\uD328",
|
|
243
|
+
noBuildTracks: "\u274C \uB4F1\uB85D\uB41C \uBE4C\uB4DC \uD2B8\uB799(buildTracks)\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. synapse.config.ts\uB97C \uD655\uC778\uD574 \uC8FC\uC138\uC694.",
|
|
244
|
+
buildSuccessSummary: (tracks, sec) => `\u2728 \uC778\uACFC\uC728 \uBCD1\uB82C \uBE4C\uB4DC \uC131\uACF5: \uC804\uCCB4 ${tracks}\uAC1C \uD2B8\uB799 \uC644\uB8CC (\uCD1D \uC18C\uC694 \uC2DC\uAC04: ${sec}\uCD08)`,
|
|
245
|
+
buildFailureSummary: "\uD83D\uDEA8 \uBCD1\uB82C \uBE4C\uB4DC \uC2E4\uD328: \uD558\uB098 \uC774\uC0C1\uC758 \uD2B8\uB799\uC5D0\uC11C \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.",
|
|
246
|
+
packagingPreBuild: "\u2139\uFE0F \uC0AC\uC804 \uC544\uD2F0\uD329\uD2B8 \uC778\uACFC\uC728 \uBE4C\uB4DC \uD655\uC778 \uC911...",
|
|
247
|
+
packagingStart: "\uD83D\uDE80 Tauri \uC778\uC2A4\uD1A8\uB7EC \uBC88\uB4E4\uB9C1 \uC2DC\uC791...",
|
|
248
|
+
packagingGuide: `\u26A0\uFE0F [\uD328\uD0A4\uC9D5 \uAC00\uC774\uB4DC] tauri.conf.json\uC758 targets\uAC00 "all"\uB85C \uC124\uC815\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4.
|
|
249
|
+
\u21B3 WiX MSI \uC911\uBCF5 \uBE4C\uB4DC\uB85C \uC2DC\uAC04\uC774 \uC18C\uC694\uB429\uB2C8\uB2E4. targets: ["nsis"] \uC124\uC815\uC744 \uAD8C\uC7A5\uD569\uB2C8\uB2E4.`,
|
|
250
|
+
pluginRustTitle: "Rust \uBC31\uC5D4\uB4DC \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 (Check & Clippy)",
|
|
251
|
+
pluginRustSuccess: "Rust \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uCEF4\uD30C\uC77C \uBC0F Clippy \uBB34\uACB0\uC131 \uD655\uC778 \uC644\uB8CC (0 Warnings, 0 Errors)",
|
|
252
|
+
pluginRustClippyWarn: (count) => `\uCEF4\uD30C\uC77C \uD1B5\uACFC \uC644\uB8CC (${count}\uAC1C Clippy \uAD8C\uC7A5\uC0AC\uD56D \uAC10\uC9C0\uB428)`,
|
|
253
|
+
pluginRustCompileFail: "Rust \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uCEF4\uD30C\uC77C\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.",
|
|
254
|
+
pluginRustExecFail: (msg) => `Rust \uAC80\uC0AC \uB3C4\uAD6C \uC2E4\uD589 \uC2E4\uD328: ${msg}`,
|
|
255
|
+
pluginSvelteTitle: "Svelte 5 & TypeScript (svelte-check)",
|
|
256
|
+
pluginSvelteSuccess: "Svelte 5 Runes \uBC0F TS \uD0C0\uC785 \uBB34\uACB0\uC131 \uAC80\uC99D \uC644\uB8CC (0 Errors, 0 Warnings)",
|
|
257
|
+
pluginSvelteError: "Svelte \uD15C\uD50C\uB9BF \uB610\uB294 TypeScript \uD0C0\uC785 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.",
|
|
258
|
+
pluginSvelteExecFail: (msg) => `Svelte \uAC80\uC0AC \uB3C4\uAD6C \uC2E4\uD589 \uC2E4\uD328: ${msg}`,
|
|
259
|
+
pluginJavaTitle: "Java \uC5D4\uD130\uD504\uB77C\uC774\uC988 \uCEF4\uD30C\uC77C\uB7EC (javac)",
|
|
260
|
+
pluginJavaSuccess: (count) => `Java ${count}\uAC1C \uC18C\uC2A4 \uD30C\uC77C \uBC14\uC774\uD2B8\uCF54\uB4DC \uCEF4\uD30C\uC77C \uBB34\uACB0\uC131 \uAC80\uC99D \uC644\uB8CC`,
|
|
261
|
+
pluginJavaNoFiles: "\uAC80\uC99D\uD560 Java \uC18C\uC2A4 \uD30C\uC77C(.java)\uC774 \uC874\uC7AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
|
|
262
|
+
pluginJavaError: "javac \uCEF4\uD30C\uC77C \uC2E4\uD328",
|
|
263
|
+
pluginCppTitle: "C/C++ \uB124\uC774\uD2F0\uBE0C \uCEE4\uB110 \uAC80\uC99D\uAE30 (g++/clang++)",
|
|
264
|
+
pluginCppSuccess: (count) => `C/C++ ${count}\uAC1C \uC18C\uC2A4 \uD30C\uC77C \uAD6C\uBB38 \uBC0F \uD5E4\uB354 \uBB34\uACB0\uC131 \uAC80\uC99D \uC644\uB8CC`,
|
|
265
|
+
pluginCppNoFiles: "\uAC80\uC99D\uD560 C/C++ \uC18C\uC2A4 \uD30C\uC77C\uC774 \uC874\uC7AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
|
|
266
|
+
pluginCppError: "C/C++ \uAD6C\uBB38 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.",
|
|
267
|
+
pluginCsharpTitle: "C# .NET \uC194\uB8E8\uC158 \uAC80\uC99D\uAE30 (dotnet build)",
|
|
268
|
+
pluginCsharpSuccess: "C# .NET \uD504\uB85C\uC81D\uD2B8 \uBE4C\uB4DC \uBC0F \uD0C0\uC785 \uBB34\uACB0\uC131 \uAC80\uC99D \uC644\uB8CC",
|
|
269
|
+
pluginCsharpError: "C# .NET \uBE4C\uB4DC \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.",
|
|
270
|
+
pluginGoTitle: "Go \uBC31\uC5D4\uB4DC \uD328\uD0A4\uC9C0 \uAC80\uC99D\uAE30 (go vet)",
|
|
271
|
+
pluginGoSuccess: "Go \uB3D9\uC2DC\uC131 \uB8E8\uD2F4 \uBC0F \uD328\uD0A4\uC9C0 \uC815\uC801 \uBD84\uC11D \uD1B5\uACFC",
|
|
272
|
+
pluginGoError: "Go \uC815\uC801 \uBD84\uC11D \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.",
|
|
273
|
+
pluginPythonTitle: "Python \uBC14\uC774\uD2B8\uCF54\uB4DC \uAC80\uC99D\uAE30 (py_compile)",
|
|
274
|
+
pluginPythonSuccess: (count) => `Python ${count}\uAC1C \uBAA8\uB4C8 \uBC14\uC774\uD2B8\uCF54\uB4DC \uBB34\uACB0\uC131 \uAC80\uC99D \uC644\uB8CC`,
|
|
275
|
+
pluginPythonNoFiles: "\uAC80\uC99D\uD560 Python \uC18C\uC2A4 \uD30C\uC77C\uC774 \uC874\uC7AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
|
|
276
|
+
pluginPythonError: "Python \uAD6C\uBB38 \uBD84\uC11D \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.",
|
|
277
|
+
pluginTypescriptTitlePure: "\uC21C\uC218 TypeScript \uACF5\uC2DD \uCEF4\uD30C\uC77C\uB7EC (tsc)",
|
|
278
|
+
pluginTypescriptTitleNative: "TypeScript \uB124\uC774\uD2F0\uBE0C Rust Oxc (tsrs)",
|
|
279
|
+
pluginTypescriptSuccess: (mode) => `TypeScript \uD0C0\uC785 \uBB34\uACB0\uC131 \uAC80\uC99D \uC644\uB8CC (${mode})`,
|
|
280
|
+
pluginTypescriptError: "TypeScript \uD0C0\uC785 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.",
|
|
281
|
+
pluginSchemaTitle: "\uB370\uC774\uD130 \uBC0F \uC124\uC815 \uC2A4\uD0A4\uB9C8 \uBB34\uACB0\uC131 \uAC80\uC0AC",
|
|
282
|
+
pluginSchemaSuccess: (count) => `${count}\uAC1C \uC2A4\uD0A4\uB9C8/\uB370\uC774\uD130 \uD30C\uC77C \uC815\uC0C1 \uD655\uC778 \uC644\uB8CC`,
|
|
283
|
+
pluginSchemaParseFail: (path, err) => `${path} \uD30C\uC2F1 \uC2E4\uD328: ${err}`,
|
|
284
|
+
pluginNativeTitle: "\uB124\uC774\uD2F0\uBE0C \uBC14\uC774\uB108\uB9AC & \uC5D0\uC14B \uAC80\uC0AC",
|
|
285
|
+
pluginNativeSuccess: (count) => `${count}\uAC1C \uBC14\uC774\uB108\uB9AC \uBC0F \uB9AC\uC18C\uC2A4 \uBB34\uACB0\uC131 \uD655\uC778 \uC644\uB8CC`,
|
|
286
|
+
pluginNativeMissing: (path) => `\uD544\uC218 \uBC14\uC774\uB108\uB9AC\uAC00 \uB204\uB77D\uB418\uC5C8\uC2B5\uB2C8\uB2E4: ${path}`,
|
|
287
|
+
pluginNativeNotPe: (path) => `${path}: \uC62C\uBC14\uB978 PE \uD3EC\uB9F7(MZ \uC2DC\uADF8\uB2C8\uCC98 \uB204\uB77D)\uC774 \uC544\uB2D9\uB2C8\uB2E4.`,
|
|
288
|
+
pluginNativeInvalidPe: (path) => `${path}: \uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 PE \uC2DC\uADF8\uB2C8\uCC98\uC785\uB2C8\uB2E4.`,
|
|
289
|
+
pluginNativeInvalidArch: (path, code) => `${path}: 64\uBE44\uD2B8(x64) \uBC14\uC774\uB108\uB9AC\uAC00 \uC544\uB2D9\uB2C8\uB2E4 (\uBA38\uC2E0 \uCF54\uB4DC: 0x${code}).`,
|
|
290
|
+
pluginNsisTitle: "NSIS \uC778\uC2A4\uD1A8\uB7EC \uD15C\uD50C\uB9BF \uAD6C\uBB38 \uAC80\uC0AC",
|
|
291
|
+
pluginNsisSuccess: (path) => `${path} \uAD6C\uBB38 \uBC0F \uD544\uC218 \uC9C0\uC2DC\uBB38 \uD655\uC778 \uC644\uB8CC`,
|
|
292
|
+
pluginNsisMissing: (path) => `NSIS \uD15C\uD50C\uB9BF \uD30C\uC77C\uC774 \uB204\uB77D\uB418\uC5C8\uC2B5\uB2C8\uB2E4: ${path}`,
|
|
293
|
+
pluginNsisCorrupt: "NSIS \uD15C\uD50C\uB9BF \uD30C\uC77C \uB0B4\uC6A9\uC774 \uBE44\uC5B4 \uC788\uAC70\uB098 \uC190\uC0C1\uB418\uC5C8\uC2B5\uB2C8\uB2E4.",
|
|
294
|
+
pluginNsisDirectiveMissing: (dir) => `NSIS \uD544\uC218 \uC9C0\uC2DC\uBB38 \uB204\uB77D: '${dir}' \uAD6C\uBB38\uC774 \uBC1C\uACAC\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.`
|
|
295
|
+
},
|
|
296
|
+
en: {
|
|
297
|
+
cliTitle: "\uD83E\uDDE0 Synapse Kit - AI-Native Unified Compiler, Build & Packaging Framework",
|
|
298
|
+
cliUsage: "Usage:",
|
|
299
|
+
cliCommands: "Core Commands:",
|
|
300
|
+
cmdCheck: "Run multi-track verification with AI causal smart skipping",
|
|
301
|
+
cmdBuild: "Fast incremental multi-track build (0.00s skip on unchanged sources)",
|
|
302
|
+
cmdPackage: "Single NSIS + zlib high-speed installer packager",
|
|
303
|
+
cmdSign: "Causal cryptographic signing engine (Minisign / Ed25519)",
|
|
304
|
+
cmdInit: "Generate optimized synapse.config.ts template in current directory",
|
|
305
|
+
cmdMemory: "Query, manage and serve zero-cost Causal Memory & Local Daemon",
|
|
306
|
+
cliOptions: "Options:",
|
|
307
|
+
optAll: "Disable causal skipping and force full verification",
|
|
308
|
+
optForce: "Ignore cache and force re-execution of build and signing",
|
|
309
|
+
optAgent: "Structured JSON output for AI coding agents (Claude, Cursor, Antigravity)",
|
|
310
|
+
optCompact: "Extreme token-diet mode for AI agents (only 11 tokens on pass)",
|
|
311
|
+
optInteractive: "Pause on error and wait for live code modification (0.05s live-fix)",
|
|
312
|
+
optWatch: "Background file-watcher mode",
|
|
313
|
+
optLang: "Force display language (ko | en)",
|
|
314
|
+
optHelp: "Display help information",
|
|
315
|
+
optVersion: "Display version information",
|
|
316
|
+
unknownCmd: "Unknown command:",
|
|
317
|
+
errPrefix: "\uD83D\uDEA8 Error:",
|
|
318
|
+
configExists: "Configuration file already exists:",
|
|
319
|
+
configCreated: "synapse.config.ts template created successfully.",
|
|
320
|
+
checkHeader: "\uD83E\uDDE0 [Synapse Kit] AI-Native Unified Compiler & Verification Framework",
|
|
321
|
+
causalAll: "Full check requested (--all): Executing all registered checkers.",
|
|
322
|
+
causalDirty: (count, plugins) => `${count} modified files detected: Running [${plugins}] plugins only.`,
|
|
323
|
+
causalClean: "No source changes detected. All checkers skipped in 0.00s.",
|
|
324
|
+
causalCleanCacheHit: "No file changes and matches last verified commit. Skipped in 0.00s.",
|
|
325
|
+
causalBaseline: "No changes detected; performing baseline verification for initial state.",
|
|
326
|
+
causalUnrelated: (count) => `${count} modified files do not affect registered plugins. Skipping all checkers.`,
|
|
327
|
+
causalGitFail: "Cannot track Git changes; running full verification in safe mode.",
|
|
328
|
+
checkPassed: "PASSED",
|
|
329
|
+
checkSkipped: "SKIPPED (Causal 0.00s)",
|
|
330
|
+
checkFailed: "FAILED",
|
|
331
|
+
checkSuccessSummary: (errs, warns, skips, sec) => `\u2728 Verification Passed: ${errs} Errors, ${warns} Warnings, ${skips} Skipped (Total: ${sec}s)`,
|
|
332
|
+
checkFailureSummary: (errs, warns, sec) => `\u274C Verification Failed: ${errs} check failures (Total: ${sec}s)`,
|
|
333
|
+
interactivePause: "\u23F8\uFE0F Paused due to errors. Save modified files to hot-recheck in 0.05s. (Exit: Ctrl+C)",
|
|
334
|
+
interactiveReload: "\u26A1 File changes detected! Launching in-memory hot-recheck...",
|
|
335
|
+
interactiveTitle: "\u23F8\uFE0F [Interactive Causal Hotfix] Process paused due to verification errors.",
|
|
336
|
+
interactiveTarget: "Target Plugins",
|
|
337
|
+
interactiveWatching: "Watch Status : \uD83D\uDC40 Waiting for code changes... (hot-rechecks in 0.05s on save)",
|
|
338
|
+
interactiveExit: "Exit Session : Press Ctrl+C in terminal",
|
|
339
|
+
interactiveDetected: (time, file) => `\u26A1 [Save Detected ${time}] ${file} changed \u279C Running hot-recheck...`,
|
|
340
|
+
interactivePassed: (sec) => `\u2728 [Hot-recheck Passed] (${sec}s) All issues resolved!`,
|
|
341
|
+
interactiveResumed: "\u25B6\uFE0F [Pipeline Resumed] All verifications passed. Exiting cleanly.",
|
|
342
|
+
interactiveFailed: "\u274C [Hot-recheck Failed] Errors remain. Please edit and save again.",
|
|
343
|
+
buildHeader: "\u26A1 [Synapse Build] Causal Multi-Track Parallel Incremental Builder",
|
|
344
|
+
buildSkipped: "\u23ED\uFE0F Unchanged source detected: 0.00s skipped",
|
|
345
|
+
buildSuccess: "\u2705 Build completed",
|
|
346
|
+
buildFailed: "\u274C Build failed",
|
|
347
|
+
buildAllUpToDate: "\u2728 All build tracks are up-to-date. (Skipped all tracks: 0.00s)",
|
|
348
|
+
buildComplete: (sec) => `\u2728 Causal incremental build completed (Total: ${sec}s)`,
|
|
349
|
+
packageHeader: "\uD83D\uDCE6 [Synapse Package] High-Speed Installer Bundler",
|
|
350
|
+
packageSuccess: (sec) => `\u2728 Installer package bundled successfully (Elapsed: ${sec}s)`,
|
|
351
|
+
packageFailed: (sec) => `\u274C Installer packaging failed (Elapsed: ${sec}s)`,
|
|
352
|
+
signHeader: "\uD83D\uDD10 [Synapse Sign] Causal Cryptographic Signing Pipeline",
|
|
353
|
+
signSkipped: "\u23ED\uFE0F Binary SHA-256 unchanged: Signature skipped in 0.00s",
|
|
354
|
+
signSuccess: (sec) => `\u2728 Ed25519 digital signature generated (Elapsed: ${sec}s)`,
|
|
355
|
+
signFailed: (sec) => `\u274C Signature generation failed (Elapsed: ${sec}s)`,
|
|
356
|
+
signNoConfig: "\u274C Signing configuration (sign.privateKeyPath) is missing in synapse.config.ts.",
|
|
357
|
+
signNoKey: (p) => `\u274C Signing private key not found: ${p}`,
|
|
358
|
+
signNoInstaller: "\u274C Target installer (.exe) not found for signing.",
|
|
359
|
+
signTarget: "Target Installer",
|
|
360
|
+
signStatus: "Signing Status",
|
|
361
|
+
signFile: "Signature File",
|
|
362
|
+
signReasonLabel: "Reason",
|
|
363
|
+
signEngineLabel: "Signing Engine",
|
|
364
|
+
signCacheHit: "SKIPPED [Causal Cache Hit: Binary hash identical]",
|
|
365
|
+
signExistingKeep: (p) => `Keeping existing signature file (${p})`,
|
|
366
|
+
signIntegrityPass: "\u2728 Signature integrity verified (0.00s)",
|
|
367
|
+
statusSuccess: "PASSED",
|
|
368
|
+
statusSkipped: "SKIPPED (Causal skip)",
|
|
369
|
+
statusWarning: "WARNING",
|
|
370
|
+
statusError: "FAILED",
|
|
371
|
+
causalAnalysis: "Causal Analysis",
|
|
372
|
+
trackSkipped: "SKIPPED [Causal Cache Hit]",
|
|
373
|
+
trackComplete: "Build Passed",
|
|
374
|
+
trackFailed: "Build Failed",
|
|
375
|
+
noBuildTracks: "\u274C No buildTracks found in synapse.config.ts.",
|
|
376
|
+
buildSuccessSummary: (tracks, sec) => `\u2728 Causal Parallel Build Passed: All ${tracks} tracks completed (Total: ${sec}s)`,
|
|
377
|
+
buildFailureSummary: "\uD83D\uDEA8 Parallel Build Failed: Errors occurred in one or more tracks.",
|
|
378
|
+
packagingPreBuild: "\u2139\uFE0F Verifying prerequisite artifact causal builds...",
|
|
379
|
+
packagingStart: "\uD83D\uDE80 Starting Tauri installer bundling...",
|
|
380
|
+
packagingGuide: `\u26A0\uFE0F [Packaging Notice] tauri.conf.json has targets set to "all".
|
|
381
|
+
\u21B3 WiX MSI adds redundant delay. Recommended setting: targets: ["nsis"].`,
|
|
382
|
+
pluginRustTitle: "Rust Backend Workspace (Check & Clippy)",
|
|
383
|
+
pluginRustSuccess: "Rust workspace compilation & Clippy integrity verified (0 Warnings, 0 Errors)",
|
|
384
|
+
pluginRustClippyWarn: (count) => `Compilation passed (${count} Clippy recommendations detected)`,
|
|
385
|
+
pluginRustCompileFail: "Rust workspace compilation failed.",
|
|
386
|
+
pluginRustExecFail: (msg) => `Failed to execute Rust checker tool: ${msg}`,
|
|
387
|
+
pluginSvelteTitle: "Svelte 5 & TypeScript (svelte-check)",
|
|
388
|
+
pluginSvelteSuccess: "Svelte 5 Runes & TS type integrity verified (0 Errors, 0 Warnings)",
|
|
389
|
+
pluginSvelteError: "Errors detected in Svelte template or TypeScript types.",
|
|
390
|
+
pluginSvelteExecFail: (msg) => `Failed to execute Svelte checker tool: ${msg}`,
|
|
391
|
+
pluginJavaTitle: "Java Enterprise Compiler (javac)",
|
|
392
|
+
pluginJavaSuccess: (count) => `Java bytecode compilation verified for ${count} source files`,
|
|
393
|
+
pluginJavaNoFiles: "No Java source files (*.java) found to verify.",
|
|
394
|
+
pluginJavaError: "javac compilation failed",
|
|
395
|
+
pluginCppTitle: "C/C++ Native Kernel Checker (g++/clang++)",
|
|
396
|
+
pluginCppSuccess: (count) => `C/C++ syntax & header integrity verified for ${count} files`,
|
|
397
|
+
pluginCppNoFiles: "No C/C++ source files found to verify.",
|
|
398
|
+
pluginCppError: "C/C++ compilation syntax errors detected.",
|
|
399
|
+
pluginCsharpTitle: "C# .NET Solution Checker (dotnet build)",
|
|
400
|
+
pluginCsharpSuccess: "C# .NET project build and type integrity verified",
|
|
401
|
+
pluginCsharpError: "Errors detected during C# .NET build.",
|
|
402
|
+
pluginGoTitle: "Go Backend Package Checker (go vet)",
|
|
403
|
+
pluginGoSuccess: "Go concurrency routines and packages passed static analysis",
|
|
404
|
+
pluginGoError: "Errors detected during Go static analysis.",
|
|
405
|
+
pluginPythonTitle: "Python Bytecode Checker (py_compile)",
|
|
406
|
+
pluginPythonSuccess: (count) => `Python bytecode integrity verified for ${count} modules`,
|
|
407
|
+
pluginPythonNoFiles: "No Python source files found to verify.",
|
|
408
|
+
pluginPythonError: "Syntax errors detected in Python source.",
|
|
409
|
+
pluginTypescriptTitlePure: "Pure TypeScript Official Compiler (tsc)",
|
|
410
|
+
pluginTypescriptTitleNative: "TypeScript Native Rust Oxc (tsrs)",
|
|
411
|
+
pluginTypescriptSuccess: (mode) => `TypeScript type integrity verified (${mode})`,
|
|
412
|
+
pluginTypescriptError: "TypeScript type errors detected.",
|
|
413
|
+
pluginSchemaTitle: "Data & Config Schema Integrity Checker",
|
|
414
|
+
pluginSchemaSuccess: (count) => `Verified ${count} schema/data files successfully`,
|
|
415
|
+
pluginSchemaParseFail: (path, err) => `${path} parse failure: ${err}`,
|
|
416
|
+
pluginNativeTitle: "Native Binary & Asset Checker",
|
|
417
|
+
pluginNativeSuccess: (count) => `Verified ${count} binaries & resources successfully`,
|
|
418
|
+
pluginNativeMissing: (path) => `Required binary is missing: ${path}`,
|
|
419
|
+
pluginNativeNotPe: (path) => `${path}: Not a valid PE format (MZ signature missing).`,
|
|
420
|
+
pluginNativeInvalidPe: (path) => `${path}: Invalid PE signature.`,
|
|
421
|
+
pluginNativeInvalidArch: (path, code) => `${path}: Not a 64-bit (x64) binary (Machine code: 0x${code}).`,
|
|
422
|
+
pluginNsisTitle: "NSIS Installer Template Checker",
|
|
423
|
+
pluginNsisSuccess: (path) => `${path} syntax & required directives verified`,
|
|
424
|
+
pluginNsisMissing: (path) => `NSIS template file is missing: ${path}`,
|
|
425
|
+
pluginNsisCorrupt: "NSIS template content is empty or corrupted.",
|
|
426
|
+
pluginNsisDirectiveMissing: (dir) => `Required NSIS directive missing: '${dir}'.`
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
function detectLocale(explicitLang) {
|
|
430
|
+
if (explicitLang === "ko" || explicitLang === "en") {
|
|
431
|
+
currentLocale = explicitLang;
|
|
432
|
+
return currentLocale;
|
|
433
|
+
}
|
|
434
|
+
const envLang = process.env.SYNAPSE_LANG || process.env.LANG || process.env.LC_ALL || process.env.LC_MESSAGES || "";
|
|
435
|
+
if (envLang.toLowerCase().includes("ko")) {
|
|
436
|
+
currentLocale = "ko";
|
|
437
|
+
return "ko";
|
|
438
|
+
}
|
|
439
|
+
try {
|
|
440
|
+
const sysLocale = Intl.DateTimeFormat().resolvedOptions().locale.toLowerCase();
|
|
441
|
+
if (sysLocale.startsWith("ko")) {
|
|
442
|
+
currentLocale = "ko";
|
|
443
|
+
return "ko";
|
|
444
|
+
}
|
|
445
|
+
} catch {}
|
|
446
|
+
currentLocale = "en";
|
|
447
|
+
return "en";
|
|
448
|
+
}
|
|
449
|
+
function setLocale(locale) {
|
|
450
|
+
currentLocale = locale;
|
|
451
|
+
}
|
|
452
|
+
function getLocale() {
|
|
453
|
+
return currentLocale;
|
|
454
|
+
}
|
|
455
|
+
function t(key, ...args) {
|
|
456
|
+
const dict = MESSAGES[currentLocale] || MESSAGES.en;
|
|
457
|
+
const val = dict[key] ?? MESSAGES.en[key] ?? key;
|
|
458
|
+
if (typeof val === "function") {
|
|
459
|
+
return val(...args);
|
|
460
|
+
}
|
|
461
|
+
return val;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// causal-graph.ts
|
|
465
|
+
async function analyzeCausalGraph(rootDir, plugins, options) {
|
|
466
|
+
const allPluginNames = new Set(plugins.map((p) => p.name));
|
|
467
|
+
if (options.mode === "all") {
|
|
468
|
+
return {
|
|
469
|
+
runAll: true,
|
|
470
|
+
activePluginNames: allPluginNames,
|
|
471
|
+
reason: t("causalAll"),
|
|
472
|
+
modifiedFiles: []
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
try {
|
|
476
|
+
const { head, modifiedFiles } = await getGitState(rootDir);
|
|
477
|
+
if (modifiedFiles.length === 0) {
|
|
478
|
+
const cache = loadBuildCache(rootDir);
|
|
479
|
+
if (cache.lastVerifiedHead && cache.lastVerifiedHead === head && head !== "unknown") {
|
|
480
|
+
return {
|
|
481
|
+
runAll: false,
|
|
482
|
+
activePluginNames: new Set,
|
|
483
|
+
reason: t("causalCleanCacheHit"),
|
|
484
|
+
modifiedFiles: []
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
return {
|
|
488
|
+
runAll: true,
|
|
489
|
+
activePluginNames: allPluginNames,
|
|
490
|
+
reason: t("causalBaseline"),
|
|
491
|
+
modifiedFiles: []
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
const activePluginNames = new Set;
|
|
495
|
+
for (const plugin of plugins) {
|
|
496
|
+
const isTriggered = plugin.triggers.some((pattern) => {
|
|
497
|
+
const cleanPattern = pattern.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
498
|
+
const isExtension = cleanPattern.startsWith(".");
|
|
499
|
+
return modifiedFiles.some((file) => {
|
|
500
|
+
if (isExtension) {
|
|
501
|
+
return file.endsWith(cleanPattern);
|
|
502
|
+
}
|
|
503
|
+
return file.includes(cleanPattern);
|
|
504
|
+
});
|
|
505
|
+
});
|
|
506
|
+
if (isTriggered) {
|
|
507
|
+
activePluginNames.add(plugin.name);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
if (activePluginNames.size === 0) {
|
|
511
|
+
return {
|
|
512
|
+
runAll: false,
|
|
513
|
+
activePluginNames: new Set,
|
|
514
|
+
reason: t("causalUnrelated", modifiedFiles.length),
|
|
515
|
+
modifiedFiles
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
return {
|
|
519
|
+
runAll: false,
|
|
520
|
+
activePluginNames,
|
|
521
|
+
reason: t("causalDirty", modifiedFiles.length, Array.from(activePluginNames).join(", ")),
|
|
522
|
+
modifiedFiles
|
|
523
|
+
};
|
|
524
|
+
} catch {
|
|
525
|
+
return {
|
|
526
|
+
runAll: true,
|
|
527
|
+
activePluginNames: allPluginNames,
|
|
528
|
+
reason: t("causalGitFail"),
|
|
529
|
+
modifiedFiles: []
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// core/reporter.ts
|
|
535
|
+
var RESET = "\x1B[0m";
|
|
536
|
+
var BOLD = "\x1B[1m";
|
|
537
|
+
var GREEN = "\x1B[32m";
|
|
538
|
+
var RED = "\x1B[31m";
|
|
539
|
+
var YELLOW = "\x1B[33m";
|
|
540
|
+
var CYAN = "\x1B[36m";
|
|
541
|
+
var GRAY = "\x1B[90m";
|
|
542
|
+
function reportResults(decision, results, totalDurationMs, options) {
|
|
543
|
+
const totalSeconds = (totalDurationMs / 1000).toFixed(2);
|
|
544
|
+
const errorResults = results.filter((r) => r.status === "error");
|
|
545
|
+
const warningResults = results.filter((r) => r.status === "warning");
|
|
546
|
+
const skippedResults = results.filter((r) => r.status === "skipped");
|
|
547
|
+
const successResults = results.filter((r) => r.status === "success");
|
|
548
|
+
if (options.agentMode || options.compactMode) {
|
|
549
|
+
const isCleanPass = errorResults.length === 0 && warningResults.length === 0;
|
|
550
|
+
if (isCleanPass && options.compactMode) {
|
|
551
|
+
const minimalPayload = {
|
|
552
|
+
ok: true,
|
|
553
|
+
duration: `${totalSeconds}s`,
|
|
554
|
+
skipped: skippedResults.map((r) => r.name)
|
|
555
|
+
};
|
|
556
|
+
process.stdout.write(`${JSON.stringify(minimalPayload)}
|
|
557
|
+
`);
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
const payload = {
|
|
561
|
+
ok: errorResults.length === 0,
|
|
562
|
+
duration: `${totalSeconds}s`,
|
|
563
|
+
summary: {
|
|
564
|
+
pass: successResults.length,
|
|
565
|
+
warn: warningResults.length,
|
|
566
|
+
err: errorResults.length,
|
|
567
|
+
skip: skippedResults.length
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
if (errorResults.length > 0) {
|
|
571
|
+
payload.errors = errorResults.map((r) => ({
|
|
572
|
+
plugin: r.name,
|
|
573
|
+
details: r.details,
|
|
574
|
+
diagnostics: r.diagnostics
|
|
575
|
+
}));
|
|
576
|
+
}
|
|
577
|
+
if (warningResults.length > 0) {
|
|
578
|
+
payload.warnings = warningResults.map((r) => ({
|
|
579
|
+
plugin: r.name,
|
|
580
|
+
details: r.details,
|
|
581
|
+
diagnostics: r.diagnostics
|
|
582
|
+
}));
|
|
583
|
+
}
|
|
584
|
+
if (skippedResults.length > 0) {
|
|
585
|
+
payload.skipped = skippedResults.map((r) => r.name);
|
|
586
|
+
}
|
|
587
|
+
const outputString = options.compactMode ? JSON.stringify(payload) : JSON.stringify(payload, null, 2);
|
|
588
|
+
process.stdout.write(`${outputString}
|
|
589
|
+
`);
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
const line = "\u2501".repeat(68);
|
|
593
|
+
process.stdout.write(`
|
|
594
|
+
${BOLD}${CYAN}${t("checkHeader")}${RESET}
|
|
595
|
+
`);
|
|
596
|
+
process.stdout.write(`${GRAY}${line}${RESET}
|
|
597
|
+
`);
|
|
598
|
+
process.stdout.write(`${GRAY}\uD83D\uDCA1 ${t("causalAnalysis")}: ${decision.reason}${RESET}
|
|
599
|
+
`);
|
|
600
|
+
process.stdout.write(`${GRAY}${line}${RESET}
|
|
601
|
+
`);
|
|
602
|
+
for (const result of results) {
|
|
603
|
+
const duration = (result.durationMs / 1000).toFixed(2);
|
|
604
|
+
let statusBadge = "";
|
|
605
|
+
switch (result.status) {
|
|
606
|
+
case "success":
|
|
607
|
+
statusBadge = `${GREEN}\u2705 ${t("statusSuccess")} (${duration}s)${RESET}`;
|
|
608
|
+
break;
|
|
609
|
+
case "skipped":
|
|
610
|
+
statusBadge = `${GRAY}\u23ED\uFE0F ${t("statusSkipped")}${RESET}`;
|
|
611
|
+
break;
|
|
612
|
+
case "warning":
|
|
613
|
+
statusBadge = `${YELLOW}\u26A0\uFE0F ${t("statusWarning")} (${duration}s)${RESET}`;
|
|
614
|
+
break;
|
|
615
|
+
case "error":
|
|
616
|
+
statusBadge = `${RED}\u274C ${t("statusError")} (${duration}s)${RESET}`;
|
|
617
|
+
break;
|
|
618
|
+
}
|
|
619
|
+
const titlePadded = result.title.padEnd(36, " ");
|
|
620
|
+
process.stdout.write(` \u2022 ${BOLD}${titlePadded}${RESET} : ${statusBadge}
|
|
621
|
+
`);
|
|
622
|
+
if (result.status !== "skipped" && result.details) {
|
|
623
|
+
process.stdout.write(` ${GRAY}\u2514\u2500 ${result.details}${RESET}
|
|
624
|
+
`);
|
|
625
|
+
}
|
|
626
|
+
if (result.diagnostics && result.diagnostics.length > 0) {
|
|
627
|
+
for (const diag of result.diagnostics) {
|
|
628
|
+
process.stdout.write(` ${RED}\u25B6 ${diag.message}${RESET}
|
|
629
|
+
`);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
process.stdout.write(`${GRAY}${line}${RESET}
|
|
634
|
+
`);
|
|
635
|
+
if (errorResults.length === 0) {
|
|
636
|
+
process.stdout.write(`${BOLD}${GREEN}${t("checkSuccessSummary", 0, warningResults.length, skippedResults.length, totalSeconds)}${RESET}
|
|
637
|
+
|
|
638
|
+
`);
|
|
639
|
+
} else {
|
|
640
|
+
process.stdout.write(`${BOLD}${RED}${t("checkFailureSummary", errorResults.length, warningResults.length, totalSeconds)}${RESET}
|
|
641
|
+
|
|
642
|
+
`);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// core/engine.ts
|
|
647
|
+
var RESET2 = "\x1B[0m";
|
|
648
|
+
var BOLD2 = "\x1B[1m";
|
|
649
|
+
var GREEN2 = "\x1B[32m";
|
|
650
|
+
var RED2 = "\x1B[31m";
|
|
651
|
+
var YELLOW2 = "\x1B[33m";
|
|
652
|
+
var CYAN2 = "\x1B[36m";
|
|
653
|
+
var GRAY2 = "\x1B[90m";
|
|
654
|
+
async function runPluginChecker(plugin, isActive, rootDir, options) {
|
|
655
|
+
if (!isActive) {
|
|
656
|
+
return {
|
|
657
|
+
name: plugin.name,
|
|
658
|
+
title: plugin.title,
|
|
659
|
+
status: "skipped",
|
|
660
|
+
durationMs: 0,
|
|
661
|
+
details: t("checkSkipped")
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
try {
|
|
665
|
+
return await plugin.check({ rootDir, options });
|
|
666
|
+
} catch (error) {
|
|
667
|
+
return {
|
|
668
|
+
name: plugin.name,
|
|
669
|
+
title: plugin.title,
|
|
670
|
+
status: "error",
|
|
671
|
+
durationMs: 0,
|
|
672
|
+
details: `Critical plugin execution failure: ${error instanceof Error ? error.message : String(error)}`
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
async function executeChecks(config, options) {
|
|
677
|
+
const rootDir = config.rootDir || process.cwd();
|
|
678
|
+
const startTime = performance.now();
|
|
679
|
+
const decision = await analyzeCausalGraph(rootDir, config.plugins, options);
|
|
680
|
+
const results = await Promise.all(config.plugins.map((plugin) => runPluginChecker(plugin, decision.activePluginNames.has(plugin.name), rootDir, options)));
|
|
681
|
+
const totalDurationMs = performance.now() - startTime;
|
|
682
|
+
reportResults(decision, results, totalDurationMs, options);
|
|
683
|
+
const hasError = results.some((r) => r.status === "error");
|
|
684
|
+
if (!hasError) {
|
|
685
|
+
const cache = loadBuildCache(rootDir);
|
|
686
|
+
const { head } = await getGitState(rootDir);
|
|
687
|
+
if (head && head !== "unknown") {
|
|
688
|
+
cache.lastVerifiedHead = head;
|
|
689
|
+
saveBuildCache(rootDir, cache);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
if (hasError && options.interactive) {
|
|
693
|
+
const failedNames = new Set(results.filter((r) => r.status === "error").map((r) => r.name));
|
|
694
|
+
const failedPlugins = config.plugins.filter((p) => failedNames.has(p.name));
|
|
695
|
+
return await runInteractiveLoop(failedPlugins, rootDir, options);
|
|
696
|
+
}
|
|
697
|
+
return hasError ? 1 : 0;
|
|
698
|
+
}
|
|
699
|
+
async function runInteractiveLoop(failedPlugins, rootDir, options) {
|
|
700
|
+
const line = "\u2501".repeat(68);
|
|
701
|
+
process.stdout.write(`
|
|
702
|
+
${BOLD2}${CYAN2}${t("interactiveTitle")}${RESET2}
|
|
703
|
+
`);
|
|
704
|
+
process.stdout.write(`${GRAY2}${line}${RESET2}
|
|
705
|
+
`);
|
|
706
|
+
process.stdout.write(` \u2022 ${t("interactiveTarget")} : ${BOLD2}${failedPlugins.map((p) => p.name).join(", ")}${RESET2}
|
|
707
|
+
`);
|
|
708
|
+
process.stdout.write(` \u2022 ${t("interactiveWatching")}
|
|
709
|
+
`);
|
|
710
|
+
process.stdout.write(` \u2022 ${t("interactiveExit")}
|
|
711
|
+
`);
|
|
712
|
+
process.stdout.write(`${GRAY2}${line}${RESET2}
|
|
713
|
+
|
|
714
|
+
`);
|
|
715
|
+
return new Promise((resolve) => {
|
|
716
|
+
let isChecking = false;
|
|
717
|
+
let debounceTimer = null;
|
|
718
|
+
const watcher = watch(rootDir, { recursive: true }, async (_eventType, filename) => {
|
|
719
|
+
if (!filename)
|
|
720
|
+
return;
|
|
721
|
+
const normalized = filename.replace(/\\/g, "/");
|
|
722
|
+
if (normalized.includes("target/") || normalized.includes("node_modules/") || normalized.includes(".git/") || normalized.includes(".svelte-kit/") || normalized.includes("dist/") || normalized.includes(".synapse/")) {
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
if (debounceTimer)
|
|
726
|
+
clearTimeout(debounceTimer);
|
|
727
|
+
debounceTimer = setTimeout(async () => {
|
|
728
|
+
if (isChecking)
|
|
729
|
+
return;
|
|
730
|
+
isChecking = true;
|
|
731
|
+
const timeStr = new Date().toLocaleTimeString("ko-KR", { hour12: false });
|
|
732
|
+
process.stdout.write(`
|
|
733
|
+
${CYAN2}${t("interactiveDetected", timeStr, normalized)}${RESET2}
|
|
734
|
+
`);
|
|
735
|
+
const retryStart = performance.now();
|
|
736
|
+
const retryResults = await Promise.all(failedPlugins.map((p) => p.check({ rootDir, options })));
|
|
737
|
+
const retryDuration = ((performance.now() - retryStart) / 1000).toFixed(2);
|
|
738
|
+
const stillFailed = retryResults.some((r) => r.status === "error");
|
|
739
|
+
if (!stillFailed) {
|
|
740
|
+
process.stdout.write(`${BOLD2}${GREEN2}${t("interactivePassed", retryDuration)}${RESET2}
|
|
741
|
+
`);
|
|
742
|
+
process.stdout.write(`${BOLD2}${CYAN2}${t("interactiveResumed")}${RESET2}
|
|
743
|
+
|
|
744
|
+
`);
|
|
745
|
+
watcher.close();
|
|
746
|
+
const cache = loadBuildCache(rootDir);
|
|
747
|
+
const { head } = await getGitState(rootDir);
|
|
748
|
+
if (head && head !== "unknown") {
|
|
749
|
+
cache.lastVerifiedHead = head;
|
|
750
|
+
saveBuildCache(rootDir, cache);
|
|
751
|
+
}
|
|
752
|
+
resolve(0);
|
|
753
|
+
} else {
|
|
754
|
+
process.stdout.write(`${BOLD2}${RED2}${t("interactiveFailed")}${RESET2}
|
|
755
|
+
`);
|
|
756
|
+
for (const res of retryResults) {
|
|
757
|
+
if (res.status === "error" && res.details) {
|
|
758
|
+
process.stdout.write(` \u2514\u2500 ${GRAY2}${res.details}${RESET2}
|
|
759
|
+
`);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
isChecking = false;
|
|
763
|
+
}
|
|
764
|
+
}, 60);
|
|
765
|
+
});
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
async function executeBuild(config, options = { mode: "smart", agentMode: false, compactMode: false, watch: false }) {
|
|
769
|
+
const rootDir = config.rootDir || process.cwd();
|
|
770
|
+
const tracks = config.buildTracks || [];
|
|
771
|
+
if (tracks.length === 0) {
|
|
772
|
+
process.stderr.write(`${RED2}${t("noBuildTracks")}${RESET2}
|
|
773
|
+
`);
|
|
774
|
+
return 1;
|
|
775
|
+
}
|
|
776
|
+
const startTime = performance.now();
|
|
777
|
+
const line = "\u2501".repeat(68);
|
|
778
|
+
process.stdout.write(`
|
|
779
|
+
${BOLD2}${CYAN2}${t("buildHeader")} (${tracks.length})${RESET2}
|
|
780
|
+
`);
|
|
781
|
+
process.stdout.write(`${GRAY2}${line}${RESET2}
|
|
782
|
+
`);
|
|
783
|
+
const cache = loadBuildCache(rootDir);
|
|
784
|
+
const { head: currentHead, modifiedFiles, repoRoot } = await getGitState(rootDir);
|
|
785
|
+
const isForce = options.force || options.mode === "all";
|
|
786
|
+
const taskPromises = tracks.map(async (track) => {
|
|
787
|
+
const { skip, reason } = shouldSkipBuildTrack(track, rootDir, repoRoot, cache, modifiedFiles, isForce);
|
|
788
|
+
if (skip) {
|
|
789
|
+
return {
|
|
790
|
+
name: track.name,
|
|
791
|
+
durationMs: 0,
|
|
792
|
+
exitCode: 0,
|
|
793
|
+
skipped: true,
|
|
794
|
+
reason
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
const trackStart = performance.now();
|
|
798
|
+
const proc = spawn2([...track.command], {
|
|
799
|
+
cwd: track.cwd || rootDir,
|
|
800
|
+
stdout: "inherit",
|
|
801
|
+
stderr: "inherit"
|
|
802
|
+
});
|
|
803
|
+
const exitCode = await proc.exited;
|
|
804
|
+
const durationMs = performance.now() - trackStart;
|
|
805
|
+
return {
|
|
806
|
+
name: track.name,
|
|
807
|
+
durationMs,
|
|
808
|
+
exitCode,
|
|
809
|
+
skipped: false,
|
|
810
|
+
reason
|
|
811
|
+
};
|
|
812
|
+
});
|
|
813
|
+
const taskResults = await Promise.all(taskPromises);
|
|
814
|
+
const totalDuration = ((performance.now() - startTime) / 1000).toFixed(2);
|
|
815
|
+
const hasFailed = taskResults.some((t) => t.exitCode !== 0);
|
|
816
|
+
process.stdout.write(`${GRAY2}${line}${RESET2}
|
|
817
|
+
`);
|
|
818
|
+
for (const res of taskResults) {
|
|
819
|
+
if (res.skipped) {
|
|
820
|
+
process.stdout.write(` \u2022 ${BOLD2}${res.name.padEnd(38, " ")}${RESET2} : ${YELLOW2}\u26A1 ${t("trackSkipped")}${RESET2} ${GRAY2}(0.00s)${RESET2}
|
|
821
|
+
`);
|
|
822
|
+
} else {
|
|
823
|
+
const sec = (res.durationMs / 1000).toFixed(2);
|
|
824
|
+
const badge = res.exitCode === 0 ? `${GREEN2}\u2705 ${t("trackComplete")} (${sec}s)${RESET2}` : `${RED2}\u274C ${t("trackFailed")} (${sec}s)${RESET2}`;
|
|
825
|
+
process.stdout.write(` \u2022 ${BOLD2}${res.name.padEnd(38, " ")}${RESET2} : ${badge}
|
|
826
|
+
`);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
process.stdout.write(`${GRAY2}${line}${RESET2}
|
|
830
|
+
`);
|
|
831
|
+
if (!hasFailed) {
|
|
832
|
+
const now = new Date().toISOString();
|
|
833
|
+
for (const res of taskResults) {
|
|
834
|
+
if (!res.skipped && res.exitCode === 0) {
|
|
835
|
+
cache.tracks[res.name] = {
|
|
836
|
+
lastBuildTime: now,
|
|
837
|
+
gitCommit: currentHead,
|
|
838
|
+
artifactExists: true
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
saveBuildCache(rootDir, cache);
|
|
843
|
+
process.stdout.write(`${BOLD2}${GREEN2}${t("buildSuccessSummary", tracks.length, totalDuration)}${RESET2}
|
|
844
|
+
|
|
845
|
+
`);
|
|
846
|
+
return 0;
|
|
847
|
+
} else {
|
|
848
|
+
process.stdout.write(`${BOLD2}${RED2}${t("buildFailureSummary")}${RESET2}
|
|
849
|
+
|
|
850
|
+
`);
|
|
851
|
+
return 1;
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
async function executePackage(config, options = { mode: "smart", agentMode: false, compactMode: false, watch: false }) {
|
|
855
|
+
const rootDir = config.rootDir || process.cwd();
|
|
856
|
+
const startTime = performance.now();
|
|
857
|
+
const line = "\u2501".repeat(68);
|
|
858
|
+
process.stdout.write(`
|
|
859
|
+
${BOLD2}${CYAN2}${t("packageHeader")}${RESET2}
|
|
860
|
+
`);
|
|
861
|
+
process.stdout.write(`${GRAY2}${line}${RESET2}
|
|
862
|
+
`);
|
|
863
|
+
if (config.buildTracks && config.buildTracks.length > 0) {
|
|
864
|
+
process.stdout.write(`${CYAN2}${t("packagingPreBuild")}${RESET2}
|
|
865
|
+
`);
|
|
866
|
+
const buildExit = await executeBuild(config, options);
|
|
867
|
+
if (buildExit !== 0)
|
|
868
|
+
return buildExit;
|
|
869
|
+
}
|
|
870
|
+
const tauriConfCandidates = [
|
|
871
|
+
resolve3(rootDir, "src-tauri/tauri.conf.json"),
|
|
872
|
+
resolve3(rootDir, "tauri.conf.json")
|
|
873
|
+
];
|
|
874
|
+
const tauriConfPath = tauriConfCandidates.find((p) => existsSync3(p));
|
|
875
|
+
if (tauriConfPath) {
|
|
876
|
+
try {
|
|
877
|
+
const content = await Bun.file(tauriConfPath).json();
|
|
878
|
+
const targets = content?.bundle?.targets;
|
|
879
|
+
if (targets === "all") {
|
|
880
|
+
process.stdout.write(`${YELLOW2}${t("packagingGuide")}${RESET2}
|
|
881
|
+
`);
|
|
882
|
+
}
|
|
883
|
+
} catch {}
|
|
884
|
+
}
|
|
885
|
+
process.stdout.write(`${BOLD2}${t("packagingStart")}${RESET2}
|
|
886
|
+
`);
|
|
887
|
+
const pkgProc = spawn2(["bun", "x", "tauri", "build", "--bundles", "nsis"], {
|
|
888
|
+
cwd: rootDir,
|
|
889
|
+
stdout: "inherit",
|
|
890
|
+
stderr: "inherit"
|
|
891
|
+
});
|
|
892
|
+
const exitCode = await pkgProc.exited;
|
|
893
|
+
const duration = ((performance.now() - startTime) / 1000).toFixed(2);
|
|
894
|
+
process.stdout.write(`${GRAY2}${line}${RESET2}
|
|
895
|
+
`);
|
|
896
|
+
if (exitCode === 0) {
|
|
897
|
+
process.stdout.write(`${BOLD2}${GREEN2}${t("packageSuccess", duration)}${RESET2}
|
|
898
|
+
|
|
899
|
+
`);
|
|
900
|
+
return 0;
|
|
901
|
+
} else {
|
|
902
|
+
process.stdout.write(`${BOLD2}${RED2}${t("packageFailed", duration)}${RESET2}
|
|
903
|
+
|
|
904
|
+
`);
|
|
905
|
+
return exitCode;
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
async function executeSign(config, options = { mode: "smart", agentMode: false, compactMode: false, watch: false }) {
|
|
909
|
+
const rootDir = config.rootDir || process.cwd();
|
|
910
|
+
const startTime = performance.now();
|
|
911
|
+
const line = "\u2501".repeat(68);
|
|
912
|
+
process.stdout.write(`
|
|
913
|
+
${BOLD2}${CYAN2}${t("signHeader")}${RESET2}
|
|
914
|
+
`);
|
|
915
|
+
process.stdout.write(`${GRAY2}${line}${RESET2}
|
|
916
|
+
`);
|
|
917
|
+
const signConfig = config.sign;
|
|
918
|
+
if (!signConfig || !signConfig.privateKeyPath) {
|
|
919
|
+
process.stderr.write(`${RED2}${t("signNoConfig")}${RESET2}
|
|
920
|
+
`);
|
|
921
|
+
return 1;
|
|
922
|
+
}
|
|
923
|
+
const keyPath = resolve3(rootDir, signConfig.privateKeyPath);
|
|
924
|
+
if (!existsSync3(keyPath)) {
|
|
925
|
+
process.stderr.write(`${RED2}${t("signNoKey", keyPath)}${RESET2}
|
|
926
|
+
`);
|
|
927
|
+
return 1;
|
|
928
|
+
}
|
|
929
|
+
let installerPath = signConfig.targetInstaller ? resolve3(rootDir, signConfig.targetInstaller) : "";
|
|
930
|
+
if (!installerPath || !existsSync3(installerPath)) {
|
|
931
|
+
const candidates = [
|
|
932
|
+
resolve3(rootDir, "target/release/bundle/nsis"),
|
|
933
|
+
resolve3(rootDir, "src-tauri/target/release/bundle/nsis"),
|
|
934
|
+
resolve3(rootDir, "../target/release/bundle/nsis")
|
|
935
|
+
];
|
|
936
|
+
for (const dir of candidates) {
|
|
937
|
+
if (existsSync3(dir)) {
|
|
938
|
+
const files = readdirSync(dir).filter((f) => f.endsWith(".exe") && !f.endsWith(".sig"));
|
|
939
|
+
if (files.length > 0) {
|
|
940
|
+
installerPath = resolve3(dir, files[0]);
|
|
941
|
+
break;
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
if (!installerPath || !existsSync3(installerPath)) {
|
|
947
|
+
process.stderr.write(`${RED2}${t("signNoInstaller")}${RESET2}
|
|
948
|
+
`);
|
|
949
|
+
return 1;
|
|
950
|
+
}
|
|
951
|
+
const signaturePath = `${installerPath}.sig`;
|
|
952
|
+
const cache = loadBuildCache(rootDir);
|
|
953
|
+
const isForce = options.force || options.mode === "all";
|
|
954
|
+
const { skip, reason, currentHash } = shouldSkipSign(installerPath, signaturePath, cache, isForce);
|
|
955
|
+
if (skip) {
|
|
956
|
+
process.stdout.write(` \u2022 ${t("signTarget")} : ${BOLD2}${installerPath}${RESET2}
|
|
957
|
+
` + ` \u2022 ${t("signStatus")} : ${YELLOW2}\u26A1 ${t("signCacheHit")}${RESET2} ${GRAY2}(0.00s)${RESET2}
|
|
958
|
+
` + ` \u2022 ${t("signFile")} : ${GREEN2}\u2705 ${t("signExistingKeep", signaturePath)}${RESET2}
|
|
959
|
+
`);
|
|
960
|
+
process.stdout.write(`${GRAY2}${line}${RESET2}
|
|
961
|
+
`);
|
|
962
|
+
process.stdout.write(`${BOLD2}${GREEN2}${t("signIntegrityPass")}${RESET2}
|
|
963
|
+
|
|
964
|
+
`);
|
|
965
|
+
return 0;
|
|
966
|
+
}
|
|
967
|
+
process.stdout.write(` \u2022 ${t("signTarget")} : ${BOLD2}${installerPath}${RESET2}
|
|
968
|
+
`);
|
|
969
|
+
process.stdout.write(` \u2022 ${t("signReasonLabel")} : ${CYAN2}${reason}${RESET2}
|
|
970
|
+
`);
|
|
971
|
+
process.stdout.write(` \u2022 ${t("signEngineLabel")} : ${BOLD2}Bun Native Tauri Signer (Ed25519)${RESET2}
|
|
972
|
+
`);
|
|
973
|
+
const passwordEnvName = signConfig.passwordEnv || "TAURI_KEY_PASSWORD";
|
|
974
|
+
const passwordVal = process.env[passwordEnvName] || process.env.TAURI_PRIVATE_KEY_PASSWORD || process.env.TAURI_KEY_PASSWORD || "";
|
|
975
|
+
const signArgs = [
|
|
976
|
+
"bun",
|
|
977
|
+
"x",
|
|
978
|
+
"tauri",
|
|
979
|
+
"signer",
|
|
980
|
+
"sign",
|
|
981
|
+
"--private-key-path",
|
|
982
|
+
keyPath
|
|
983
|
+
];
|
|
984
|
+
if (passwordVal) {
|
|
985
|
+
signArgs.push("--password", passwordVal);
|
|
986
|
+
}
|
|
987
|
+
signArgs.push(installerPath);
|
|
988
|
+
const proc = spawn2(signArgs, {
|
|
989
|
+
cwd: rootDir,
|
|
990
|
+
env: {
|
|
991
|
+
...process.env,
|
|
992
|
+
TAURI_PRIVATE_KEY_PASSWORD: passwordVal,
|
|
993
|
+
TAURI_KEY_PASSWORD: passwordVal
|
|
994
|
+
},
|
|
995
|
+
stdout: "inherit",
|
|
996
|
+
stderr: "inherit"
|
|
997
|
+
});
|
|
998
|
+
const exitCode = await proc.exited;
|
|
999
|
+
const duration = ((performance.now() - startTime) / 1000).toFixed(2);
|
|
1000
|
+
process.stdout.write(`${GRAY2}${line}${RESET2}
|
|
1001
|
+
`);
|
|
1002
|
+
if (exitCode === 0) {
|
|
1003
|
+
cache.sign = {
|
|
1004
|
+
lastSignTime: new Date().toISOString(),
|
|
1005
|
+
installerHash: currentHash || computeFileHash(installerPath),
|
|
1006
|
+
signaturePath
|
|
1007
|
+
};
|
|
1008
|
+
saveBuildCache(rootDir, cache);
|
|
1009
|
+
process.stdout.write(`${BOLD2}${GREEN2}${t("signSuccess", duration)}${RESET2}
|
|
1010
|
+
` + ` \u2022 ${t("signFile")}: ${BOLD2}${signaturePath}${RESET2}
|
|
1011
|
+
|
|
1012
|
+
`);
|
|
1013
|
+
return 0;
|
|
1014
|
+
} else {
|
|
1015
|
+
process.stdout.write(`${BOLD2}${RED2}${t("signFailed", duration)}${RESET2}
|
|
1016
|
+
|
|
1017
|
+
`);
|
|
1018
|
+
return exitCode;
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
// plugins/rust.ts
|
|
1022
|
+
var {spawn: spawn3 } = globalThis.Bun;
|
|
1023
|
+
import { resolve as resolve4 } from "path";
|
|
1024
|
+
function rustChecker(options = {}) {
|
|
1025
|
+
return {
|
|
1026
|
+
name: "rust",
|
|
1027
|
+
get title() {
|
|
1028
|
+
return t("pluginRustTitle");
|
|
1029
|
+
},
|
|
1030
|
+
triggers: [
|
|
1031
|
+
"Cargo.toml",
|
|
1032
|
+
"Cargo.lock",
|
|
1033
|
+
".rs",
|
|
1034
|
+
"src-tauri/",
|
|
1035
|
+
"crates/"
|
|
1036
|
+
],
|
|
1037
|
+
check: async (ctx) => {
|
|
1038
|
+
const start = performance.now();
|
|
1039
|
+
const workspacePath = resolve4(ctx.rootDir, options.workspaceDir || "./");
|
|
1040
|
+
try {
|
|
1041
|
+
const checkProc = spawn3(["cargo", "check", "--workspace"], {
|
|
1042
|
+
cwd: workspacePath,
|
|
1043
|
+
stdout: "pipe",
|
|
1044
|
+
stderr: "pipe"
|
|
1045
|
+
});
|
|
1046
|
+
const [checkStdout, checkStderr] = await Promise.all([
|
|
1047
|
+
new Response(checkProc.stdout).text(),
|
|
1048
|
+
new Response(checkProc.stderr).text()
|
|
1049
|
+
]);
|
|
1050
|
+
const checkExitCode = await checkProc.exited;
|
|
1051
|
+
if (checkExitCode !== 0) {
|
|
1052
|
+
const durationMs = performance.now() - start;
|
|
1053
|
+
const outputText = `${checkStderr}
|
|
1054
|
+
${checkStdout}`.trim();
|
|
1055
|
+
return {
|
|
1056
|
+
name: "rust",
|
|
1057
|
+
title: t("pluginRustTitle"),
|
|
1058
|
+
status: "error",
|
|
1059
|
+
durationMs,
|
|
1060
|
+
details: t("pluginRustCompileFail"),
|
|
1061
|
+
diagnostics: [{ message: outputText.slice(-1500), severity: "error" }]
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
const clippyProc = spawn3(["cargo", "clippy", "--workspace"], {
|
|
1065
|
+
cwd: workspacePath,
|
|
1066
|
+
stdout: "pipe",
|
|
1067
|
+
stderr: "pipe"
|
|
1068
|
+
});
|
|
1069
|
+
const [clippyStdout, clippyStderr] = await Promise.all([
|
|
1070
|
+
new Response(clippyProc.stdout).text(),
|
|
1071
|
+
new Response(clippyProc.stderr).text()
|
|
1072
|
+
]);
|
|
1073
|
+
const clippyExitCode = await clippyProc.exited;
|
|
1074
|
+
const clippyOutput = `${clippyStderr}
|
|
1075
|
+
${clippyStdout}`;
|
|
1076
|
+
const warningMatches = clippyOutput.match(/warning: /g);
|
|
1077
|
+
const warningCount = warningMatches ? warningMatches.length : 0;
|
|
1078
|
+
const durationMs = performance.now() - start;
|
|
1079
|
+
if (clippyExitCode !== 0 || warningCount > 0) {
|
|
1080
|
+
return {
|
|
1081
|
+
name: "rust",
|
|
1082
|
+
title: t("pluginRustTitle"),
|
|
1083
|
+
status: warningCount > 0 && clippyExitCode === 0 ? "warning" : "error",
|
|
1084
|
+
durationMs,
|
|
1085
|
+
details: t("pluginRustClippyWarn", warningCount)
|
|
1086
|
+
};
|
|
1087
|
+
}
|
|
1088
|
+
return {
|
|
1089
|
+
name: "rust",
|
|
1090
|
+
title: t("pluginRustTitle"),
|
|
1091
|
+
status: "success",
|
|
1092
|
+
durationMs,
|
|
1093
|
+
details: t("pluginRustSuccess")
|
|
1094
|
+
};
|
|
1095
|
+
} catch (error) {
|
|
1096
|
+
return {
|
|
1097
|
+
name: "rust",
|
|
1098
|
+
title: t("pluginRustTitle"),
|
|
1099
|
+
status: "error",
|
|
1100
|
+
durationMs: performance.now() - start,
|
|
1101
|
+
details: t("pluginRustExecFail", error instanceof Error ? error.message : String(error))
|
|
1102
|
+
};
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
};
|
|
1106
|
+
}
|
|
1107
|
+
// plugins/svelte.ts
|
|
1108
|
+
var {spawn: spawn4 } = globalThis.Bun;
|
|
1109
|
+
import { resolve as resolve5 } from "path";
|
|
1110
|
+
function svelteChecker(options = {}) {
|
|
1111
|
+
return {
|
|
1112
|
+
name: "svelte",
|
|
1113
|
+
get title() {
|
|
1114
|
+
return t("pluginSvelteTitle");
|
|
1115
|
+
},
|
|
1116
|
+
triggers: [
|
|
1117
|
+
".svelte",
|
|
1118
|
+
".ts",
|
|
1119
|
+
".js",
|
|
1120
|
+
"svelte.config.js",
|
|
1121
|
+
"tsconfig.json",
|
|
1122
|
+
"src/"
|
|
1123
|
+
],
|
|
1124
|
+
check: async (ctx) => {
|
|
1125
|
+
const start = performance.now();
|
|
1126
|
+
const appPath = resolve5(ctx.rootDir, options.appDir || "./");
|
|
1127
|
+
const tsconfigPath = resolve5(appPath, options.tsconfig || "./tsconfig.json");
|
|
1128
|
+
try {
|
|
1129
|
+
const syncProc = spawn4(["bun", "x", "svelte-kit", "sync"], {
|
|
1130
|
+
cwd: appPath,
|
|
1131
|
+
stdout: "pipe",
|
|
1132
|
+
stderr: "pipe"
|
|
1133
|
+
});
|
|
1134
|
+
await syncProc.exited;
|
|
1135
|
+
const checkProc = spawn4(["bun", "x", "svelte-check", "--tsconfig", tsconfigPath, "--threshold", options.threshold || "warning"], {
|
|
1136
|
+
cwd: appPath,
|
|
1137
|
+
stdout: "pipe",
|
|
1138
|
+
stderr: "pipe"
|
|
1139
|
+
});
|
|
1140
|
+
const [stdout, stderr] = await Promise.all([
|
|
1141
|
+
new Response(checkProc.stdout).text(),
|
|
1142
|
+
new Response(checkProc.stderr).text()
|
|
1143
|
+
]);
|
|
1144
|
+
const exitCode = await checkProc.exited;
|
|
1145
|
+
const durationMs = performance.now() - start;
|
|
1146
|
+
if (exitCode !== 0) {
|
|
1147
|
+
const outputText = `${stdout}
|
|
1148
|
+
${stderr}`.trim();
|
|
1149
|
+
return {
|
|
1150
|
+
name: "svelte",
|
|
1151
|
+
title: t("pluginSvelteTitle"),
|
|
1152
|
+
status: "error",
|
|
1153
|
+
durationMs,
|
|
1154
|
+
details: t("pluginSvelteError"),
|
|
1155
|
+
diagnostics: [{ message: outputText.slice(-1500), severity: "error" }]
|
|
1156
|
+
};
|
|
1157
|
+
}
|
|
1158
|
+
return {
|
|
1159
|
+
name: "svelte",
|
|
1160
|
+
title: t("pluginSvelteTitle"),
|
|
1161
|
+
status: "success",
|
|
1162
|
+
durationMs,
|
|
1163
|
+
details: t("pluginSvelteSuccess")
|
|
1164
|
+
};
|
|
1165
|
+
} catch (error) {
|
|
1166
|
+
return {
|
|
1167
|
+
name: "svelte",
|
|
1168
|
+
title: t("pluginSvelteTitle"),
|
|
1169
|
+
status: "error",
|
|
1170
|
+
durationMs: performance.now() - start,
|
|
1171
|
+
details: t("pluginSvelteExecFail", error instanceof Error ? error.message : String(error))
|
|
1172
|
+
};
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
};
|
|
1176
|
+
}
|
|
1177
|
+
// plugins/typescript.ts
|
|
1178
|
+
var {spawn: spawn5 } = globalThis.Bun;
|
|
1179
|
+
import { resolve as resolve6 } from "path";
|
|
1180
|
+
import { existsSync as existsSync4 } from "fs";
|
|
1181
|
+
function typescriptChecker(options = {}) {
|
|
1182
|
+
const tool = options.tool || "hybrid";
|
|
1183
|
+
const tsconfig = options.tsconfig || "./tsconfig.json";
|
|
1184
|
+
return {
|
|
1185
|
+
name: "typescript",
|
|
1186
|
+
get title() {
|
|
1187
|
+
if (tool === "hybrid") {
|
|
1188
|
+
return t("getLocale") === "en" ? "TypeScript Dual Hybrid (Native Fast-Abort + Pure tsc)" : "TypeScript 2\uB2E8 \uD558\uC774\uBE0C\uB9AC\uB4DC (\uB124\uC774\uD2F0\uBE0C Fast-Abort + \uC21C\uC218 tsc)";
|
|
1189
|
+
}
|
|
1190
|
+
return tool === "tsc" ? t("pluginTypescriptTitlePure") : t("pluginTypescriptTitleNative");
|
|
1191
|
+
},
|
|
1192
|
+
triggers: [
|
|
1193
|
+
".ts",
|
|
1194
|
+
".tsx",
|
|
1195
|
+
".mts",
|
|
1196
|
+
".cts",
|
|
1197
|
+
"tsconfig.json",
|
|
1198
|
+
"package.json"
|
|
1199
|
+
],
|
|
1200
|
+
check: async (ctx) => {
|
|
1201
|
+
const start = performance.now();
|
|
1202
|
+
const tsconfigPath = resolve6(ctx.rootDir, tsconfig);
|
|
1203
|
+
const nativeCandidates = [
|
|
1204
|
+
options.tsrsPath,
|
|
1205
|
+
resolve6(ctx.rootDir, "node_modules/@tsrs/win32-x64/tsrs.exe"),
|
|
1206
|
+
resolve6(ctx.rootDir, "../node_modules/@tsrs/win32-x64/tsrs.exe"),
|
|
1207
|
+
"D:/synapse/examples/massive-200k/node_modules/@tsrs/win32-x64/tsrs.exe",
|
|
1208
|
+
"tsrs"
|
|
1209
|
+
].filter((p) => !!p);
|
|
1210
|
+
const resolvedNativePath = nativeCandidates.find((p) => p === "tsrs" || existsSync4(p));
|
|
1211
|
+
if (tool === "hybrid" && resolvedNativePath) {
|
|
1212
|
+
try {
|
|
1213
|
+
const nativeProc = spawn5([resolvedNativePath, "--noEmit", ...options.extraArgs || []], {
|
|
1214
|
+
cwd: ctx.rootDir,
|
|
1215
|
+
stdout: "pipe",
|
|
1216
|
+
stderr: "pipe"
|
|
1217
|
+
});
|
|
1218
|
+
const tscProc = spawn5(["bun", "x", "tsc", "--project", tsconfigPath, "--incremental", "--noEmit", ...options.extraArgs || []], {
|
|
1219
|
+
cwd: ctx.rootDir,
|
|
1220
|
+
stdout: "pipe",
|
|
1221
|
+
stderr: "pipe"
|
|
1222
|
+
});
|
|
1223
|
+
const nativePromise = (async () => {
|
|
1224
|
+
const [stdout, stderr] = await Promise.all([
|
|
1225
|
+
new Response(nativeProc.stdout).text(),
|
|
1226
|
+
new Response(nativeProc.stderr).text()
|
|
1227
|
+
]);
|
|
1228
|
+
const exitCode = await nativeProc.exited;
|
|
1229
|
+
return { exitCode, stdout, stderr };
|
|
1230
|
+
})();
|
|
1231
|
+
const tscPromise = (async () => {
|
|
1232
|
+
const [stdout, stderr] = await Promise.all([
|
|
1233
|
+
new Response(tscProc.stdout).text(),
|
|
1234
|
+
new Response(tscProc.stderr).text()
|
|
1235
|
+
]);
|
|
1236
|
+
const exitCode = await tscProc.exited;
|
|
1237
|
+
return { exitCode, stdout, stderr };
|
|
1238
|
+
})();
|
|
1239
|
+
const nativeResult = await nativePromise;
|
|
1240
|
+
if (nativeResult.exitCode !== 0) {
|
|
1241
|
+
try {
|
|
1242
|
+
tscProc.kill();
|
|
1243
|
+
} catch {}
|
|
1244
|
+
const durationMs = performance.now() - start;
|
|
1245
|
+
const outputText = `${nativeResult.stderr}
|
|
1246
|
+
${nativeResult.stdout}`.trim();
|
|
1247
|
+
return {
|
|
1248
|
+
name: "typescript",
|
|
1249
|
+
title: "TypeScript 2\uB2E8 \uD558\uC774\uBE0C\uB9AC\uB4DC (Fast-Abort)",
|
|
1250
|
+
status: "error",
|
|
1251
|
+
durationMs,
|
|
1252
|
+
details: `\uB124\uC774\uD2F0\uBE0C Oxc \uAD6C\uBB38 \uAC80\uC0AC \uC989\uC2DC \uCC28\uB2E8 (${durationMs.toFixed(1)}ms): \uBB38\uBC95 \uC624\uB958\uAC00 \uBC1C\uACAC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`,
|
|
1253
|
+
diagnostics: [{ message: outputText.slice(-1500), severity: "error" }]
|
|
1254
|
+
};
|
|
1255
|
+
}
|
|
1256
|
+
const tscResult = await tscPromise;
|
|
1257
|
+
const durationMs = performance.now() - start;
|
|
1258
|
+
if (tscResult.exitCode !== 0) {
|
|
1259
|
+
const outputText = `${tscResult.stderr}
|
|
1260
|
+
${tscResult.stdout}`.trim();
|
|
1261
|
+
return {
|
|
1262
|
+
name: "typescript",
|
|
1263
|
+
title: "TypeScript 2\uB2E8 \uD558\uC774\uBE0C\uB9AC\uB4DC (Pure tsc)",
|
|
1264
|
+
status: "error",
|
|
1265
|
+
durationMs,
|
|
1266
|
+
details: "\uACF5\uC2DD tsc \uD0C0\uC785 \uAC80\uC0AC\uC5D0\uC11C \uC2DC\uB9E8\uD2F1 \uC624\uB958\uAC00 \uAC10\uC9C0\uB418\uC5C8\uC2B5\uB2C8\uB2E4.",
|
|
1267
|
+
diagnostics: [{ message: outputText.slice(-1500), severity: "error" }]
|
|
1268
|
+
};
|
|
1269
|
+
}
|
|
1270
|
+
return {
|
|
1271
|
+
name: "typescript",
|
|
1272
|
+
title: "TypeScript 2\uB2E8 \uD558\uC774\uBE0C\uB9AC\uB4DC \uC735\uD569",
|
|
1273
|
+
status: "success",
|
|
1274
|
+
durationMs,
|
|
1275
|
+
details: `\uB124\uC774\uD2F0\uBE0C Oxc(\uAD6C\uBB38 0.1s) + \uC21C\uC218 tsc(\uC99D\uBD84 \uD0C0\uC785 0.3s) \uB3D9\uC2DC \uC644\uACB0`
|
|
1276
|
+
};
|
|
1277
|
+
} catch {}
|
|
1278
|
+
}
|
|
1279
|
+
const isNative = tool === "tsrs" && resolvedNativePath;
|
|
1280
|
+
const args = isNative ? [resolvedNativePath, "--noEmit", ...options.extraArgs || []] : ["bun", "x", "tsc", "--project", tsconfigPath, "--incremental", "--noEmit", ...options.extraArgs || []];
|
|
1281
|
+
try {
|
|
1282
|
+
const proc = spawn5(args, {
|
|
1283
|
+
cwd: ctx.rootDir,
|
|
1284
|
+
stdout: "pipe",
|
|
1285
|
+
stderr: "pipe"
|
|
1286
|
+
});
|
|
1287
|
+
const [stdout, stderr] = await Promise.all([
|
|
1288
|
+
new Response(proc.stdout).text(),
|
|
1289
|
+
new Response(proc.stderr).text()
|
|
1290
|
+
]);
|
|
1291
|
+
const exitCode = await proc.exited;
|
|
1292
|
+
const durationMs = performance.now() - start;
|
|
1293
|
+
if (exitCode !== 0) {
|
|
1294
|
+
const outputText = `${stderr}
|
|
1295
|
+
${stdout}`.trim();
|
|
1296
|
+
return {
|
|
1297
|
+
name: "typescript",
|
|
1298
|
+
title: isNative ? t("pluginTypescriptTitleNative") : t("pluginTypescriptTitlePure"),
|
|
1299
|
+
status: "error",
|
|
1300
|
+
durationMs,
|
|
1301
|
+
details: t("pluginTypescriptError"),
|
|
1302
|
+
diagnostics: [{ message: outputText.slice(-1500), severity: "error" }]
|
|
1303
|
+
};
|
|
1304
|
+
}
|
|
1305
|
+
return {
|
|
1306
|
+
name: "typescript",
|
|
1307
|
+
title: isNative ? t("pluginTypescriptTitleNative") : t("pluginTypescriptTitlePure"),
|
|
1308
|
+
status: "success",
|
|
1309
|
+
durationMs,
|
|
1310
|
+
details: t("pluginTypescriptSuccess", isNative ? "Native tsrs" : "Pure tsc incremental")
|
|
1311
|
+
};
|
|
1312
|
+
} catch (error) {
|
|
1313
|
+
return {
|
|
1314
|
+
name: "typescript",
|
|
1315
|
+
title: "TypeScript \uAC80\uC99D\uAE30",
|
|
1316
|
+
status: "error",
|
|
1317
|
+
durationMs: performance.now() - start,
|
|
1318
|
+
details: `TypeScript execution failed: ${error instanceof Error ? error.message : String(error)}`
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
};
|
|
1323
|
+
}
|
|
1324
|
+
// plugins/java.ts
|
|
1325
|
+
var {spawn: spawn6 } = globalThis.Bun;
|
|
1326
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
|
|
1327
|
+
import { resolve as resolve7 } from "path";
|
|
1328
|
+
function javaChecker(options = {}) {
|
|
1329
|
+
const sourceDir = options.sourceDir || ".";
|
|
1330
|
+
const outputDir = options.outputDir || "./target/java-classes";
|
|
1331
|
+
const extraArgs = options.javacArgs || [];
|
|
1332
|
+
return {
|
|
1333
|
+
name: "java",
|
|
1334
|
+
get title() {
|
|
1335
|
+
return t("pluginJavaTitle");
|
|
1336
|
+
},
|
|
1337
|
+
triggers: [
|
|
1338
|
+
".java",
|
|
1339
|
+
"pom.xml",
|
|
1340
|
+
"build.gradle",
|
|
1341
|
+
"build.gradle.kts",
|
|
1342
|
+
"settings.gradle"
|
|
1343
|
+
],
|
|
1344
|
+
check: async (ctx) => {
|
|
1345
|
+
const start = performance.now();
|
|
1346
|
+
const targetDir = resolve7(ctx.rootDir, sourceDir);
|
|
1347
|
+
const outDir = resolve7(ctx.rootDir, outputDir);
|
|
1348
|
+
if (!existsSync5(outDir)) {
|
|
1349
|
+
try {
|
|
1350
|
+
mkdirSync2(outDir, { recursive: true });
|
|
1351
|
+
} catch {}
|
|
1352
|
+
}
|
|
1353
|
+
let javaFiles = options.targetFiles ? [...options.targetFiles] : [];
|
|
1354
|
+
if (javaFiles.length === 0) {
|
|
1355
|
+
try {
|
|
1356
|
+
const glob = new Bun.Glob("**/*.java");
|
|
1357
|
+
const scanned = Array.from(glob.scanSync({ cwd: targetDir, absolute: true }));
|
|
1358
|
+
javaFiles = scanned.slice(0, 10);
|
|
1359
|
+
} catch {
|
|
1360
|
+
javaFiles = [];
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
if (javaFiles.length === 0) {
|
|
1364
|
+
return {
|
|
1365
|
+
name: "java",
|
|
1366
|
+
title: t("pluginJavaTitle"),
|
|
1367
|
+
status: "skipped",
|
|
1368
|
+
durationMs: performance.now() - start,
|
|
1369
|
+
details: t("pluginJavaNoFiles")
|
|
1370
|
+
};
|
|
1371
|
+
}
|
|
1372
|
+
const args = ["javac", "-d", outDir, ...extraArgs, ...javaFiles];
|
|
1373
|
+
try {
|
|
1374
|
+
const proc = spawn6(args, {
|
|
1375
|
+
cwd: ctx.rootDir,
|
|
1376
|
+
stdout: "pipe",
|
|
1377
|
+
stderr: "pipe"
|
|
1378
|
+
});
|
|
1379
|
+
const stderrText = await new Response(proc.stderr).text();
|
|
1380
|
+
await proc.exited;
|
|
1381
|
+
const durationMs = performance.now() - start;
|
|
1382
|
+
if (proc.exitCode === 0) {
|
|
1383
|
+
return {
|
|
1384
|
+
name: "java",
|
|
1385
|
+
title: t("pluginJavaTitle"),
|
|
1386
|
+
status: "success",
|
|
1387
|
+
durationMs,
|
|
1388
|
+
details: t("pluginJavaSuccess", javaFiles.length)
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1391
|
+
return {
|
|
1392
|
+
name: "java",
|
|
1393
|
+
title: t("pluginJavaTitle"),
|
|
1394
|
+
status: "error",
|
|
1395
|
+
durationMs,
|
|
1396
|
+
details: stderrText.trim() || t("pluginJavaError"),
|
|
1397
|
+
diagnostics: [
|
|
1398
|
+
{
|
|
1399
|
+
file: javaFiles[0] || "Unknown.java",
|
|
1400
|
+
line: 1,
|
|
1401
|
+
message: stderrText.trim() || t("pluginJavaError"),
|
|
1402
|
+
severity: "error"
|
|
1403
|
+
}
|
|
1404
|
+
]
|
|
1405
|
+
};
|
|
1406
|
+
} catch (error) {
|
|
1407
|
+
return {
|
|
1408
|
+
name: "java",
|
|
1409
|
+
title: t("pluginJavaTitle"),
|
|
1410
|
+
status: "error",
|
|
1411
|
+
durationMs: performance.now() - start,
|
|
1412
|
+
details: `javac execution failed: ${error instanceof Error ? error.message : String(error)}`
|
|
1413
|
+
};
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
};
|
|
1417
|
+
}
|
|
1418
|
+
// plugins/cpp.ts
|
|
1419
|
+
var {spawn: spawn7 } = globalThis.Bun;
|
|
1420
|
+
import { resolve as resolve8 } from "path";
|
|
1421
|
+
function cppChecker(options = {}) {
|
|
1422
|
+
const compiler = options.compiler || "g++";
|
|
1423
|
+
const std = options.std || "c++17";
|
|
1424
|
+
const sourceDir = options.sourceDir || ".";
|
|
1425
|
+
return {
|
|
1426
|
+
name: "cpp",
|
|
1427
|
+
get title() {
|
|
1428
|
+
return t("pluginCppTitle");
|
|
1429
|
+
},
|
|
1430
|
+
triggers: [
|
|
1431
|
+
".cpp",
|
|
1432
|
+
".hpp",
|
|
1433
|
+
".cc",
|
|
1434
|
+
".cxx",
|
|
1435
|
+
".h",
|
|
1436
|
+
"CMakeLists.txt"
|
|
1437
|
+
],
|
|
1438
|
+
check: async (ctx) => {
|
|
1439
|
+
const start = performance.now();
|
|
1440
|
+
const targetPath = resolve8(ctx.rootDir, sourceDir);
|
|
1441
|
+
let targetFiles = options.targetFiles ? [...options.targetFiles] : [];
|
|
1442
|
+
if (targetFiles.length === 0) {
|
|
1443
|
+
try {
|
|
1444
|
+
const glob = new Bun.Glob("**/*.{cpp,cc,cxx}");
|
|
1445
|
+
const scanned = Array.from(glob.scanSync({ cwd: targetPath, absolute: true }));
|
|
1446
|
+
targetFiles = scanned.slice(0, 50);
|
|
1447
|
+
} catch {
|
|
1448
|
+
targetFiles = [];
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
if (targetFiles.length === 0) {
|
|
1452
|
+
return {
|
|
1453
|
+
name: "cpp",
|
|
1454
|
+
title: t("pluginCppTitle"),
|
|
1455
|
+
status: "skipped",
|
|
1456
|
+
durationMs: performance.now() - start,
|
|
1457
|
+
details: t("pluginCppNoFiles")
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1460
|
+
const includes = (options.includeDirs || []).map((d) => `-I${resolve8(ctx.rootDir, d)}`);
|
|
1461
|
+
const args = [
|
|
1462
|
+
compiler,
|
|
1463
|
+
`-std=${std}`,
|
|
1464
|
+
"-fsyntax-only",
|
|
1465
|
+
...includes,
|
|
1466
|
+
...options.extraArgs || [],
|
|
1467
|
+
...targetFiles
|
|
1468
|
+
];
|
|
1469
|
+
try {
|
|
1470
|
+
const proc = spawn7(args, {
|
|
1471
|
+
cwd: ctx.rootDir,
|
|
1472
|
+
stdout: "pipe",
|
|
1473
|
+
stderr: "pipe"
|
|
1474
|
+
});
|
|
1475
|
+
const [stdout, stderr] = await Promise.all([
|
|
1476
|
+
new Response(proc.stdout).text(),
|
|
1477
|
+
new Response(proc.stderr).text()
|
|
1478
|
+
]);
|
|
1479
|
+
const exitCode = await proc.exited;
|
|
1480
|
+
const durationMs = performance.now() - start;
|
|
1481
|
+
if (exitCode !== 0) {
|
|
1482
|
+
const outputText = `${stderr}
|
|
1483
|
+
${stdout}`.trim();
|
|
1484
|
+
return {
|
|
1485
|
+
name: "cpp",
|
|
1486
|
+
title: t("pluginCppTitle"),
|
|
1487
|
+
status: "error",
|
|
1488
|
+
durationMs,
|
|
1489
|
+
details: t("pluginCppError"),
|
|
1490
|
+
diagnostics: [{ message: outputText.slice(-1500), severity: "error" }]
|
|
1491
|
+
};
|
|
1492
|
+
}
|
|
1493
|
+
return {
|
|
1494
|
+
name: "cpp",
|
|
1495
|
+
title: t("pluginCppTitle"),
|
|
1496
|
+
status: "success",
|
|
1497
|
+
durationMs,
|
|
1498
|
+
details: t("pluginCppSuccess", targetFiles.length)
|
|
1499
|
+
};
|
|
1500
|
+
} catch (error) {
|
|
1501
|
+
return {
|
|
1502
|
+
name: "cpp",
|
|
1503
|
+
title: t("pluginCppTitle"),
|
|
1504
|
+
status: "error",
|
|
1505
|
+
durationMs: performance.now() - start,
|
|
1506
|
+
details: `${compiler} execution failed: ${error instanceof Error ? error.message : String(error)}`
|
|
1507
|
+
};
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
};
|
|
1511
|
+
}
|
|
1512
|
+
// plugins/csharp.ts
|
|
1513
|
+
var {spawn: spawn8 } = globalThis.Bun;
|
|
1514
|
+
import { resolve as resolve9 } from "path";
|
|
1515
|
+
function csharpChecker(options = {}) {
|
|
1516
|
+
const projectPath = options.projectPath || ".";
|
|
1517
|
+
const configuration = options.configuration || "Release";
|
|
1518
|
+
return {
|
|
1519
|
+
name: "csharp",
|
|
1520
|
+
get title() {
|
|
1521
|
+
return t("pluginCsharpTitle");
|
|
1522
|
+
},
|
|
1523
|
+
triggers: [
|
|
1524
|
+
".cs",
|
|
1525
|
+
".csproj",
|
|
1526
|
+
".sln",
|
|
1527
|
+
"Directory.Build.props",
|
|
1528
|
+
"Directory.Build.targets"
|
|
1529
|
+
],
|
|
1530
|
+
check: async (ctx) => {
|
|
1531
|
+
const start = performance.now();
|
|
1532
|
+
const target = resolve9(ctx.rootDir, projectPath);
|
|
1533
|
+
const args = [
|
|
1534
|
+
"dotnet",
|
|
1535
|
+
"build",
|
|
1536
|
+
target,
|
|
1537
|
+
"-c",
|
|
1538
|
+
configuration,
|
|
1539
|
+
"-v",
|
|
1540
|
+
"q",
|
|
1541
|
+
"--nologo",
|
|
1542
|
+
...options.extraArgs || []
|
|
1543
|
+
];
|
|
1544
|
+
try {
|
|
1545
|
+
const proc = spawn8(args, {
|
|
1546
|
+
cwd: ctx.rootDir,
|
|
1547
|
+
stdout: "pipe",
|
|
1548
|
+
stderr: "pipe"
|
|
1549
|
+
});
|
|
1550
|
+
const [stdout, stderr] = await Promise.all([
|
|
1551
|
+
new Response(proc.stdout).text(),
|
|
1552
|
+
new Response(proc.stderr).text()
|
|
1553
|
+
]);
|
|
1554
|
+
const exitCode = await proc.exited;
|
|
1555
|
+
const durationMs = performance.now() - start;
|
|
1556
|
+
if (exitCode !== 0) {
|
|
1557
|
+
const outputText = `${stderr}
|
|
1558
|
+
${stdout}`.trim();
|
|
1559
|
+
return {
|
|
1560
|
+
name: "csharp",
|
|
1561
|
+
title: t("pluginCsharpTitle"),
|
|
1562
|
+
status: "error",
|
|
1563
|
+
durationMs,
|
|
1564
|
+
details: t("pluginCsharpError"),
|
|
1565
|
+
diagnostics: [{ message: outputText.slice(-1500), severity: "error" }]
|
|
1566
|
+
};
|
|
1567
|
+
}
|
|
1568
|
+
return {
|
|
1569
|
+
name: "csharp",
|
|
1570
|
+
title: t("pluginCsharpTitle"),
|
|
1571
|
+
status: "success",
|
|
1572
|
+
durationMs,
|
|
1573
|
+
details: t("pluginCsharpSuccess")
|
|
1574
|
+
};
|
|
1575
|
+
} catch (error) {
|
|
1576
|
+
return {
|
|
1577
|
+
name: "csharp",
|
|
1578
|
+
title: t("pluginCsharpTitle"),
|
|
1579
|
+
status: "error",
|
|
1580
|
+
durationMs: performance.now() - start,
|
|
1581
|
+
details: `dotnet execution failed: ${error instanceof Error ? error.message : String(error)}`
|
|
1582
|
+
};
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
};
|
|
1586
|
+
}
|
|
1587
|
+
// plugins/go.ts
|
|
1588
|
+
var {spawn: spawn9 } = globalThis.Bun;
|
|
1589
|
+
import { resolve as resolve10 } from "path";
|
|
1590
|
+
function goChecker(options = {}) {
|
|
1591
|
+
const moduleDir = options.moduleDir || ".";
|
|
1592
|
+
const targetPackage = options.targetPackage || "./...";
|
|
1593
|
+
const checkCmd = options.checkCommand || "vet";
|
|
1594
|
+
return {
|
|
1595
|
+
name: "go",
|
|
1596
|
+
get title() {
|
|
1597
|
+
return t("pluginGoTitle");
|
|
1598
|
+
},
|
|
1599
|
+
triggers: [
|
|
1600
|
+
".go",
|
|
1601
|
+
"go.mod",
|
|
1602
|
+
"go.sum",
|
|
1603
|
+
"go.work"
|
|
1604
|
+
],
|
|
1605
|
+
check: async (ctx) => {
|
|
1606
|
+
const start = performance.now();
|
|
1607
|
+
const cwd = resolve10(ctx.rootDir, moduleDir);
|
|
1608
|
+
const args = checkCmd === "vet" ? ["go", "vet", ...options.extraArgs || [], targetPackage] : ["go", "build", "-n", ...options.extraArgs || [], targetPackage];
|
|
1609
|
+
try {
|
|
1610
|
+
const proc = spawn9(args, {
|
|
1611
|
+
cwd,
|
|
1612
|
+
stdout: "pipe",
|
|
1613
|
+
stderr: "pipe"
|
|
1614
|
+
});
|
|
1615
|
+
const [stdout, stderr] = await Promise.all([
|
|
1616
|
+
new Response(proc.stdout).text(),
|
|
1617
|
+
new Response(proc.stderr).text()
|
|
1618
|
+
]);
|
|
1619
|
+
const exitCode = await proc.exited;
|
|
1620
|
+
const durationMs = performance.now() - start;
|
|
1621
|
+
if (exitCode !== 0) {
|
|
1622
|
+
const outputText = `${stderr}
|
|
1623
|
+
${stdout}`.trim();
|
|
1624
|
+
return {
|
|
1625
|
+
name: "go",
|
|
1626
|
+
title: t("pluginGoTitle"),
|
|
1627
|
+
status: "error",
|
|
1628
|
+
durationMs,
|
|
1629
|
+
details: t("pluginGoError"),
|
|
1630
|
+
diagnostics: [{ message: outputText.slice(-1500), severity: "error" }]
|
|
1631
|
+
};
|
|
1632
|
+
}
|
|
1633
|
+
return {
|
|
1634
|
+
name: "go",
|
|
1635
|
+
title: t("pluginGoTitle"),
|
|
1636
|
+
status: "success",
|
|
1637
|
+
durationMs,
|
|
1638
|
+
details: t("pluginGoSuccess")
|
|
1639
|
+
};
|
|
1640
|
+
} catch (error) {
|
|
1641
|
+
return {
|
|
1642
|
+
name: "go",
|
|
1643
|
+
title: t("pluginGoTitle"),
|
|
1644
|
+
status: "error",
|
|
1645
|
+
durationMs: performance.now() - start,
|
|
1646
|
+
details: `go execution failed: ${error instanceof Error ? error.message : String(error)}`
|
|
1647
|
+
};
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
};
|
|
1651
|
+
}
|
|
1652
|
+
// plugins/python.ts
|
|
1653
|
+
var {spawn: spawn10 } = globalThis.Bun;
|
|
1654
|
+
import { resolve as resolve11 } from "path";
|
|
1655
|
+
function pythonChecker(options = {}) {
|
|
1656
|
+
const pythonBin = options.pythonBin || "python";
|
|
1657
|
+
const sourceDir = options.sourceDir || ".";
|
|
1658
|
+
const mode = options.mode || "fast";
|
|
1659
|
+
return {
|
|
1660
|
+
name: "python",
|
|
1661
|
+
get title() {
|
|
1662
|
+
return t("pluginPythonTitle");
|
|
1663
|
+
},
|
|
1664
|
+
triggers: [
|
|
1665
|
+
".py",
|
|
1666
|
+
"pyproject.toml",
|
|
1667
|
+
"requirements.txt",
|
|
1668
|
+
"setup.py"
|
|
1669
|
+
],
|
|
1670
|
+
check: async (ctx) => {
|
|
1671
|
+
const start = performance.now();
|
|
1672
|
+
const targetPath = resolve11(ctx.rootDir, sourceDir);
|
|
1673
|
+
let targetFiles = options.targetFiles ? [...options.targetFiles] : [];
|
|
1674
|
+
if (targetFiles.length === 0) {
|
|
1675
|
+
try {
|
|
1676
|
+
const glob = new Bun.Glob("**/*.py");
|
|
1677
|
+
const scanned = Array.from(glob.scanSync({ cwd: targetPath, absolute: true }));
|
|
1678
|
+
targetFiles = scanned.filter((f) => !f.includes("__pycache__") && !f.includes(".venv") && !f.includes("site-packages")).slice(0, 50);
|
|
1679
|
+
} catch {
|
|
1680
|
+
targetFiles = [];
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
if (targetFiles.length === 0) {
|
|
1684
|
+
return {
|
|
1685
|
+
name: "python",
|
|
1686
|
+
title: t("pluginPythonTitle"),
|
|
1687
|
+
status: "skipped",
|
|
1688
|
+
durationMs: performance.now() - start,
|
|
1689
|
+
details: t("pluginPythonNoFiles")
|
|
1690
|
+
};
|
|
1691
|
+
}
|
|
1692
|
+
let args;
|
|
1693
|
+
if (mode === "fast") {
|
|
1694
|
+
const fastScript = `import sys
|
|
1695
|
+
for f in sys.argv[1:]:
|
|
1696
|
+
compile(open(f, 'rb').read(), f, 'exec')`;
|
|
1697
|
+
args = [
|
|
1698
|
+
pythonBin,
|
|
1699
|
+
"-S",
|
|
1700
|
+
"-B",
|
|
1701
|
+
...options.extraArgs || [],
|
|
1702
|
+
"-c",
|
|
1703
|
+
fastScript,
|
|
1704
|
+
...targetFiles
|
|
1705
|
+
];
|
|
1706
|
+
} else {
|
|
1707
|
+
args = [
|
|
1708
|
+
pythonBin,
|
|
1709
|
+
"-B",
|
|
1710
|
+
"-m",
|
|
1711
|
+
"py_compile",
|
|
1712
|
+
...options.extraArgs || [],
|
|
1713
|
+
...targetFiles
|
|
1714
|
+
];
|
|
1715
|
+
}
|
|
1716
|
+
try {
|
|
1717
|
+
const proc = spawn10(args, {
|
|
1718
|
+
cwd: ctx.rootDir,
|
|
1719
|
+
stdout: "pipe",
|
|
1720
|
+
stderr: "pipe"
|
|
1721
|
+
});
|
|
1722
|
+
const [stdout, stderr] = await Promise.all([
|
|
1723
|
+
new Response(proc.stdout).text(),
|
|
1724
|
+
new Response(proc.stderr).text()
|
|
1725
|
+
]);
|
|
1726
|
+
const exitCode = await proc.exited;
|
|
1727
|
+
const durationMs = performance.now() - start;
|
|
1728
|
+
if (exitCode !== 0) {
|
|
1729
|
+
const outputText = `${stderr}
|
|
1730
|
+
${stdout}`.trim();
|
|
1731
|
+
return {
|
|
1732
|
+
name: "python",
|
|
1733
|
+
title: t("pluginPythonTitle"),
|
|
1734
|
+
status: "error",
|
|
1735
|
+
durationMs,
|
|
1736
|
+
details: t("pluginPythonError"),
|
|
1737
|
+
diagnostics: [{ message: outputText.slice(-1500), severity: "error" }]
|
|
1738
|
+
};
|
|
1739
|
+
}
|
|
1740
|
+
return {
|
|
1741
|
+
name: "python",
|
|
1742
|
+
title: t("pluginPythonTitle"),
|
|
1743
|
+
status: "success",
|
|
1744
|
+
durationMs,
|
|
1745
|
+
details: t("pluginPythonSuccess", targetFiles.length)
|
|
1746
|
+
};
|
|
1747
|
+
} catch (error) {
|
|
1748
|
+
return {
|
|
1749
|
+
name: "python",
|
|
1750
|
+
title: t("pluginPythonTitle"),
|
|
1751
|
+
status: "error",
|
|
1752
|
+
durationMs: performance.now() - start,
|
|
1753
|
+
details: `${pythonBin} execution failed: ${error instanceof Error ? error.message : String(error)}`
|
|
1754
|
+
};
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
};
|
|
1758
|
+
}
|
|
1759
|
+
// plugins/schema.ts
|
|
1760
|
+
import { readFile } from "fs/promises";
|
|
1761
|
+
import { resolve as resolve12 } from "path";
|
|
1762
|
+
function schemaChecker(options) {
|
|
1763
|
+
const triggers = options.targets.map((t) => t.path.replaceAll("\\", "/"));
|
|
1764
|
+
return {
|
|
1765
|
+
name: "schema",
|
|
1766
|
+
get title() {
|
|
1767
|
+
return t("pluginSchemaTitle");
|
|
1768
|
+
},
|
|
1769
|
+
triggers,
|
|
1770
|
+
check: async (ctx) => {
|
|
1771
|
+
const start = performance.now();
|
|
1772
|
+
const errors = [];
|
|
1773
|
+
let verifiedCount = 0;
|
|
1774
|
+
for (const target of options.targets) {
|
|
1775
|
+
const fullPath = resolve12(ctx.rootDir, target.path);
|
|
1776
|
+
try {
|
|
1777
|
+
const raw = await readFile(fullPath, "utf8");
|
|
1778
|
+
const parsed = JSON.parse(raw);
|
|
1779
|
+
if (target.validator) {
|
|
1780
|
+
const validationError = target.validator(parsed);
|
|
1781
|
+
if (validationError) {
|
|
1782
|
+
errors.push(`${target.path}: ${validationError}`);
|
|
1783
|
+
continue;
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
verifiedCount++;
|
|
1787
|
+
} catch (error) {
|
|
1788
|
+
errors.push(t("pluginSchemaParseFail", target.path, error instanceof Error ? error.message : String(error)));
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
const durationMs = performance.now() - start;
|
|
1792
|
+
if (errors.length > 0) {
|
|
1793
|
+
return {
|
|
1794
|
+
name: "schema",
|
|
1795
|
+
title: t("pluginSchemaTitle"),
|
|
1796
|
+
status: "error",
|
|
1797
|
+
durationMs,
|
|
1798
|
+
details: errors.join(" | "),
|
|
1799
|
+
diagnostics: errors.map((message) => ({ message, severity: "error" }))
|
|
1800
|
+
};
|
|
1801
|
+
}
|
|
1802
|
+
return {
|
|
1803
|
+
name: "schema",
|
|
1804
|
+
title: t("pluginSchemaTitle"),
|
|
1805
|
+
status: "success",
|
|
1806
|
+
durationMs,
|
|
1807
|
+
details: t("pluginSchemaSuccess", verifiedCount)
|
|
1808
|
+
};
|
|
1809
|
+
}
|
|
1810
|
+
};
|
|
1811
|
+
}
|
|
1812
|
+
// plugins/native.ts
|
|
1813
|
+
import { existsSync as existsSync6 } from "fs";
|
|
1814
|
+
import { open } from "fs/promises";
|
|
1815
|
+
import { resolve as resolve13 } from "path";
|
|
1816
|
+
var PE_SIGNATURE_OFFSET_LOCATION = 60;
|
|
1817
|
+
var PE_SIGNATURE = 17744;
|
|
1818
|
+
var PE_MACHINE_X64 = 34404;
|
|
1819
|
+
var DOS_SIGNATURE_MZ = 23117;
|
|
1820
|
+
function nativeChecker(options) {
|
|
1821
|
+
const triggers = options.targets.map((t) => t.path.replaceAll("\\", "/"));
|
|
1822
|
+
return {
|
|
1823
|
+
name: "native",
|
|
1824
|
+
get title() {
|
|
1825
|
+
return t("pluginNativeTitle");
|
|
1826
|
+
},
|
|
1827
|
+
triggers,
|
|
1828
|
+
check: async (ctx) => {
|
|
1829
|
+
const start = performance.now();
|
|
1830
|
+
const errors = [];
|
|
1831
|
+
let checkedCount = 0;
|
|
1832
|
+
for (const target of options.targets) {
|
|
1833
|
+
const fullPath = resolve13(ctx.rootDir, target.path);
|
|
1834
|
+
if (!existsSync6(fullPath)) {
|
|
1835
|
+
errors.push(t("pluginNativeMissing", target.path));
|
|
1836
|
+
continue;
|
|
1837
|
+
}
|
|
1838
|
+
if (fullPath.endsWith(".dll") || fullPath.endsWith(".exe")) {
|
|
1839
|
+
let handle;
|
|
1840
|
+
try {
|
|
1841
|
+
handle = await open(fullPath, "r");
|
|
1842
|
+
const buffer = Buffer.alloc(1024);
|
|
1843
|
+
await handle.read(buffer, 0, 1024, 0);
|
|
1844
|
+
const dosSig = buffer.readUInt16LE(0);
|
|
1845
|
+
if (dosSig !== DOS_SIGNATURE_MZ) {
|
|
1846
|
+
errors.push(t("pluginNativeNotPe", target.path));
|
|
1847
|
+
continue;
|
|
1848
|
+
}
|
|
1849
|
+
const peOffset = buffer.readUInt32LE(PE_SIGNATURE_OFFSET_LOCATION);
|
|
1850
|
+
if (peOffset < buffer.length - 24) {
|
|
1851
|
+
const peSig = buffer.readUInt32LE(peOffset);
|
|
1852
|
+
const machine = buffer.readUInt16LE(peOffset + 4);
|
|
1853
|
+
if (peSig !== PE_SIGNATURE) {
|
|
1854
|
+
errors.push(t("pluginNativeInvalidPe", target.path));
|
|
1855
|
+
} else if (target.expectedArchitecture === "x64" && machine !== PE_MACHINE_X64) {
|
|
1856
|
+
errors.push(t("pluginNativeInvalidArch", target.path, machine.toString(16)));
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
} catch (error) {
|
|
1860
|
+
errors.push(`${target.path}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1861
|
+
continue;
|
|
1862
|
+
} finally {
|
|
1863
|
+
if (handle) {
|
|
1864
|
+
await handle.close().catch(() => {});
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
checkedCount++;
|
|
1869
|
+
}
|
|
1870
|
+
const durationMs = performance.now() - start;
|
|
1871
|
+
if (errors.length > 0) {
|
|
1872
|
+
return {
|
|
1873
|
+
name: "native",
|
|
1874
|
+
title: t("pluginNativeTitle"),
|
|
1875
|
+
status: "error",
|
|
1876
|
+
durationMs,
|
|
1877
|
+
details: errors.join(" | "),
|
|
1878
|
+
diagnostics: errors.map((message) => ({ message, severity: "error" }))
|
|
1879
|
+
};
|
|
1880
|
+
}
|
|
1881
|
+
return {
|
|
1882
|
+
name: "native",
|
|
1883
|
+
title: t("pluginNativeTitle"),
|
|
1884
|
+
status: "success",
|
|
1885
|
+
durationMs,
|
|
1886
|
+
details: t("pluginNativeSuccess", checkedCount)
|
|
1887
|
+
};
|
|
1888
|
+
}
|
|
1889
|
+
};
|
|
1890
|
+
}
|
|
1891
|
+
// plugins/nsis.ts
|
|
1892
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
1893
|
+
import { existsSync as existsSync7 } from "fs";
|
|
1894
|
+
import { resolve as resolve14 } from "path";
|
|
1895
|
+
function nsisChecker(options) {
|
|
1896
|
+
return {
|
|
1897
|
+
name: "nsis",
|
|
1898
|
+
get title() {
|
|
1899
|
+
return t("pluginNsisTitle");
|
|
1900
|
+
},
|
|
1901
|
+
triggers: [options.templatePath.replaceAll("\\", "/")],
|
|
1902
|
+
check: async (ctx) => {
|
|
1903
|
+
const start = performance.now();
|
|
1904
|
+
const errors = [];
|
|
1905
|
+
const fullPath = resolve14(ctx.rootDir, options.templatePath);
|
|
1906
|
+
if (!existsSync7(fullPath)) {
|
|
1907
|
+
errors.push(t("pluginNsisMissing", options.templatePath));
|
|
1908
|
+
} else {
|
|
1909
|
+
try {
|
|
1910
|
+
const content = await readFile2(fullPath, "utf8");
|
|
1911
|
+
if (content.length < 50) {
|
|
1912
|
+
errors.push(t("pluginNsisCorrupt"));
|
|
1913
|
+
}
|
|
1914
|
+
const requiredDirectives = ["Section", "!include"];
|
|
1915
|
+
for (const dir of requiredDirectives) {
|
|
1916
|
+
if (!content.includes(dir)) {
|
|
1917
|
+
errors.push(t("pluginNsisDirectiveMissing", dir));
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
} catch (error) {
|
|
1921
|
+
errors.push(`${options.templatePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
const durationMs = performance.now() - start;
|
|
1925
|
+
if (errors.length > 0) {
|
|
1926
|
+
return {
|
|
1927
|
+
name: "nsis",
|
|
1928
|
+
title: t("pluginNsisTitle"),
|
|
1929
|
+
status: "error",
|
|
1930
|
+
durationMs,
|
|
1931
|
+
details: errors.join(" | "),
|
|
1932
|
+
diagnostics: errors.map((message) => ({ message, severity: "error" }))
|
|
1933
|
+
};
|
|
1934
|
+
}
|
|
1935
|
+
return {
|
|
1936
|
+
name: "nsis",
|
|
1937
|
+
title: t("pluginNsisTitle"),
|
|
1938
|
+
status: "success",
|
|
1939
|
+
durationMs,
|
|
1940
|
+
details: t("pluginNsisSuccess", options.templatePath)
|
|
1941
|
+
};
|
|
1942
|
+
}
|
|
1943
|
+
};
|
|
1944
|
+
}
|
|
1945
|
+
export {
|
|
1946
|
+
analyzeCausalGraph,
|
|
1947
|
+
computeFileHash,
|
|
1948
|
+
cppChecker,
|
|
1949
|
+
createCheckerPlugin,
|
|
1950
|
+
csharpChecker,
|
|
1951
|
+
defineConfig,
|
|
1952
|
+
detectLocale,
|
|
1953
|
+
executeBuild,
|
|
1954
|
+
executeChecks,
|
|
1955
|
+
executePackage,
|
|
1956
|
+
executeSign,
|
|
1957
|
+
getLocale,
|
|
1958
|
+
goChecker,
|
|
1959
|
+
javaChecker,
|
|
1960
|
+
loadBuildCache,
|
|
1961
|
+
loadSynapseConfig,
|
|
1962
|
+
nativeChecker,
|
|
1963
|
+
nsisChecker,
|
|
1964
|
+
pythonChecker,
|
|
1965
|
+
reportResults,
|
|
1966
|
+
rustChecker,
|
|
1967
|
+
saveBuildCache,
|
|
1968
|
+
schemaChecker,
|
|
1969
|
+
setLocale,
|
|
1970
|
+
svelteChecker,
|
|
1971
|
+
t,
|
|
1972
|
+
typescriptChecker
|
|
1973
|
+
};
|