smithue-cli 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +146 -0
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +190 -0
  5. package/dist/client.d.ts +37 -0
  6. package/dist/client.d.ts.map +1 -0
  7. package/dist/client.js +184 -0
  8. package/dist/commands/batch.d.ts +13 -0
  9. package/dist/commands/batch.d.ts.map +1 -0
  10. package/dist/commands/batch.js +64 -0
  11. package/dist/commands/exec.d.ts +6 -0
  12. package/dist/commands/exec.d.ts.map +1 -0
  13. package/dist/commands/exec.js +18 -0
  14. package/dist/commands/list.d.ts +8 -0
  15. package/dist/commands/list.d.ts.map +1 -0
  16. package/dist/commands/list.js +18 -0
  17. package/dist/commands/purge.d.ts +3 -0
  18. package/dist/commands/purge.d.ts.map +1 -0
  19. package/dist/commands/purge.js +154 -0
  20. package/dist/commands/search.d.ts +8 -0
  21. package/dist/commands/search.d.ts.map +1 -0
  22. package/dist/commands/search.js +31 -0
  23. package/dist/commands/status.d.ts +9 -0
  24. package/dist/commands/status.d.ts.map +1 -0
  25. package/dist/commands/status.js +51 -0
  26. package/dist/commands/upgrade.d.ts +2 -0
  27. package/dist/commands/upgrade.d.ts.map +1 -0
  28. package/dist/commands/upgrade.js +20 -0
  29. package/dist/index.d.ts +3 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +139 -0
  32. package/dist/output.d.ts +8 -0
  33. package/dist/output.d.ts.map +1 -0
  34. package/dist/output.js +46 -0
  35. package/dist/portfile.d.ts +31 -0
  36. package/dist/portfile.d.ts.map +1 -0
  37. package/dist/portfile.js +133 -0
  38. package/dist/types.d.ts +50 -0
  39. package/dist/types.d.ts.map +1 -0
  40. package/dist/types.js +3 -0
  41. package/dist/version-check.d.ts +2 -0
  42. package/dist/version-check.d.ts.map +1 -0
  43. package/dist/version-check.js +9 -0
  44. package/package.json +40 -0
