@ps-generator-bridge/cli 0.1.4
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/LICENSE +21 -0
- package/README.md +98 -0
- package/README_zh.md +93 -0
- package/dist/cli.js +349 -0
- package/dist/cli.js.map +1 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 wojzj57
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# `@ps-generator-bridge/cli`
|
|
2
|
+
|
|
3
|
+
Command-line tools for PS Generator Bridge. The current commands are a Windows-only smoke harness for PS Generator Bridge plugins: they start Adobe `generator-core` against the published generator package, verify the bridge server, check plugin discovery, and perform an SDK `getServerInfo` smoke call.
|
|
4
|
+
|
|
5
|
+
Online documentation:
|
|
6
|
+
|
|
7
|
+
- English: https://wojzj57.github.io/ps-generator-bridge-service/generator/photoshop-setup
|
|
8
|
+
- Chinese: https://wojzj57.github.io/ps-generator-bridge-service/zh/generator/photoshop-setup
|
|
9
|
+
|
|
10
|
+
Related public docs:
|
|
11
|
+
|
|
12
|
+
- [Photoshop Setup](../../docs/generator/photoshop-setup.md)
|
|
13
|
+
- [Troubleshooting](../../docs/generator/troubleshooting.md)
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install -D @ps-generator-bridge/cli
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
In this monorepo:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pnpm --filter @ps-generator-bridge/cli build
|
|
25
|
+
pnpm --filter @ps-generator-bridge/cli typecheck
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Requirements
|
|
29
|
+
|
|
30
|
+
- Windows
|
|
31
|
+
- Node.js >=18
|
|
32
|
+
- Photoshop already running
|
|
33
|
+
- Photoshop Generator enabled
|
|
34
|
+
- Photoshop Remote Connections enabled
|
|
35
|
+
- Git and npm available for installing Adobe `generator-core`
|
|
36
|
+
|
|
37
|
+
## Commands
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
ps-generator-bridge setup-core [--update]
|
|
41
|
+
ps-generator-bridge run (--plugin <dir> | --plugins-dir <dir>) [--expect-plugin <id>] [--port <number>] [--timeout <ms>] [--update-core]
|
|
42
|
+
ps-generator-bridge dev (--plugin <dir> | --plugins-dir <dir>) [--expect-plugin <id>] [--port <number>] [--timeout <ms>] [--update-core]
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### `setup-core`
|
|
46
|
+
|
|
47
|
+
Clones or updates Adobe `generator-core` and runs `npm install`.
|
|
48
|
+
|
|
49
|
+
When run inside a pnpm workspace, `generator-core` is stored at:
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
<workspace-root>/generator-core
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Outside a pnpm workspace, it falls back to:
|
|
56
|
+
|
|
57
|
+
```text
|
|
58
|
+
<system-temp>/ps-generator-bridge/generator-core
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### `run`
|
|
62
|
+
|
|
63
|
+
Starts `generator-core`, waits for `GET /health`, validates `GET /plugins`, runs an SDK `getServerInfo` smoke call, prints the result, and exits.
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
ps-generator-bridge run --plugin ./my-plugin --expect-plugin myPlugin
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### `dev`
|
|
70
|
+
|
|
71
|
+
Starts the same harness and keeps `generator-core` running until interrupted.
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
ps-generator-bridge dev --plugins-dir ./plugins --port 7700
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Plugin Inputs
|
|
78
|
+
|
|
79
|
+
Use exactly one of:
|
|
80
|
+
|
|
81
|
+
- `--plugin <dir>` for a single plugin package directory
|
|
82
|
+
- `--plugins-dir <dir>` for a directory whose direct children are plugin package directories
|
|
83
|
+
|
|
84
|
+
`--expect-plugin <id>` can be repeated. The harness fails if any expected id is missing from `/plugins`.
|
|
85
|
+
|
|
86
|
+
## What the Harness Verifies
|
|
87
|
+
|
|
88
|
+
1. Photoshop is running.
|
|
89
|
+
2. `generator-core` is installed and can start.
|
|
90
|
+
3. The generator package can be loaded by `generator-core`.
|
|
91
|
+
4. The bridge server becomes healthy.
|
|
92
|
+
5. The number of loaded plugins matches the candidate plugin directories.
|
|
93
|
+
6. Expected plugin ids are present.
|
|
94
|
+
7. The SDK can connect over WebSocket and call `getServerInfo`.
|
|
95
|
+
|
|
96
|
+
## Limits
|
|
97
|
+
|
|
98
|
+
This CLI does not expose a public import API. The current smoke harness is not a full integration test framework; it does not drive Photoshop documents or assert plugin-specific UI/workflow behavior. Use package unit tests for deterministic logic and use this CLI to verify the real Photoshop boot path.
|
package/README_zh.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# `@ps-generator-bridge/cli`
|
|
2
|
+
|
|
3
|
+
PS Generator Bridge 的命令行工具。当前命令是一组 Windows-only 冒烟验证工具:它会用已发布的 generator 包启动 Adobe `generator-core`,验证 bridge 服务、插件发现,并通过 SDK 执行一次 `getServerInfo` 冒烟调用。
|
|
4
|
+
|
|
5
|
+
Online documentation:
|
|
6
|
+
|
|
7
|
+
- English: https://wojzj57.github.io/ps-generator-bridge-service/generator/photoshop-setup
|
|
8
|
+
- Chinese: https://wojzj57.github.io/ps-generator-bridge-service/zh/generator/photoshop-setup
|
|
9
|
+
|
|
10
|
+
## 安装
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install -D @ps-generator-bridge/cli
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
在本 monorepo 中开发:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pnpm --filter @ps-generator-bridge/cli build
|
|
20
|
+
pnpm --filter @ps-generator-bridge/cli typecheck
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## 环境要求
|
|
24
|
+
|
|
25
|
+
- Windows
|
|
26
|
+
- Node.js >=18
|
|
27
|
+
- Photoshop 已经运行
|
|
28
|
+
- Photoshop Generator 已启用
|
|
29
|
+
- Photoshop Remote Connections 已启用
|
|
30
|
+
- 可用的 Git 和 npm,用于安装 Adobe `generator-core`
|
|
31
|
+
|
|
32
|
+
## 命令
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
ps-generator-bridge setup-core [--update]
|
|
36
|
+
ps-generator-bridge run (--plugin <dir> | --plugins-dir <dir>) [--expect-plugin <id>] [--port <number>] [--timeout <ms>] [--update-core]
|
|
37
|
+
ps-generator-bridge dev (--plugin <dir> | --plugins-dir <dir>) [--expect-plugin <id>] [--port <number>] [--timeout <ms>] [--update-core]
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### `setup-core`
|
|
41
|
+
|
|
42
|
+
克隆或更新 Adobe `generator-core`,并在该目录中执行 `npm install`。
|
|
43
|
+
|
|
44
|
+
在 pnpm workspace 内运行时,`generator-core` 存放在:
|
|
45
|
+
|
|
46
|
+
```text
|
|
47
|
+
<workspace-root>/generator-core
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
不在 pnpm workspace 内运行时,回退到:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
<system-temp>/ps-generator-bridge/generator-core
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### `run`
|
|
57
|
+
|
|
58
|
+
启动 `generator-core`,等待 `GET /health`,校验 `GET /plugins`,执行 SDK `getServerInfo` 冒烟调用,打印结果后退出。
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
ps-generator-bridge run --plugin ./my-plugin --expect-plugin myPlugin
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### `dev`
|
|
65
|
+
|
|
66
|
+
启动相同的 harness,但保持 `generator-core` 运行直到手动中断。
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
ps-generator-bridge dev --plugins-dir ./plugins --port 7700
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## 插件输入
|
|
73
|
+
|
|
74
|
+
必须且只能使用其中一种:
|
|
75
|
+
|
|
76
|
+
- `--plugin <dir>`:单个插件包目录
|
|
77
|
+
- `--plugins-dir <dir>`:直接子目录均为插件包的目录
|
|
78
|
+
|
|
79
|
+
`--expect-plugin <id>` 可以重复传入。如果 `/plugins` 中缺少任何期望 id,harness 会失败。
|
|
80
|
+
|
|
81
|
+
## Harness 验证内容
|
|
82
|
+
|
|
83
|
+
1. Photoshop 正在运行。
|
|
84
|
+
2. `generator-core` 已安装并能启动。
|
|
85
|
+
3. generator 包能被 `generator-core` 加载。
|
|
86
|
+
4. bridge 服务进入 healthy 状态。
|
|
87
|
+
5. 已加载插件数量与候选插件目录数量一致。
|
|
88
|
+
6. 期望插件 id 均存在。
|
|
89
|
+
7. SDK 能通过 WebSocket 连接并调用 `getServerInfo`。
|
|
90
|
+
|
|
91
|
+
## 限制
|
|
92
|
+
|
|
93
|
+
该 CLI 不暴露可 import 的公共 API。当前冒烟验证工具不是完整集成测试框架,不会驱动 Photoshop 文档,也不会断言插件自己的 UI 或业务流程。确定性逻辑应使用 package 单元测试;该 CLI 用于验证真实 Photoshop 启动链路。
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/core.ts
|
|
4
|
+
import { execFileSync as execFileSync3, spawn } from "child_process";
|
|
5
|
+
import { createRequire } from "module";
|
|
6
|
+
import { dirname as dirname2, join as join3 } from "path";
|
|
7
|
+
import { Connection } from "@ps-generator-bridge/sdk";
|
|
8
|
+
import WebSocketImpl from "ws";
|
|
9
|
+
|
|
10
|
+
// src/generatorCore.ts
|
|
11
|
+
import { execFileSync } from "child_process";
|
|
12
|
+
import { existsSync, mkdirSync } from "fs";
|
|
13
|
+
import { tmpdir } from "os";
|
|
14
|
+
import { dirname, join, parse, resolve } from "path";
|
|
15
|
+
var REPO = "https://github.com/adobe-photoshop/generator-core";
|
|
16
|
+
function generatorCoreDir() {
|
|
17
|
+
const workspaceRoot = findWorkspaceRoot(process.cwd());
|
|
18
|
+
if (workspaceRoot) return join(workspaceRoot, "generator-core");
|
|
19
|
+
return join(tmpdir(), "ps-generator-bridge", "generator-core");
|
|
20
|
+
}
|
|
21
|
+
async function ensureGeneratorCore(options) {
|
|
22
|
+
const dir = generatorCoreDir();
|
|
23
|
+
mkdirSync(dirname(dir), { recursive: true });
|
|
24
|
+
if (!existsSync(join(dir, ".git"))) {
|
|
25
|
+
run("git", ["clone", REPO, dir], void 0);
|
|
26
|
+
} else if (options.update) {
|
|
27
|
+
run("git", ["pull", "--ff-only"], dir);
|
|
28
|
+
}
|
|
29
|
+
run("npm", ["install"], dir);
|
|
30
|
+
}
|
|
31
|
+
function run(command, args, cwd) {
|
|
32
|
+
console.log(`[generator-core] ${command} ${args.join(" ")}`);
|
|
33
|
+
execFileSync(command, args, {
|
|
34
|
+
cwd,
|
|
35
|
+
stdio: "inherit",
|
|
36
|
+
shell: process.platform === "win32"
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function findWorkspaceRoot(start) {
|
|
40
|
+
let current = resolve(start);
|
|
41
|
+
const root = parse(current).root;
|
|
42
|
+
while (true) {
|
|
43
|
+
if (existsSync(join(current, "pnpm-workspace.yaml"))) return current;
|
|
44
|
+
if (current === root) return void 0;
|
|
45
|
+
current = dirname(current);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// src/photoshop.ts
|
|
50
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
51
|
+
function ensurePhotoshopRunning() {
|
|
52
|
+
const output = execFileSync2("tasklist", ["/FI", "IMAGENAME eq Photoshop.exe", "/NH"], {
|
|
53
|
+
encoding: "utf8"
|
|
54
|
+
});
|
|
55
|
+
if (!output.toLowerCase().includes("photoshop.exe")) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
"Photoshop is not running. Please open Photoshop first, then rerun this command."
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// src/pluginDirs.ts
|
|
63
|
+
import {
|
|
64
|
+
existsSync as existsSync2,
|
|
65
|
+
lstatSync,
|
|
66
|
+
mkdirSync as mkdirSync2,
|
|
67
|
+
mkdtempSync,
|
|
68
|
+
realpathSync,
|
|
69
|
+
readdirSync,
|
|
70
|
+
rmSync,
|
|
71
|
+
symlinkSync
|
|
72
|
+
} from "fs";
|
|
73
|
+
import { basename, join as join2, resolve as resolve2 } from "path";
|
|
74
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
75
|
+
async function preparePluginSource(options) {
|
|
76
|
+
if (options.pluginsDir) {
|
|
77
|
+
const pluginsDir2 = requireDirectory(options.pluginsDir, "--plugins-dir");
|
|
78
|
+
return { pluginsDir: pluginsDir2 };
|
|
79
|
+
}
|
|
80
|
+
const pluginDir = requireDirectory(options.plugin, "--plugin");
|
|
81
|
+
requirePackageEntry(pluginDir);
|
|
82
|
+
const tempRoot = mkdtempSync(join2(tmpdir2(), "ps-generator-bridge-"));
|
|
83
|
+
const pluginsDir = join2(tempRoot, "plugins");
|
|
84
|
+
const linkName = safeName(basename(pluginDir));
|
|
85
|
+
const linkPath = join2(pluginsDir, linkName);
|
|
86
|
+
rmSync(pluginsDir, { recursive: true, force: true });
|
|
87
|
+
mkdirSync2(pluginsDir, { recursive: true });
|
|
88
|
+
symlinkSync(pluginDir, linkPath, process.platform === "win32" ? "junction" : "dir");
|
|
89
|
+
return { pluginsDir, cleanupDir: tempRoot };
|
|
90
|
+
}
|
|
91
|
+
async function cleanupPluginSource(source) {
|
|
92
|
+
if (source.cleanupDir) rmSync(source.cleanupDir, { recursive: true, force: true });
|
|
93
|
+
}
|
|
94
|
+
function scanPluginCandidates(pluginsDir) {
|
|
95
|
+
return readdirSync(pluginsDir, { withFileTypes: true }).filter((entry) => {
|
|
96
|
+
if (entry.name === "node_modules" || entry.name.startsWith(".")) return false;
|
|
97
|
+
if (entry.isDirectory()) return true;
|
|
98
|
+
if (!entry.isSymbolicLink()) return false;
|
|
99
|
+
return lstatSync(join2(pluginsDir, entry.name)).isSymbolicLink();
|
|
100
|
+
}).map((entry) => entry.name).filter((name) => existsSync2(join2(pluginsDir, name, "package.json"))).sort();
|
|
101
|
+
}
|
|
102
|
+
function requireDirectory(input, flag) {
|
|
103
|
+
if (!input) throw new Error(`${flag} is required`);
|
|
104
|
+
const dir = realpathSync(resolve2(input));
|
|
105
|
+
if (!lstatSync(dir).isDirectory()) throw new Error(`${flag} must point to a directory: ${input}`);
|
|
106
|
+
return dir;
|
|
107
|
+
}
|
|
108
|
+
function requirePackageEntry(dir) {
|
|
109
|
+
const packageJson = join2(dir, "package.json");
|
|
110
|
+
if (!existsSync2(packageJson)) throw new Error(`Plugin directory has no package.json: ${dir}`);
|
|
111
|
+
}
|
|
112
|
+
function safeName(name) {
|
|
113
|
+
return name.replace(/[^A-Za-z0-9_.-]/g, "_") || "plugin";
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// src/core.ts
|
|
117
|
+
var DEFAULT_PORT = 7700;
|
|
118
|
+
var DEFAULT_TIMEOUT_MS = 6e4;
|
|
119
|
+
var require2 = createRequire(import.meta.url);
|
|
120
|
+
async function setupGeneratorCore(options = {}) {
|
|
121
|
+
await ensureGeneratorCore({ update: options.update ?? false });
|
|
122
|
+
}
|
|
123
|
+
async function runHarness(options) {
|
|
124
|
+
await withHarness(options, async (ctx) => {
|
|
125
|
+
console.log(`PS Generator Bridge server ready: http://127.0.0.1:${ctx.port}`);
|
|
126
|
+
console.log(`Loaded plugins: ${formatPlugins(ctx.plugins)}`);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
async function runDev(options) {
|
|
130
|
+
await withHarness(options, async (ctx) => {
|
|
131
|
+
console.log(`PS Generator Bridge dev server ready: http://127.0.0.1:${ctx.port}`);
|
|
132
|
+
console.log(`WebSocket: ws://127.0.0.1:${ctx.port}/ws`);
|
|
133
|
+
console.log(`Loaded plugins: ${formatPlugins(ctx.plugins)}`);
|
|
134
|
+
console.log("Press Ctrl+C to stop generator-core.");
|
|
135
|
+
await waitForInterrupt();
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
async function withHarness(options, body) {
|
|
139
|
+
ensureWindows();
|
|
140
|
+
ensurePhotoshopRunning();
|
|
141
|
+
await ensureGeneratorCore({ update: options.updateCore ?? false });
|
|
142
|
+
const port = options.port ?? DEFAULT_PORT;
|
|
143
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
144
|
+
const pluginSource = await preparePluginSource(options);
|
|
145
|
+
const expectedCount = scanPluginCandidates(pluginSource.pluginsDir).length;
|
|
146
|
+
let child;
|
|
147
|
+
try {
|
|
148
|
+
child = startGeneratorCore({
|
|
149
|
+
port,
|
|
150
|
+
pluginsDir: pluginSource.pluginsDir,
|
|
151
|
+
hostPluginDir: resolveHostGeneratorDir()
|
|
152
|
+
});
|
|
153
|
+
await waitForHealth(port, timeoutMs);
|
|
154
|
+
const plugins = await readPlugins(port);
|
|
155
|
+
assertPlugins({ plugins, expectedCount, expectPlugins: options.expectPlugins });
|
|
156
|
+
const info = await smokeServerInfo(port, timeoutMs);
|
|
157
|
+
console.log(
|
|
158
|
+
`Server info: ${info.name} ${info.version}${info.psVersion ? `, Photoshop ${info.psVersion}` : ""}`
|
|
159
|
+
);
|
|
160
|
+
await body({ port, plugins });
|
|
161
|
+
} finally {
|
|
162
|
+
if (child) stopProcessTree(child);
|
|
163
|
+
await cleanupPluginSource(pluginSource);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function ensureWindows() {
|
|
167
|
+
if (process.platform !== "win32") {
|
|
168
|
+
throw new Error("ps-generator-bridge only supports Windows for run/dev in this version.");
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function startGeneratorCore(options) {
|
|
172
|
+
const app = join3(generatorCoreDir(), "app.js");
|
|
173
|
+
console.log(`Starting generator-core: ${app}`);
|
|
174
|
+
const child = spawn(process.execPath, [app, "-f", options.hostPluginDir], {
|
|
175
|
+
cwd: generatorCoreDir(),
|
|
176
|
+
env: {
|
|
177
|
+
...process.env,
|
|
178
|
+
PS_BRIDGE_PLUGINS_DIR: options.pluginsDir,
|
|
179
|
+
PS_BRIDGE_PORT: String(options.port)
|
|
180
|
+
},
|
|
181
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
182
|
+
});
|
|
183
|
+
child.stdout?.on("data", (chunk) => process.stdout.write(chunk));
|
|
184
|
+
child.stderr?.on("data", (chunk) => process.stderr.write(chunk));
|
|
185
|
+
child.on("exit", (code, signal) => {
|
|
186
|
+
if (code !== null && code !== 0) console.error(`generator-core exited with code ${code}`);
|
|
187
|
+
if (signal) console.error(`generator-core exited with signal ${signal}`);
|
|
188
|
+
});
|
|
189
|
+
return child;
|
|
190
|
+
}
|
|
191
|
+
async function waitForHealth(port, timeoutMs) {
|
|
192
|
+
const deadline = Date.now() + timeoutMs;
|
|
193
|
+
const url = `http://127.0.0.1:${port}/health`;
|
|
194
|
+
while (Date.now() < deadline) {
|
|
195
|
+
try {
|
|
196
|
+
const response = await fetch(url);
|
|
197
|
+
if (response.ok) return;
|
|
198
|
+
} catch {
|
|
199
|
+
}
|
|
200
|
+
await delay(500);
|
|
201
|
+
}
|
|
202
|
+
throw new Error(
|
|
203
|
+
"Photoshop is running, but PS Generator Bridge server did not become ready. Verify Generator and Remote Connections are enabled."
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
async function readPlugins(port) {
|
|
207
|
+
const response = await fetch(`http://127.0.0.1:${port}/plugins`);
|
|
208
|
+
if (!response.ok) throw new Error(`GET /plugins failed with HTTP ${response.status}`);
|
|
209
|
+
const body = await response.json();
|
|
210
|
+
return Array.isArray(body.plugins) ? body.plugins : [];
|
|
211
|
+
}
|
|
212
|
+
async function smokeServerInfo(port, timeoutMs) {
|
|
213
|
+
const connection = new Connection({
|
|
214
|
+
url: `ws://127.0.0.1:${port}/ws`,
|
|
215
|
+
WebSocket: WebSocketImpl,
|
|
216
|
+
timeoutMs,
|
|
217
|
+
maxRetries: 0
|
|
218
|
+
});
|
|
219
|
+
try {
|
|
220
|
+
return await connection.getServerInfo();
|
|
221
|
+
} finally {
|
|
222
|
+
connection.close();
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
function assertPlugins(options) {
|
|
226
|
+
const ids = new Set(options.plugins.map((plugin) => plugin.id));
|
|
227
|
+
if (options.plugins.length !== options.expectedCount) {
|
|
228
|
+
throw new Error(
|
|
229
|
+
`Expected ${options.expectedCount} plugin(s), but host loaded ${options.plugins.length}: ${formatPlugins(options.plugins)}`
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
for (const id of options.expectPlugins) {
|
|
233
|
+
if (!ids.has(id)) throw new Error(`Expected plugin '${id}' was not loaded.`);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
function resolveHostGeneratorDir() {
|
|
237
|
+
return dirname2(require2.resolve("@ps-generator-bridge/generator"));
|
|
238
|
+
}
|
|
239
|
+
function stopProcessTree(child) {
|
|
240
|
+
if (!child.pid || child.exitCode !== null) return;
|
|
241
|
+
if (process.platform === "win32") {
|
|
242
|
+
execFileSync3("taskkill", ["/PID", String(child.pid), "/T", "/F"], { stdio: "ignore" });
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
child.kill();
|
|
246
|
+
}
|
|
247
|
+
function formatPlugins(plugins) {
|
|
248
|
+
return plugins.length > 0 ? plugins.map((plugin) => plugin.id).join(", ") : "(none)";
|
|
249
|
+
}
|
|
250
|
+
function waitForInterrupt() {
|
|
251
|
+
return new Promise((resolve3) => {
|
|
252
|
+
process.once("SIGINT", resolve3);
|
|
253
|
+
process.once("SIGTERM", resolve3);
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
function delay(ms) {
|
|
257
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// src/cli.ts
|
|
261
|
+
var USAGE = `Usage:
|
|
262
|
+
ps-generator-bridge setup-core [--update]
|
|
263
|
+
ps-generator-bridge run (--plugin <dir> | --plugins-dir <dir>) [--expect-plugin <id>] [--port <number>] [--timeout <ms>] [--update-core]
|
|
264
|
+
ps-generator-bridge dev (--plugin <dir> | --plugins-dir <dir>) [--expect-plugin <id>] [--port <number>] [--timeout <ms>] [--update-core]`;
|
|
265
|
+
async function main() {
|
|
266
|
+
const parsed = parseArgs(process.argv.slice(2));
|
|
267
|
+
if (parsed.command === "setup-core") {
|
|
268
|
+
await setupGeneratorCore({ update: parsed.options.updateCore ?? parsed.options.update });
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
if (parsed.command === "run") {
|
|
272
|
+
await runHarness(parsed.options);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
await runDev(parsed.options);
|
|
276
|
+
}
|
|
277
|
+
function parseArgs(args) {
|
|
278
|
+
if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
|
|
279
|
+
console.log(USAGE);
|
|
280
|
+
process.exit(0);
|
|
281
|
+
}
|
|
282
|
+
const command = args.shift();
|
|
283
|
+
if (command !== "setup-core" && command !== "run" && command !== "dev") {
|
|
284
|
+
throw usage(`Unknown command: ${command ?? "(missing)"}`);
|
|
285
|
+
}
|
|
286
|
+
const options = {
|
|
287
|
+
expectPlugins: []
|
|
288
|
+
};
|
|
289
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
290
|
+
const arg = args[i];
|
|
291
|
+
switch (arg) {
|
|
292
|
+
case "--update":
|
|
293
|
+
options.update = true;
|
|
294
|
+
break;
|
|
295
|
+
case "--update-core":
|
|
296
|
+
options.updateCore = true;
|
|
297
|
+
break;
|
|
298
|
+
case "--plugin":
|
|
299
|
+
options.plugin = readValue(args, ++i, arg);
|
|
300
|
+
break;
|
|
301
|
+
case "--plugins-dir":
|
|
302
|
+
options.pluginsDir = readValue(args, ++i, arg);
|
|
303
|
+
break;
|
|
304
|
+
case "--expect-plugin":
|
|
305
|
+
options.expectPlugins.push(readValue(args, ++i, arg));
|
|
306
|
+
break;
|
|
307
|
+
case "--port":
|
|
308
|
+
options.port = readNumber(readValue(args, ++i, arg), arg);
|
|
309
|
+
break;
|
|
310
|
+
case "--timeout":
|
|
311
|
+
options.timeoutMs = readNumber(readValue(args, ++i, arg), arg);
|
|
312
|
+
break;
|
|
313
|
+
case "--help":
|
|
314
|
+
case "-h":
|
|
315
|
+
console.log(USAGE);
|
|
316
|
+
process.exit(0);
|
|
317
|
+
default:
|
|
318
|
+
throw usage(`Unknown option: ${arg}`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
if (command === "setup-core") return { command, options };
|
|
322
|
+
if (options.plugin && options.pluginsDir) {
|
|
323
|
+
throw usage("--plugin and --plugins-dir are mutually exclusive");
|
|
324
|
+
}
|
|
325
|
+
if (!options.plugin && !options.pluginsDir) {
|
|
326
|
+
throw usage("Either --plugin or --plugins-dir is required");
|
|
327
|
+
}
|
|
328
|
+
return { command, options };
|
|
329
|
+
}
|
|
330
|
+
function readValue(args, index, name) {
|
|
331
|
+
const value = args[index];
|
|
332
|
+
if (!value || value.startsWith("--")) throw usage(`${name} requires a value`);
|
|
333
|
+
return value;
|
|
334
|
+
}
|
|
335
|
+
function readNumber(value, name) {
|
|
336
|
+
const parsed = Number(value);
|
|
337
|
+
if (!Number.isInteger(parsed) || parsed <= 0) throw usage(`${name} must be a positive integer`);
|
|
338
|
+
return parsed;
|
|
339
|
+
}
|
|
340
|
+
function usage(message) {
|
|
341
|
+
return new Error(`${message}
|
|
342
|
+
|
|
343
|
+
${USAGE}`);
|
|
344
|
+
}
|
|
345
|
+
main().catch((error) => {
|
|
346
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
347
|
+
process.exitCode = 1;
|
|
348
|
+
});
|
|
349
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core.ts","../src/generatorCore.ts","../src/photoshop.ts","../src/pluginDirs.ts","../src/cli.ts"],"sourcesContent":["import { execFileSync, spawn, type ChildProcess } from \"node:child_process\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join } from \"node:path\";\nimport { Connection, type PluginInfo } from \"@ps-generator-bridge/sdk\";\nimport WebSocketImpl from \"ws\";\nimport { ensureGeneratorCore, generatorCoreDir } from \"./generatorCore\";\nimport { ensurePhotoshopRunning } from \"./photoshop\";\nimport { cleanupPluginSource, preparePluginSource, scanPluginCandidates } from \"./pluginDirs\";\n\nconst DEFAULT_PORT = 7700;\nconst DEFAULT_TIMEOUT_MS = 60_000;\nconst require = createRequire(import.meta.url);\n\nexport interface HarnessOptions {\n plugin?: string;\n pluginsDir?: string;\n expectPlugins: string[];\n port?: number;\n timeoutMs?: number;\n updateCore?: boolean;\n}\n\nexport async function setupGeneratorCore(options: { update?: boolean } = {}): Promise<void> {\n await ensureGeneratorCore({ update: options.update ?? false });\n}\n\nexport async function runHarness(options: HarnessOptions): Promise<void> {\n await withHarness(options, async (ctx) => {\n console.log(`PS Generator Bridge server ready: http://127.0.0.1:${ctx.port}`);\n console.log(`Loaded plugins: ${formatPlugins(ctx.plugins)}`);\n });\n}\n\nexport async function runDev(options: HarnessOptions): Promise<void> {\n await withHarness(options, async (ctx) => {\n console.log(`PS Generator Bridge dev server ready: http://127.0.0.1:${ctx.port}`);\n console.log(`WebSocket: ws://127.0.0.1:${ctx.port}/ws`);\n console.log(`Loaded plugins: ${formatPlugins(ctx.plugins)}`);\n console.log(\"Press Ctrl+C to stop generator-core.\");\n await waitForInterrupt();\n });\n}\n\nasync function withHarness(\n options: HarnessOptions,\n body: (ctx: { port: number; plugins: PluginInfo[] }) => Promise<void>\n): Promise<void> {\n ensureWindows();\n ensurePhotoshopRunning();\n await ensureGeneratorCore({ update: options.updateCore ?? false });\n\n const port = options.port ?? DEFAULT_PORT;\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const pluginSource = await preparePluginSource(options);\n const expectedCount = scanPluginCandidates(pluginSource.pluginsDir).length;\n let child: ChildProcess | undefined;\n\n try {\n child = startGeneratorCore({\n port,\n pluginsDir: pluginSource.pluginsDir,\n hostPluginDir: resolveHostGeneratorDir(),\n });\n await waitForHealth(port, timeoutMs);\n const plugins = await readPlugins(port);\n assertPlugins({ plugins, expectedCount, expectPlugins: options.expectPlugins });\n const info = await smokeServerInfo(port, timeoutMs);\n console.log(\n `Server info: ${info.name} ${info.version}${info.psVersion ? `, Photoshop ${info.psVersion}` : \"\"}`\n );\n await body({ port, plugins });\n } finally {\n if (child) stopProcessTree(child);\n await cleanupPluginSource(pluginSource);\n }\n}\n\nfunction ensureWindows(): void {\n if (process.platform !== \"win32\") {\n throw new Error(\"ps-generator-bridge only supports Windows for run/dev in this version.\");\n }\n}\n\nfunction startGeneratorCore(options: {\n port: number;\n pluginsDir: string;\n hostPluginDir: string;\n}): ChildProcess {\n const app = join(generatorCoreDir(), \"app.js\");\n console.log(`Starting generator-core: ${app}`);\n const child = spawn(process.execPath, [app, \"-f\", options.hostPluginDir], {\n cwd: generatorCoreDir(),\n env: {\n ...process.env,\n PS_BRIDGE_PLUGINS_DIR: options.pluginsDir,\n PS_BRIDGE_PORT: String(options.port),\n },\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n child.stdout?.on(\"data\", (chunk) => process.stdout.write(chunk));\n child.stderr?.on(\"data\", (chunk) => process.stderr.write(chunk));\n child.on(\"exit\", (code, signal) => {\n if (code !== null && code !== 0) console.error(`generator-core exited with code ${code}`);\n if (signal) console.error(`generator-core exited with signal ${signal}`);\n });\n return child;\n}\n\nasync function waitForHealth(port: number, timeoutMs: number): Promise<void> {\n const deadline = Date.now() + timeoutMs;\n const url = `http://127.0.0.1:${port}/health`;\n while (Date.now() < deadline) {\n try {\n const response = await fetch(url);\n if (response.ok) return;\n } catch {\n // Keep polling until timeout.\n }\n await delay(500);\n }\n throw new Error(\n \"Photoshop is running, but PS Generator Bridge server did not become ready. Verify Generator and Remote Connections are enabled.\"\n );\n}\n\nasync function readPlugins(port: number): Promise<PluginInfo[]> {\n const response = await fetch(`http://127.0.0.1:${port}/plugins`);\n if (!response.ok) throw new Error(`GET /plugins failed with HTTP ${response.status}`);\n const body = (await response.json()) as { plugins?: PluginInfo[] };\n return Array.isArray(body.plugins) ? body.plugins : [];\n}\n\nasync function smokeServerInfo(port: number, timeoutMs: number) {\n const connection = new Connection({\n url: `ws://127.0.0.1:${port}/ws`,\n WebSocket: WebSocketImpl as unknown as typeof WebSocket,\n timeoutMs,\n maxRetries: 0,\n });\n try {\n return await connection.getServerInfo();\n } finally {\n connection.close();\n }\n}\n\nfunction assertPlugins(options: {\n plugins: PluginInfo[];\n expectedCount: number;\n expectPlugins: string[];\n}): void {\n const ids = new Set(options.plugins.map((plugin) => plugin.id));\n if (options.plugins.length !== options.expectedCount) {\n throw new Error(\n `Expected ${options.expectedCount} plugin(s), but host loaded ${options.plugins.length}: ${formatPlugins(options.plugins)}`\n );\n }\n for (const id of options.expectPlugins) {\n if (!ids.has(id)) throw new Error(`Expected plugin '${id}' was not loaded.`);\n }\n}\n\nfunction resolveHostGeneratorDir(): string {\n return dirname(require.resolve(\"@ps-generator-bridge/generator\"));\n}\n\nfunction stopProcessTree(child: ChildProcess): void {\n if (!child.pid || child.exitCode !== null) return;\n if (process.platform === \"win32\") {\n execFileSync(\"taskkill\", [\"/PID\", String(child.pid), \"/T\", \"/F\"], { stdio: \"ignore\" });\n return;\n }\n child.kill();\n}\n\nfunction formatPlugins(plugins: PluginInfo[]): string {\n return plugins.length > 0 ? plugins.map((plugin) => plugin.id).join(\", \") : \"(none)\";\n}\n\nfunction waitForInterrupt(): Promise<void> {\n return new Promise((resolve) => {\n process.once(\"SIGINT\", resolve);\n process.once(\"SIGTERM\", resolve);\n });\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import { execFileSync } from \"node:child_process\";\nimport { existsSync, mkdirSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, join, parse, resolve } from \"node:path\";\n\nconst REPO = \"https://github.com/adobe-photoshop/generator-core\";\n\nexport function generatorCoreDir(): string {\n const workspaceRoot = findWorkspaceRoot(process.cwd());\n if (workspaceRoot) return join(workspaceRoot, \"generator-core\");\n return join(tmpdir(), \"ps-generator-bridge\", \"generator-core\");\n}\n\nexport async function ensureGeneratorCore(options: { update: boolean }): Promise<void> {\n const dir = generatorCoreDir();\n mkdirSync(dirname(dir), { recursive: true });\n\n if (!existsSync(join(dir, \".git\"))) {\n run(\"git\", [\"clone\", REPO, dir], undefined);\n } else if (options.update) {\n run(\"git\", [\"pull\", \"--ff-only\"], dir);\n }\n\n run(\"npm\", [\"install\"], dir);\n}\n\nfunction run(command: string, args: string[], cwd: string | undefined): void {\n console.log(`[generator-core] ${command} ${args.join(\" \")}`);\n execFileSync(command, args, {\n cwd,\n stdio: \"inherit\",\n shell: process.platform === \"win32\",\n });\n}\n\nfunction findWorkspaceRoot(start: string): string | undefined {\n let current = resolve(start);\n const root = parse(current).root;\n while (true) {\n if (existsSync(join(current, \"pnpm-workspace.yaml\"))) return current;\n if (current === root) return undefined;\n current = dirname(current);\n }\n}\n","import { execFileSync } from \"node:child_process\";\n\nexport function ensurePhotoshopRunning(): void {\n const output = execFileSync(\"tasklist\", [\"/FI\", \"IMAGENAME eq Photoshop.exe\", \"/NH\"], {\n encoding: \"utf8\",\n });\n if (!output.toLowerCase().includes(\"photoshop.exe\")) {\n throw new Error(\n \"Photoshop is not running. Please open Photoshop first, then rerun this command.\"\n );\n }\n}\n","import {\n existsSync,\n lstatSync,\n mkdirSync,\n mkdtempSync,\n realpathSync,\n readdirSync,\n rmSync,\n symlinkSync,\n} from \"node:fs\";\nimport { basename, join, resolve } from \"node:path\";\nimport { tmpdir } from \"node:os\";\nimport type { HarnessOptions } from \"./core\";\n\nexport interface PluginSource {\n pluginsDir: string;\n cleanupDir?: string;\n}\n\nexport async function preparePluginSource(options: HarnessOptions): Promise<PluginSource> {\n if (options.pluginsDir) {\n const pluginsDir = requireDirectory(options.pluginsDir, \"--plugins-dir\");\n return { pluginsDir };\n }\n\n const pluginDir = requireDirectory(options.plugin, \"--plugin\");\n requirePackageEntry(pluginDir);\n const tempRoot = mkdtempSync(join(tmpdir(), \"ps-generator-bridge-\"));\n const pluginsDir = join(tempRoot, \"plugins\");\n const linkName = safeName(basename(pluginDir));\n const linkPath = join(pluginsDir, linkName);\n rmSync(pluginsDir, { recursive: true, force: true });\n mkdirSync(pluginsDir, { recursive: true });\n symlinkSync(pluginDir, linkPath, process.platform === \"win32\" ? \"junction\" : \"dir\");\n return { pluginsDir, cleanupDir: tempRoot };\n}\n\nexport async function cleanupPluginSource(source: PluginSource): Promise<void> {\n if (source.cleanupDir) rmSync(source.cleanupDir, { recursive: true, force: true });\n}\n\nexport function scanPluginCandidates(pluginsDir: string): string[] {\n return readdirSync(pluginsDir, { withFileTypes: true })\n .filter((entry) => {\n if (entry.name === \"node_modules\" || entry.name.startsWith(\".\")) return false;\n if (entry.isDirectory()) return true;\n if (!entry.isSymbolicLink()) return false;\n return lstatSync(join(pluginsDir, entry.name)).isSymbolicLink();\n })\n .map((entry) => entry.name)\n .filter((name) => existsSync(join(pluginsDir, name, \"package.json\")))\n .sort();\n}\n\nfunction requireDirectory(input: string | undefined, flag: string): string {\n if (!input) throw new Error(`${flag} is required`);\n const dir = realpathSync(resolve(input));\n if (!lstatSync(dir).isDirectory()) throw new Error(`${flag} must point to a directory: ${input}`);\n return dir;\n}\n\nfunction requirePackageEntry(dir: string): void {\n const packageJson = join(dir, \"package.json\");\n if (!existsSync(packageJson)) throw new Error(`Plugin directory has no package.json: ${dir}`);\n}\n\nfunction safeName(name: string): string {\n return name.replace(/[^A-Za-z0-9_.-]/g, \"_\") || \"plugin\";\n}\n","#!/usr/bin/env node\nimport { runDev, runHarness, setupGeneratorCore, type HarnessOptions } from \"./core\";\n\ntype Command = \"setup-core\" | \"run\" | \"dev\";\n\ninterface Parsed {\n command: Command;\n options: HarnessOptions & { update?: boolean };\n}\n\nconst USAGE = `Usage:\n ps-generator-bridge setup-core [--update]\n ps-generator-bridge run (--plugin <dir> | --plugins-dir <dir>) [--expect-plugin <id>] [--port <number>] [--timeout <ms>] [--update-core]\n ps-generator-bridge dev (--plugin <dir> | --plugins-dir <dir>) [--expect-plugin <id>] [--port <number>] [--timeout <ms>] [--update-core]`;\n\nasync function main(): Promise<void> {\n const parsed = parseArgs(process.argv.slice(2));\n if (parsed.command === \"setup-core\") {\n await setupGeneratorCore({ update: parsed.options.updateCore ?? parsed.options.update });\n return;\n }\n if (parsed.command === \"run\") {\n await runHarness(parsed.options);\n return;\n }\n await runDev(parsed.options);\n}\n\nfunction parseArgs(args: string[]): Parsed {\n if (args.length === 0 || args[0] === \"--help\" || args[0] === \"-h\") {\n console.log(USAGE);\n process.exit(0);\n }\n\n const command = args.shift();\n if (command !== \"setup-core\" && command !== \"run\" && command !== \"dev\") {\n throw usage(`Unknown command: ${command ?? \"(missing)\"}`);\n }\n\n const options: Parsed[\"options\"] = {\n expectPlugins: [],\n };\n\n for (let i = 0; i < args.length; i += 1) {\n const arg = args[i];\n switch (arg) {\n case \"--update\":\n options.update = true;\n break;\n case \"--update-core\":\n options.updateCore = true;\n break;\n case \"--plugin\":\n options.plugin = readValue(args, ++i, arg);\n break;\n case \"--plugins-dir\":\n options.pluginsDir = readValue(args, ++i, arg);\n break;\n case \"--expect-plugin\":\n options.expectPlugins.push(readValue(args, ++i, arg));\n break;\n case \"--port\":\n options.port = readNumber(readValue(args, ++i, arg), arg);\n break;\n case \"--timeout\":\n options.timeoutMs = readNumber(readValue(args, ++i, arg), arg);\n break;\n case \"--help\":\n case \"-h\":\n console.log(USAGE);\n process.exit(0);\n default:\n throw usage(`Unknown option: ${arg}`);\n }\n }\n\n if (command === \"setup-core\") return { command, options };\n if (options.plugin && options.pluginsDir) {\n throw usage(\"--plugin and --plugins-dir are mutually exclusive\");\n }\n if (!options.plugin && !options.pluginsDir) {\n throw usage(\"Either --plugin or --plugins-dir is required\");\n }\n return { command, options };\n}\n\nfunction readValue(args: string[], index: number, name: string): string {\n const value = args[index];\n if (!value || value.startsWith(\"--\")) throw usage(`${name} requires a value`);\n return value;\n}\n\nfunction readNumber(value: string, name: string): number {\n const parsed = Number(value);\n if (!Number.isInteger(parsed) || parsed <= 0) throw usage(`${name} must be a positive integer`);\n return parsed;\n}\n\nfunction usage(message: string): Error {\n return new Error(`${message}\\n\\n${USAGE}`);\n}\n\nmain().catch((error) => {\n console.error(error instanceof Error ? error.message : String(error));\n process.exitCode = 1;\n});\n"],"mappings":"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","names":["execFileSync","dirname","join","execFileSync","existsSync","mkdirSync","join","resolve","tmpdir","pluginsDir","require","join","dirname","execFileSync","resolve"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ps-generator-bridge/cli",
|
|
3
|
+
"version": "0.1.4",
|
|
4
|
+
"description": "Command-line tools for PS Generator Bridge",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "wojzj57",
|
|
7
|
+
"homepage": "https://wojzj57.github.io/ps-generator-bridge-service/",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/wojzj57/ps-generator-bridge-service.git",
|
|
11
|
+
"directory": "packages/cli"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/wojzj57/ps-generator-bridge-service/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"photoshop",
|
|
18
|
+
"generator",
|
|
19
|
+
"testing",
|
|
20
|
+
"cli"
|
|
21
|
+
],
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"type": "module",
|
|
26
|
+
"bin": {
|
|
27
|
+
"ps-generator-bridge": "./dist/cli.js"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist",
|
|
31
|
+
"README.md",
|
|
32
|
+
"README_zh.md"
|
|
33
|
+
],
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"ws": "^8.18.0",
|
|
36
|
+
"@ps-generator-bridge/generator": "0.3.0",
|
|
37
|
+
"@ps-generator-bridge/sdk": "0.3.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "^22.13.5",
|
|
41
|
+
"@types/ws": "^8.5.12",
|
|
42
|
+
"rimraf": "^6.0.1",
|
|
43
|
+
"tsup": "^8.3.5",
|
|
44
|
+
"typescript": "^5.9.3"
|
|
45
|
+
},
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=18"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "tsup",
|
|
51
|
+
"typecheck": "tsc --noEmit",
|
|
52
|
+
"test": "pnpm typecheck",
|
|
53
|
+
"clean": "rimraf dist *.tsbuildinfo"
|
|
54
|
+
}
|
|
55
|
+
}
|