twskin 0.5.3

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.
Files changed (65) hide show
  1. package/CHANGELOG.md +99 -0
  2. package/CONTRIBUTING.md +37 -0
  3. package/LICENSE +21 -0
  4. package/README.md +104 -0
  5. package/SECURITY.md +28 -0
  6. package/dist/bin/twskin.d.ts +3 -0
  7. package/dist/bin/twskin.d.ts.map +1 -0
  8. package/dist/bin/twskin.js +4 -0
  9. package/dist/bin/twskin.js.map +1 -0
  10. package/dist/commands.d.ts +41 -0
  11. package/dist/commands.d.ts.map +1 -0
  12. package/dist/commands.js +421 -0
  13. package/dist/commands.js.map +1 -0
  14. package/dist/context.d.ts +14 -0
  15. package/dist/context.d.ts.map +1 -0
  16. package/dist/context.js +51 -0
  17. package/dist/context.js.map +1 -0
  18. package/dist/errors.d.ts +9 -0
  19. package/dist/errors.d.ts.map +1 -0
  20. package/dist/errors.js +20 -0
  21. package/dist/errors.js.map +1 -0
  22. package/dist/lock.d.ts +3 -0
  23. package/dist/lock.d.ts.map +1 -0
  24. package/dist/lock.js +52 -0
  25. package/dist/lock.js.map +1 -0
  26. package/dist/main.d.ts +9 -0
  27. package/dist/main.d.ts.map +1 -0
  28. package/dist/main.js +92 -0
  29. package/dist/main.js.map +1 -0
  30. package/dist/output.d.ts +4 -0
  31. package/dist/output.d.ts.map +1 -0
  32. package/dist/output.js +27 -0
  33. package/dist/output.js.map +1 -0
  34. package/dist/persistent-cdp.d.ts +14 -0
  35. package/dist/persistent-cdp.d.ts.map +1 -0
  36. package/dist/persistent-cdp.js +140 -0
  37. package/dist/persistent-cdp.js.map +1 -0
  38. package/dist/system.d.ts +64 -0
  39. package/dist/system.d.ts.map +1 -0
  40. package/dist/system.js +234 -0
  41. package/dist/system.js.map +1 -0
  42. package/dist/theme-download.d.ts +9 -0
  43. package/dist/theme-download.d.ts.map +1 -0
  44. package/dist/theme-download.js +250 -0
  45. package/dist/theme-download.js.map +1 -0
  46. package/dist/themes.d.ts +9 -0
  47. package/dist/themes.d.ts.map +1 -0
  48. package/dist/themes.js +185 -0
  49. package/dist/themes.js.map +1 -0
  50. package/dist/types.d.ts +58 -0
  51. package/dist/types.d.ts.map +1 -0
  52. package/dist/types.js +2 -0
  53. package/dist/types.js.map +1 -0
  54. package/docs/publishing.md +45 -0
  55. package/docs/theme-distribution.md +62 -0
  56. package/package.json +74 -0
  57. package/runtime/component-map.mjs +200 -0
  58. package/runtime/injector.mjs +705 -0
  59. package/runtime/manifest.json +47 -0
  60. package/runtime/restore.sh +33 -0
  61. package/runtime/skin.js +1133 -0
  62. package/runtime/start.sh +86 -0
  63. package/runtime/styles/base.css +687 -0
  64. package/runtime/styles/manager.css +346 -0
  65. package/runtime/token-map.mjs +432 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.js","sourceRoot":"","sources":["../src/lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAOvC,SAAS,WAAW,CAAC,OAAmB,EAAE,OAAe;IACvD,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxE,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,MAAM,UAAU,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QACpE,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;QACxH,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC3B,CAAC,CAAC;IAEF,IAAI,CAAC;QACH,OAAO,EAAE,CAAC;IACZ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,KAAK,CAAC;QAC5F,IAAI,KAAK,GAAqB,IAAI,CAAC;QACnC,IAAI,CAAC;YAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAc,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QAClG,IAAI,KAAK,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC,EAAE,yBAAyB,KAAK,CAAC,GAAG,IAAI,EAAE,YAAY,CAAC,CAAC;QACxF,CAAC;QACD,IAAI,CAAC;YAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QACvD,IAAI,CAAC;YAAC,OAAO,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YACxB,MAAM,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC,EAAE,oBAAoB,EAAE,QAAQ,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;IACD,OAAO,GAAG,EAAE,GAAG,IAAI,CAAC;QAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC,CAAC,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAI,OAAmB,EAAE,OAAe,EAAE,SAA+B;IACrG,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC9C,IAAI,CAAC;QAAC,OAAO,MAAM,SAAS,EAAE,CAAC;IAAC,CAAC;YAAS,CAAC;QAAC,OAAO,EAAE,CAAC;IAAC,CAAC;AAC1D,CAAC"}