@@ -0,0 +1,133 @@
1
+ import { readdir, readFile, unlink } from 'fs/promises';
2
+ import { join } from 'path';
3
+ // ---------------------------------------------------------------------------
4
+ // Error class
5
+ // ---------------------------------------------------------------------------
6
+ export class SmithUEError extends Error {
7
+ exitCode;
8
+ constructor(message, exitCode) {
9
+ super(message);
10
+ this.exitCode = exitCode;
11
+ this.name = 'SmithUEError';
12
+ }
13
+ }
14
+ // ---------------------------------------------------------------------------
15
+ // Helpers
16
+ // ---------------------------------------------------------------------------
17
+ export function getPortfileDir() {
18
+ const localAppData = process.env['LOCALAPPDATA'];
19
+ if (!localAppData) {
20
+ throw new SmithUEError('LOCALAPPDATA environment variable is not set. This command requires Windows.', 2);
21
+ }
22
+ return join(localAppData, '.smithue');
23
+ }
24
+ export async function readPortfiles(dir) {
25
+ let entries;
26
+ try {
27
+ entries = await readdir(dir);
28
+ }
29
+ catch {
30
+ return [];
31
+ }
32
+ const portfiles = [];
33
+ for (const entry of entries) {
34
+ if (!entry.endsWith('.port'))
35
+ continue;
36
+ const filePath = join(dir, entry);
37
+ try {
38
+ const raw = await readFile(filePath, 'utf-8');
39
+ const data = JSON.parse(raw);
40
+ portfiles.push({ file: filePath, data });
41
+ }
42
+ catch {
43
+ // Ignore malformed portfiles
44
+ }
45
+ }
46
+ return portfiles;
47
+ }
48
+ async function checkLiveness(port, filePath) {
49
+ try {
50
+ await fetch(`http://127.0.0.1:${port}/ready`, {
51
+ signal: AbortSignal.timeout(3000),
52
+ });
53
+ // any HTTP response = server is alive (including 503 during startup)
54
+ return;
55
+ }
56
+ catch {
57
+ // network failure = truly stale
58
+ try {
59
+ await unlink(filePath);
60
+ }
61
+ catch {
62
+ // best effort
63
+ }
64
+ throw new SmithUEError(`SmithUE instance on port ${port} is not responding. Stale portfile removed.`, 2);
65
+ }
66
+ }
67
+ // ---------------------------------------------------------------------------
68
+ // Main export
69
+ // ---------------------------------------------------------------------------
70
+ export async function discoverPort(opts = {}) {
71
+ // 1. SMITHUE_PORT env override — skip discovery entirely
72
+ const envPort = process.env['SMITHUE_PORT'];
73
+ if (envPort) {
74
+ const port = parseInt(envPort, 10);
75
+ if (isNaN(port) || port <= 0) {
76
+ throw new SmithUEError(`SMITHUE_PORT is not a valid port number: "${envPort}"`, 1);
77
+ }
78
+ return { port, pid: 0, project: '', project_name: '' };
79
+ }
80
+ // 2. --port flag shortcut (already resolved by caller, treated same as env override)
81
+ if (opts.port !== undefined) {
82
+ return { port: opts.port, pid: 0, project: '', project_name: '' };
83
+ }
84
+ // 3. Determine effective PID filter (--pid > SMITHUE_PID env)
85
+ let pidFilter = opts.pid;
86
+ if (pidFilter === undefined) {
87
+ const envPid = process.env['SMITHUE_PID'];
88
+ if (envPid) {
89
+ const p = parseInt(envPid, 10);
90
+ if (!isNaN(p) && p > 0) {
91
+ pidFilter = p;
92
+ }
93
+ }
94
+ }
95
+ // 4. Read all portfiles
96
+ const dir = getPortfileDir();
97
+ const all = await readPortfiles(dir);
98
+ if (all.length === 0) {
99
+ throw new SmithUEError('No SmithUE portfiles found. Is the SmithUE plugin running in Unreal Editor?', 2);
100
+ }
101
+ // 5. Apply filters
102
+ let candidates = all;
103
+ if (pidFilter !== undefined) {
104
+ candidates = candidates.filter((c) => c.data.pid === pidFilter);
105
+ if (candidates.length === 0) {
106
+ throw new SmithUEError(`No SmithUE instance found with PID ${pidFilter}.`, 2);
107
+ }
108
+ }
109
+ else if (opts.project !== undefined) {
110
+ // Exact absolute path comparison (M7)
111
+ candidates = candidates.filter((c) => c.data.project === opts.project);
112
+ if (candidates.length === 0) {
113
+ throw new SmithUEError(`No SmithUE instance found for project "${opts.project}".`, 2);
114
+ }
115
+ }
116
+ // 6. Multi-instance error (no disambiguation possible)
117
+ if (candidates.length > 1) {
118
+ const list = candidates
119
+ .map((c) => ` PID ${c.data.pid} ${c.data.project_name} (port ${c.data.port})`)
120
+ .join('\n');
121
+ throw new SmithUEError(`Multiple SmithUE instances are running. Use --pid or --project to select one:\n${list}`, 1);
122
+ }
123
+ // 7. Single candidate — liveness check
124
+ const { file, data } = candidates[0];
125
+ await checkLiveness(data.port, file);
126
+ return {
127
+ port: data.port,
128
+ pid: data.pid,
129
+ project: data.project,
130
+ project_name: data.project_name,
131
+ plugin_version: data.plugin_version,
132
+ };
133
+ }
@@ -0,0 +1,50 @@
1
+ export interface SmithUEToolParam {
2
+ name: string;
3
+ type: string;
4
+ description: string;
5
+ required: boolean;
6
+ default?: string;
7
+ itemsType?: string;
8
+ allowedValues?: string[];
9
+ }
10
+ export interface SmithUEToolSchema {
11
+ name: string;
12
+ category: string;
13
+ description: string;
14
+ params: SmithUEToolParam[];
15
+ }
16
+ export interface SmithUEListToolsResponse {
17
+ status: 'success' | 'error';
18
+ data: {
19
+ protocol_version: string;
20
+ tools: SmithUEToolSchema[];
21
+ };
22
+ }
23
+ export interface SmithUEExecuteResponse {
24
+ status: 'success' | 'error';
25
+ data?: Record<string, unknown>;
26
+ error?: string;
27
+ error_code?: string;
28
+ }
29
+ export interface SmithUEClientConfig {
30
+ host: string;
31
+ port: number;
32
+ timeout: number;
33
+ }
34
+ export interface PurgeOptions {
35
+ force: boolean;
36
+ dryRun: boolean;
37
+ yes: boolean;
38
+ }
39
+ export interface PurgeResult {
40
+ status: 'purged' | 'nothing_to_purge' | 'partial' | 'cancelled' | 'dry_run';
41
+ path: string;
42
+ scanned: number;
43
+ deleted: number;
44
+ skipped_live: number;
45
+ failed: number;
46
+ directory_removed: boolean;
47
+ errors: string[];
48
+ warnings: string[];
49
+ }
50
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,gBAAgB,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;IAC5B,IAAI,EAAE;QACJ,gBAAgB,EAAE,MAAM,CAAC;QACzB,KAAK,EAAE,iBAAiB,EAAE,CAAC;KAC5B,CAAC;CACH;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,EAAE,OAAO,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,QAAQ,GAAG,kBAAkB,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;IAC5E,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,OAAO,CAAC;IAC3B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ // SmithUE plugin HTTP API types
2
+ // Mirrors FUEAgentToolParam and FUEAgentToolSchema from plugin C++ code
3
+ export {};
@@ -0,0 +1,2 @@
1
+ export declare function checkVersionCompat(cliVersion: string, pluginVersion: string | undefined): void;
2
+ //# sourceMappingURL=version-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version-check.d.ts","sourceRoot":"","sources":["../src/version-check.ts"],"names":[],"mappings":"AAAA,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAW9F"}
@@ -0,0 +1,9 @@
1
+ export function checkVersionCompat(cliVersion, pluginVersion) {
2
+ if (!pluginVersion)
3
+ return;
4
+ const [cliMajor, cliMinor] = cliVersion.split('.');
5
+ const [pluginMajor, pluginMinor] = pluginVersion.split('.');
6
+ if (cliMajor !== pluginMajor || cliMinor !== pluginMinor) {
7
+ process.stderr.write(`Warning: smithue-cli version ${cliVersion} does not match plugin version ${pluginVersion}. Run "smithue-cli upgrade" to update.\n`);
8
+ }
9
+ }
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "smithue-cli",
3
+ "version": "0.8.0",
4
+ "type": "module",
5
+ "main": "dist/cli.js",
6
+ "scripts": {
7
+ "build": "tsc -p tsconfig.build.json",
8
+ "test": "vitest run",
9
+ "typecheck": "tsc --noEmit",
10
+ "dev": "tsc -p tsconfig.build.json --watch"
11
+ },
12
+ "files": [
13
+ "dist/",
14
+ "package.json",
15
+ "README.md"
16
+ ],
17
+ "devDependencies": {
18
+ "@types/node": "^20.0.0",
19
+ "typescript": "^5.3.0",
20
+ "vitest": "^1.0.0"
21
+ },
22
+ "dependencies": {
23
+ "commander": "^15.0.0"
24
+ },
25
+ "bin": {
26
+ "smithue-cli": "./dist/cli.js"
27
+ },
28
+ "engines": {
29
+ "node": "\u003e=18"
30
+ },
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "license": "MIT",
35
+ "description": "CLI tool for controlling Unreal Engine editor via SmithUE plugin",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/123dx-svg/smithue-cli.git"
39
+ }
40
+ }