package/dist/main.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import type { CliOptions } from "./types.js";
2
+ export interface ParsedArguments {
3
+ command: string;
4
+ args: string[];
5
+ options: CliOptions;
6
+ }
7
+ export declare function parseArgs(argv: readonly string[]): ParsedArguments;
8
+ export declare function run(argv?: readonly string[], environment?: NodeJS.ProcessEnv): Promise<void>;
9
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,UAAU,CAAC;CACrB;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,eAAe,CAWlE;AAED,wBAAsB,GAAG,CAAC,IAAI,GAAE,SAAS,MAAM,EAA0B,EAAE,WAAW,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyCtI"}
package/dist/main.js ADDED
@@ -0,0 +1,92 @@
1
+ import process from "node:process";
2
+ import { doctorCommand, downloadThemeCommand, helpText, loadThemeCommand, startCommand, statusCommand, stopCommand, themeCommand, themesCommand, restoreCommand, uninstallCommand, } from "./commands.js";
3
+ import { createContext } from "./context.js";
4
+ import { asCliError, CliError } from "./errors.js";
5
+ import { emit, emitError } from "./output.js";
6
+ export function parseArgs(argv) {
7
+ const options = { json: false, yes: false, help: false };
8
+ const positional = [];
9
+ for (const argument of argv) {
10
+ if (argument === "--json")
11
+ options.json = true;
12
+ else if (argument === "--yes" || argument === "-y")
13
+ options.yes = true;
14
+ else if (argument === "--help" || argument === "-h")
15
+ options.help = true;
16
+ else if (argument.startsWith("-"))
17
+ throw new CliError("UNKNOWN_OPTION", 2, `未知选项:${argument}`, "运行 twskin help 查看用法。");
18
+ else
19
+ positional.push(argument);
20
+ }
21
+ return { command: positional[0] || "help", args: positional.slice(1), options };
22
+ }
23
+ export async function run(argv = process.argv.slice(2), environment = process.env) {
24
+ const context = createContext(environment);
25
+ let parsed;
26
+ try {
27
+ parsed = parseArgs(argv);
28
+ if (parsed.options.help)
29
+ parsed.command = "help";
30
+ const knownCommands = new Set(["start", "stop", "status", "themes", "theme", "doctor", "restore", "uninstall", "version", "help"]);
31
+ if (!knownCommands.has(parsed.command))
32
+ throw new CliError("UNKNOWN_COMMAND", 2, `未知命令:${parsed.command}`, "运行 twskin help 查看用法。");
33
+ const [first, ...rest] = parsed.args;
34
+ if (parsed.command !== "theme" && parsed.command !== "help" && parsed.args.length) {
35
+ throw new CliError("TOO_MANY_ARGUMENTS", 2, "参数过多。", "运行 twskin help 查看用法。");
36
+ }
37
+ switch (parsed.command) {
38
+ case "start":
39
+ await startCommand(context, parsed.options);
40
+ break;
41
+ case "stop":
42
+ await stopCommand(context, parsed.options);
43
+ break;
44
+ case "status":
45
+ await statusCommand(context, parsed.options);
46
+ break;
47
+ case "themes":
48
+ themesCommand(context, parsed.options);
49
+ break;
50
+ case "theme":
51
+ if (first === "download") {
52
+ if (rest.length > 1)
53
+ throw new CliError("TOO_MANY_ARGUMENTS", 2, "参数过多。", "用法:twskin theme download [id]");
54
+ await downloadThemeCommand(context, rest[0], parsed.options);
55
+ }
56
+ else if (first === "load") {
57
+ if (rest.length !== 1)
58
+ throw new CliError(rest.length ? "TOO_MANY_ARGUMENTS" : "THEME_SOURCE_REQUIRED", 2, rest.length ? "参数过多。" : "缺少本地主题目录。", "用法:twskin theme load <directory>");
59
+ await loadThemeCommand(context, rest[0], parsed.options);
60
+ }
61
+ else {
62
+ if (rest.length)
63
+ throw new CliError("TOO_MANY_ARGUMENTS", 2, "参数过多。", "用法:twskin theme <id>");
64
+ await themeCommand(context, first, parsed.options);
65
+ }
66
+ break;
67
+ case "doctor":
68
+ await doctorCommand(context, parsed.options);
69
+ break;
70
+ case "restore":
71
+ await restoreCommand(context, parsed.options);
72
+ break;
73
+ case "uninstall":
74
+ await uninstallCommand(context, parsed.options);
75
+ break;
76
+ case "version":
77
+ emit({ command: "version", version: context.packageVersion }, `twskin ${context.packageVersion}`, parsed.options.json);
78
+ break;
79
+ case "help":
80
+ console.log(helpText(context).trimEnd());
81
+ break;
82
+ }
83
+ }
84
+ catch (error) {
85
+ const cliError = asCliError(error);
86
+ const json = parsed?.options?.json ?? false;
87
+ if (!(cliError.code === "CANCELLED" && !json && process.stdout.isTTY))
88
+ emitError(cliError, json);
89
+ process.exitCode = cliError.exitCode;
90
+ }
91
+ }
92
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { CliError } from "./errors.js";
2
+ export declare function emit(payload: Record<string, unknown>, human: string, json: boolean): void;
3
+ export declare function emitError(error: CliError, json?: boolean): void;
4
+ //# sourceMappingURL=output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAGzF;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,UAAQ,GAAG,IAAI,CAiB7D"}
package/dist/output.js ADDED
@@ -0,0 +1,27 @@
1
+ export function emit(payload, human, json) {
2
+ if (json)
3
+ console.log(JSON.stringify({ schemaVersion: 1, ok: true, ...payload }, null, 2));
4
+ else if (human)
5
+ console.log(human);
6
+ }
7
+ export function emitError(error, json = false) {
8
+ if (json) {
9
+ console.log(JSON.stringify({
10
+ schemaVersion: 1,
11
+ ok: false,
12
+ error: {
13
+ code: error.code,
14
+ message: error.message,
15
+ hint: error.hint || undefined,
16
+ detail: error.detail,
17
+ },
18
+ }, null, 2));
19
+ return;
20
+ }
21
+ console.error(`twskin: ${error.message}`);
22
+ if (error.hint)
23
+ console.error(`建议:${error.hint}`);
24
+ if (process.env.TWSKIN_DEBUG && error.detail)
25
+ console.error(error.detail);
26
+ }
27
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,IAAI,CAAC,OAAgC,EAAE,KAAa,EAAE,IAAa;IACjF,IAAI,IAAI;QAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;SACtF,IAAI,KAAK;QAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAe,EAAE,IAAI,GAAG,KAAK;IACrD,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC;YACzB,aAAa,EAAE,CAAC;YAChB,EAAE,EAAE,KAAK;YACT,KAAK,EAAE;gBACL,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,SAAS;gBAC7B,MAAM,EAAE,KAAK,CAAC,MAAM;aACrB;SACF,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACb,OAAO;IACT,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,WAAW,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1C,IAAI,KAAK,CAAC,IAAI;QAAE,OAAO,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAClD,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,KAAK,CAAC,MAAM;QAAE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AAC5E,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { CliContext } from "./types.js";
2
+ export interface PersistentCdpResult {
3
+ argvFile: string;
4
+ managed: boolean;
5
+ changed: boolean;
6
+ port: number;
7
+ }
8
+ export declare function resolveAppArgvFile(context: CliContext, appBundle: string): string;
9
+ export declare function enablePersistentCdp(context: CliContext, appBundle: string, port: number): PersistentCdpResult;
10
+ export declare function disablePersistentCdp(context: CliContext): {
11
+ changed: boolean;
12
+ argvFile: string | null;
13
+ };
14
+ //# sourceMappingURL=persistent-cdp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistent-cdp.d.ts","sourceRoot":"","sources":["../src/persistent-cdp.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAY7C,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AA2ED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CA0BjF;AAED,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,UAAU,EACnB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,GACX,mBAAmB,CAuCrB;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,UAAU,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAwBvG"}
@@ -0,0 +1,140 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { applyEdits, modify, parse, printParseErrorCode, } from "jsonc-parser";
5
+ import { CliError } from "./errors.js";
6
+ import { atomicWrite } from "./system.js";
7
+ const CDP_KEY = "remote-debugging-port";
8
+ function isRecord(value) {
9
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
10
+ }
11
+ function formattingOptions(text) {
12
+ const tabIndented = /(?:^|\r?\n)\t+"/.test(text);
13
+ return {
14
+ insertSpaces: !tabIndented,
15
+ tabSize: 2,
16
+ eol: text.includes("\r\n") ? "\r\n" : "\n",
17
+ };
18
+ }
19
+ function readJsonc(file) {
20
+ const text = fs.existsSync(file) ? fs.readFileSync(file, "utf8") : "{}\n";
21
+ const errors = [];
22
+ const value = parse(text, errors, { allowTrailingComma: true });
23
+ if (errors.length || !isRecord(value)) {
24
+ const detail = errors[0]
25
+ ? `${printParseErrorCode(errors[0].error)} at offset ${errors[0].offset}`
26
+ : "root value must be an object";
27
+ throw new CliError("APP_ARGV_INVALID", 5, `TRAE 启动参数文件格式无效:${file}`, "请修复 argv.json 后重试。", detail);
28
+ }
29
+ return { text, value };
30
+ }
31
+ function updateProperty(document, value) {
32
+ const edits = modify(document.text, [CDP_KEY], value, {
33
+ formattingOptions: formattingOptions(document.text),
34
+ });
35
+ return applyEdits(document.text, edits);
36
+ }
37
+ function readState(context) {
38
+ if (!fs.existsSync(context.paths.cdpConfigState))
39
+ return null;
40
+ try {
41
+ const value = JSON.parse(fs.readFileSync(context.paths.cdpConfigState, "utf8"));
42
+ if (!isRecord(value)
43
+ || value.schemaVersion !== 1
44
+ || typeof value.argvFile !== "string"
45
+ || !Number.isInteger(value.managedPort)
46
+ || typeof value.previousExists !== "boolean") {
47
+ throw new Error("invalid state shape");
48
+ }
49
+ return value;
50
+ }
51
+ catch (error) {
52
+ throw new CliError("CDP_STATE_INVALID", 5, `持久 CDP 状态文件无效:${context.paths.cdpConfigState}`, "删除该状态文件后重新运行 twskin start。", error instanceof Error ? error.message : String(error));
53
+ }
54
+ }
55
+ function writeState(context, state) {
56
+ atomicWrite(context.paths.cdpConfigState, `${JSON.stringify(state, null, 2)}\n`);
57
+ }
58
+ export function resolveAppArgvFile(context, appBundle) {
59
+ if (context.app.argvFile)
60
+ return context.app.argvFile;
61
+ const productFile = path.join(appBundle, "Contents/Resources/app/product.json");
62
+ try {
63
+ const product = JSON.parse(fs.readFileSync(productFile, "utf8"));
64
+ const folder = product.dataFolderName;
65
+ if (typeof folder !== "string"
66
+ || !folder
67
+ || path.isAbsolute(folder)
68
+ || path.basename(folder) !== folder
69
+ || folder === "."
70
+ || folder === "..") {
71
+ throw new Error("product.json has no safe dataFolderName");
72
+ }
73
+ return path.join(os.homedir(), folder, "argv.json");
74
+ }
75
+ catch (error) {
76
+ throw new CliError("APP_ARGV_UNAVAILABLE", 5, "无法定位 TRAE 的持久启动参数文件。", "确认 TRAE 安装完整后重试。", error instanceof Error ? error.message : String(error));
77
+ }
78
+ }
79
+ export function enablePersistentCdp(context, appBundle, port) {
80
+ const argvFile = resolveAppArgvFile(context, appBundle);
81
+ let state = readState(context);
82
+ if (state && state.argvFile !== argvFile) {
83
+ disablePersistentCdp(context);
84
+ state = null;
85
+ }
86
+ const document = readJsonc(argvFile);
87
+ const currentExists = Object.prototype.hasOwnProperty.call(document.value, CDP_KEY);
88
+ const currentValue = document.value[CDP_KEY];
89
+ if (!state && currentValue === String(port)) {
90
+ return { argvFile, managed: false, changed: false, port };
91
+ }
92
+ const nextState = state && currentValue === String(state.managedPort)
93
+ ? { ...state, managedPort: port }
94
+ : {
95
+ schemaVersion: 1,
96
+ argvFile,
97
+ managedPort: port,
98
+ previousExists: currentExists,
99
+ ...(currentExists ? { previousValue: currentValue } : {}),
100
+ };
101
+ const updated = updateProperty(document, String(port));
102
+ if (updated !== document.text)
103
+ atomicWrite(argvFile, updated);
104
+ try {
105
+ writeState(context, nextState);
106
+ }
107
+ catch (error) {
108
+ if (updated !== document.text)
109
+ atomicWrite(argvFile, document.text);
110
+ throw error;
111
+ }
112
+ return {
113
+ argvFile,
114
+ managed: true,
115
+ changed: updated !== document.text,
116
+ port,
117
+ };
118
+ }
119
+ export function disablePersistentCdp(context) {
120
+ const state = readState(context);
121
+ if (!state)
122
+ return { changed: false, argvFile: null };
123
+ if (!fs.existsSync(state.argvFile)) {
124
+ fs.unlinkSync(context.paths.cdpConfigState);
125
+ return { changed: false, argvFile: state.argvFile };
126
+ }
127
+ const document = readJsonc(state.argvFile);
128
+ const currentValue = document.value[CDP_KEY];
129
+ let changed = false;
130
+ if (currentValue === String(state.managedPort)) {
131
+ const restored = updateProperty(document, state.previousExists ? state.previousValue : undefined);
132
+ if (restored !== document.text) {
133
+ atomicWrite(state.argvFile, restored);
134
+ changed = true;
135
+ }
136
+ }
137
+ fs.unlinkSync(context.paths.cdpConfigState);
138
+ return { changed, argvFile: state.argvFile };
139
+ }
140
+ //# sourceMappingURL=persistent-cdp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistent-cdp.js","sourceRoot":"","sources":["../src/persistent-cdp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ import type { SpawnSyncReturns } from "node:child_process";
2
+ import type { CliContext } from "./types.js";
3
+ interface CommandOptions {
4
+ cwd?: string;
5
+ env?: NodeJS.ProcessEnv;
6
+ inherit?: boolean;
7
+ }
8
+ export interface WatcherStatus {
9
+ pid: number | null;
10
+ alive: boolean;
11
+ expected: boolean;
12
+ command: string;
13
+ }
14
+ export interface CdpVersion {
15
+ Browser?: string;
16
+ [key: string]: unknown;
17
+ }
18
+ export interface IntegrityFailure {
19
+ path: string;
20
+ reason: string;
21
+ }
22
+ interface RuntimeManifestEntry {
23
+ path: string;
24
+ size: number;
25
+ sha256: string;
26
+ }
27
+ interface RuntimeManifest {
28
+ packageVersion?: string;
29
+ files?: RuntimeManifestEntry[];
30
+ }
31
+ export declare function readText(file: string, fallback?: string): string;
32
+ export declare function atomicWrite(file: string, content: string): void;
33
+ export declare function commandResult(context: CliContext, command: string, args: readonly string[], options?: CommandOptions): SpawnSyncReturns<string>;
34
+ export declare function commandText(context: CliContext, command: string, args: readonly string[]): string;
35
+ export declare function readPort(context: CliContext): number;
36
+ export declare function pidAlive(pid: number): boolean;
37
+ export declare function pidCommand(context: CliContext, pid: number): string;
38
+ export declare function watcherStatus(context: CliContext): WatcherStatus;
39
+ export declare function resolveAppBundle(context: CliContext): string;
40
+ export declare function appRunning(context: CliContext, appBundle: string): boolean;
41
+ export declare function portOwner(context: CliContext, port: number): {
42
+ pid: number;
43
+ command: string;
44
+ } | null;
45
+ export declare function cdpVersion(port: number, timeoutMs?: number): Promise<CdpVersion | null>;
46
+ export declare function runInjector(context: CliContext, args: readonly string[]): string;
47
+ export declare function managerStatus(context: CliContext, port: number): {
48
+ ready: boolean;
49
+ version: string | null;
50
+ };
51
+ export declare function stopWatcher(context: CliContext, { strict }?: {
52
+ strict?: boolean;
53
+ }): boolean;
54
+ export declare function startWatcher(context: CliContext, port: number): number;
55
+ export declare function runScript(context: CliContext, script: string, extraEnv?: NodeJS.ProcessEnv): void;
56
+ export declare function verifyRuntimeIntegrity(context: CliContext): {
57
+ available: boolean;
58
+ valid: boolean | null;
59
+ checked: number;
60
+ failures: IntegrityFailure[];
61
+ manifest?: RuntimeManifest;
62
+ };
63
+ export {};
64
+ //# sourceMappingURL=system.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../src/system.ts"],"names":[],"mappings":"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"}
package/dist/system.js ADDED
@@ -0,0 +1,234 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs";
3
+ import http from "node:http";
4
+ import path from "node:path";
5
+ import process from "node:process";
6
+ import { spawn, spawnSync } from "node:child_process";
7
+ import { DEFAULT_PORT } from "./context.js";
8
+ import { CliError } from "./errors.js";
9
+ export function readText(file, fallback = "") {
10
+ try {
11
+ return fs.readFileSync(file, "utf8").trim();
12
+ }
13
+ catch {
14
+ return fallback;
15
+ }
16
+ }
17
+ export function atomicWrite(file, content) {
18
+ fs.mkdirSync(path.dirname(file), { recursive: true });
19
+ const temporary = `${file}.${process.pid}.${Date.now()}.tmp`;
20
+ let mode = 0o600;
21
+ try {
22
+ mode = fs.statSync(file).mode & 0o777;
23
+ }
24
+ catch { }
25
+ fs.writeFileSync(temporary, content, { mode });
26
+ fs.renameSync(temporary, file);
27
+ }
28
+ export function commandResult(context, command, args, options = {}) {
29
+ return spawnSync(command, args, {
30
+ cwd: options.cwd || context.runtimeRoot,
31
+ env: { ...context.env, ...options.env },
32
+ encoding: "utf8",
33
+ stdio: options.inherit ? "inherit" : ["ignore", "pipe", "pipe"],
34
+ });
35
+ }
36
+ export function commandText(context, command, args) {
37
+ const result = commandResult(context, command, args);
38
+ return result.status === 0 ? result.stdout.trim() : "";
39
+ }
40
+ export function readPort(context) {
41
+ const raw = context.env.PORT || readText(context.paths.portFile, String(DEFAULT_PORT));
42
+ const port = Number(raw);
43
+ if (!Number.isInteger(port) || port < 1024 || port > 65535) {
44
+ throw new CliError("INVALID_PORT", 3, `端口配置无效:${raw}`, `删除 ${context.paths.portFile} 后重试。`);
45
+ }
46
+ return port;
47
+ }
48
+ export function pidAlive(pid) {
49
+ if (!Number.isInteger(pid) || pid <= 0)
50
+ return false;
51
+ try {
52
+ process.kill(pid, 0);
53
+ return true;
54
+ }
55
+ catch {
56
+ return false;
57
+ }
58
+ }
59
+ export function pidCommand(context, pid) {
60
+ return commandText(context, "/bin/ps", ["-p", String(pid), "-o", "command="]);
61
+ }
62
+ export function watcherStatus(context) {
63
+ const pid = Number(readText(context.paths.pidFile, "0"));
64
+ const alive = pidAlive(pid);
65
+ const command = alive ? pidCommand(context, pid) : "";
66
+ const expected = alive && command.includes("injector.mjs") && command.includes("--watch");
67
+ return { pid: pid || null, alive, expected, command };
68
+ }
69
+ export function resolveAppBundle(context) {
70
+ if (fs.existsSync(context.app.bundle))
71
+ return context.app.bundle;
72
+ const found = commandText(context, "/usr/bin/mdfind", [
73
+ `kMDItemCFBundleIdentifier == '${context.app.bundleId}'`,
74
+ ]).split("\n").find(Boolean);
75
+ return found || context.app.bundle;
76
+ }
77
+ export function appRunning(context, appBundle) {
78
+ if (!fs.existsSync(appBundle))
79
+ return false;
80
+ return commandResult(context, "/usr/bin/pgrep", ["-f", `${appBundle}/Contents/MacOS/`]).status === 0;
81
+ }
82
+ export function portOwner(context, port) {
83
+ const pidText = commandText(context, "/usr/sbin/lsof", [
84
+ "-nP", `-iTCP:${port}`, "-sTCP:LISTEN", "-t",
85
+ ]).split("\n").find(Boolean);
86
+ const pid = Number(pidText || 0);
87
+ if (!pid)
88
+ return null;
89
+ return { pid, command: pidCommand(context, pid) };
90
+ }
91
+ export function cdpVersion(port, timeoutMs = 800) {
92
+ return new Promise((resolve) => {
93
+ const request = http.get({
94
+ hostname: "127.0.0.1",
95
+ port,
96
+ path: "/json/version",
97
+ timeout: timeoutMs,
98
+ }, (response) => {
99
+ let body = "";
100
+ response.setEncoding("utf8");
101
+ response.on("data", (chunk) => { body += chunk; });
102
+ response.on("end", () => {
103
+ if (response.statusCode !== 200)
104
+ return resolve(null);
105
+ try {
106
+ resolve(JSON.parse(body));
107
+ }
108
+ catch {
109
+ resolve(null);
110
+ }
111
+ });
112
+ });
113
+ request.on("timeout", () => request.destroy());
114
+ request.on("error", () => resolve(null));
115
+ });
116
+ }
117
+ function runtimeEnvironment(context, extra = {}) {
118
+ return {
119
+ TWSKIN_STATE_DIR: context.stateDir,
120
+ TWSKIN_THEMES_DIR: context.themesDir,
121
+ ...extra,
122
+ };
123
+ }
124
+ export function runInjector(context, args) {
125
+ const result = commandResult(context, process.execPath, [
126
+ path.join(context.runtimeRoot, "injector.mjs"),
127
+ ...args,
128
+ "--themes", context.themesDir,
129
+ ], { env: runtimeEnvironment(context) });
130
+ if (result.status !== 0) {
131
+ const detail = (result.stderr || result.stdout || "injector failed").trim();
132
+ throw new CliError("INJECT_FAILED", 5, "主题注入失败。", "运行 twskin doctor 检查环境。", detail);
133
+ }
134
+ return result.stdout.trim();
135
+ }
136
+ export function managerStatus(context, port) {
137
+ const result = commandResult(context, process.execPath, [
138
+ path.join(context.runtimeRoot, "injector.mjs"),
139
+ "--manager-status", "--port", String(port), "--themes", context.themesDir,
140
+ ], { env: runtimeEnvironment(context) });
141
+ if (result.status !== 0)
142
+ return { ready: false, version: null };
143
+ try {
144
+ const status = JSON.parse(result.stdout.trim());
145
+ return { ready: status.ready === true, version: typeof status.version === "string" ? status.version : null };
146
+ }
147
+ catch {
148
+ return { ready: false, version: null };
149
+ }
150
+ }
151
+ export function stopWatcher(context, { strict = false } = {}) {
152
+ const watcher = watcherStatus(context);
153
+ if (!watcher.alive) {
154
+ try {
155
+ fs.unlinkSync(context.paths.pidFile);
156
+ }
157
+ catch { }
158
+ return false;
159
+ }
160
+ if (!watcher.expected) {
161
+ if (strict) {
162
+ throw new CliError("WATCHER_PID_MISMATCH", 5, `PID 文件指向了非 TRAE Work Skin 进程:${watcher.pid}`, "运行 twskin doctor 查看详情。");
163
+ }
164
+ return false;
165
+ }
166
+ try {
167
+ process.kill(watcher.pid, "SIGTERM");
168
+ }
169
+ catch { }
170
+ try {
171
+ fs.unlinkSync(context.paths.pidFile);
172
+ }
173
+ catch { }
174
+ return true;
175
+ }
176
+ export function startWatcher(context, port) {
177
+ stopWatcher(context, { strict: true });
178
+ fs.mkdirSync(context.stateDir, { recursive: true });
179
+ const logFd = fs.openSync(context.paths.logFile, "a", 0o600);
180
+ const child = spawn(process.execPath, [
181
+ path.join(context.runtimeRoot, "injector.mjs"),
182
+ "--watch", "--port", String(port), "--themes", context.themesDir,
183
+ ], {
184
+ cwd: context.runtimeRoot,
185
+ detached: true,
186
+ stdio: ["ignore", logFd, logFd],
187
+ env: { ...context.env, ...runtimeEnvironment(context) },
188
+ });
189
+ child.unref();
190
+ fs.closeSync(logFd);
191
+ if (!child.pid)
192
+ throw new CliError("WATCHER_START_FAILED", 5, "守护进程启动失败。", "运行 twskin doctor 检查环境。");
193
+ atomicWrite(context.paths.pidFile, `${child.pid}\n`);
194
+ atomicWrite(context.paths.portFile, `${port}\n`);
195
+ return child.pid;
196
+ }
197
+ export function runScript(context, script, extraEnv = {}) {
198
+ const file = path.join(context.runtimeRoot, script);
199
+ const result = commandResult(context, file, [], {
200
+ inherit: true,
201
+ env: runtimeEnvironment(context, extraEnv),
202
+ });
203
+ if (result.status !== 0) {
204
+ throw new CliError("SCRIPT_FAILED", 5, `${script} 执行失败。`, "运行 twskin doctor 检查环境。", { status: result.status });
205
+ }
206
+ }
207
+ export function verifyRuntimeIntegrity(context) {
208
+ if (!fs.existsSync(context.paths.runtimeManifest)) {
209
+ return { available: false, valid: null, checked: 0, failures: [] };
210
+ }
211
+ try {
212
+ const manifest = JSON.parse(fs.readFileSync(context.paths.runtimeManifest, "utf8"));
213
+ const failures = [];
214
+ for (const entry of manifest.files || []) {
215
+ const file = path.resolve(context.runtimeRoot, entry.path);
216
+ if (!file.startsWith(`${context.runtimeRoot}${path.sep}`) || !fs.existsSync(file)) {
217
+ failures.push({ path: entry.path, reason: "missing" });
218
+ continue;
219
+ }
220
+ const content = fs.readFileSync(file);
221
+ const digest = crypto.createHash("sha256").update(content).digest("hex");
222
+ if (content.byteLength !== entry.size || digest !== entry.sha256) {
223
+ failures.push({ path: entry.path, reason: "digest" });
224
+ }
225
+ }
226
+ if (manifest.packageVersion !== context.packageVersion)
227
+ failures.push({ path: "manifest.json", reason: "version" });
228
+ return { available: true, valid: failures.length === 0, checked: manifest.files?.length || 0, failures, manifest };
229
+ }
230
+ catch (error) {
231
+ return { available: true, valid: false, checked: 0, failures: [{ path: "manifest.json", reason: error instanceof Error ? error.message : String(error) }] };
232
+ }
233
+ }
234
+ //# sourceMappingURL=system.js.map