smithue-cli 0.9.1 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -48,6 +48,8 @@ npx smithue-cli <command>
48
48
  | `upgrade` | Update the CLI to the latest version via npm |
49
49
  | `prune` | Remove stale port files from crashed instances |
50
50
  | `purge` | Remove the entire `.smithue` directory (full uninstall cleanup) |
51
+ | `use` | Pin (or unpin) a default SmithUE instance for multi-editor setups |
52
+ | `skill` | Print or install the bundled SKILL.md for AI agent integration |
51
53
 
52
54
  ## Output Modes
53
55
 
@@ -141,6 +143,25 @@ smithue-cli purge -y # non-interactive full purge (CI/scripts)
141
143
 
142
144
  For routine cleanup of stale portfiles without removing the directory, use `smithue-cli prune` instead.
143
145
 
146
+ ## Exit Codes
147
+
148
+ | Code | Meaning | Common cause |
149
+ |---|---|---|
150
+ | `0` | Success | Command completed normally |
151
+ | `1` | Bad input or disambiguation required | Invalid arguments; multiple instances running without `--pid`/`--project`; `PAYLOAD_TOO_LARGE` |
152
+ | `2` | Not found or unreachable | No portfiles found; instance unreachable; PID/project not matched |
153
+ | `3` | Command error | `PIE_LOCKED`, `ASSET_NOT_FOUND`, `INVALID_REQUEST`, or unknown plugin error |
154
+ | `4` | Internal / editor not ready | `INTERNAL_ERROR`, `EDITOR_NOT_READY`, unexpected exception |
155
+ | `5` | Stale session NID | `STALE_NID` — node ID is outdated, re-run the command |
156
+ | `6` | Wait timeout | `--wait` exceeded without editor becoming ready |
157
+
158
+ Scripts can branch on exit codes:
159
+ ```powershell
160
+ smithue-cli status
161
+ if ($LASTEXITCODE -eq 2) { Write-Host "Editor not running" }
162
+ if ($LASTEXITCODE -eq 5) { Write-Host "Reconnecting (stale NID)..." }
163
+ ```
164
+
144
165
  ## Known Limitations
145
166
  - Version 1 is Windows-only due to portfile path conventions.
146
167
  - No persistent configuration files. Use environment variables like `SMITHUE_PORT` or `SMITHUE_PID` for overrides.
package/dist/cli.js CHANGED
@@ -7,9 +7,11 @@ import { execCommand } from './commands/exec.js';
7
7
  import { listCommand } from './commands/list.js';
8
8
  import { searchCommand } from './commands/search.js';
9
9
  import { statusCommand } from './commands/status.js';
10
+ import { useCommand } from './commands/use.js';
10
11
  import { purge } from './commands/purge.js';
11
12
  import { upgradeCommand } from './commands/upgrade.js';
12
13
  import { batchCommand } from './commands/batch.js';
14
+ import { skillCommand } from './commands/skill.js';
13
15
  import { printResult, printError, setOutputOptions } from './output.js';
14
16
  const program = new Command();
15
17
  const require = createRequire(import.meta.url);
@@ -22,10 +24,15 @@ program
22
24
  .option('--project <path>', 'target SmithUE instance by project path')
23
25
  .option('--port <port>', 'connect directly to port (skip discovery)', parseInt)
24
26
  .option('--terse', 'emit minified JSON output')
25
- .option('--out <file>', 'write result to file instead of stdout');
27
+ .option('--out <file>', 'write result to file instead of stdout')
28
+ .option('--strict', 'require explicit instance selection; error on multiple instances (CI mode)');
26
29
  program.hook('preAction', () => {
27
30
  const opts = program.opts();
28
31
  setOutputOptions({ terse: opts.terse, outPath: opts.out });
32
+ // SMITHUE_STRICT=1 env var acts as global --strict
33
+ if (!opts.strict && process.env['SMITHUE_STRICT'] === '1') {
34
+ program.setOptionValue('strict', true);
35
+ }
29
36
  });
30
37
  // ---------------------------------------------------------------------------
31
38
  // exec
@@ -79,6 +86,18 @@ program
79
86
  await statusCommand({ ...globals, wait: cmdOpts.wait, cliVersion });
80
87
  });
81
88
  // ---------------------------------------------------------------------------
89
+ // use
90
+ // ---------------------------------------------------------------------------
91
+ program
92
+ .command('use')
93
+ .description('Pin a default SmithUE instance. Use --clear to unpin.')
94
+ .option('--pid <pid>', 'pin instance by PID', parseInt)
95
+ .option('--project <path>', 'pin instance by project path or name')
96
+ .option('--clear', 'remove the pinned instance')
97
+ .action(async (cmdOpts) => {
98
+ await useCommand(cmdOpts);
99
+ });
100
+ // ---------------------------------------------------------------------------
82
101
  // prune
83
102
  // ---------------------------------------------------------------------------
84
103
  program
@@ -175,6 +194,17 @@ program
175
194
  await upgradeCommand();
176
195
  });
177
196
  // ---------------------------------------------------------------------------
197
+ // skill
198
+ // ---------------------------------------------------------------------------
199
+ program
200
+ .command('skill')
201
+ .description('Print or install the bundled SKILL.md for AI agent integration')
202
+ .option('--print', 'print SKILL.md to stdout')
203
+ .option('--install <dir>', 'install SKILL.md into the specified directory')
204
+ .action(async (cmdOpts) => {
205
+ await skillCommand(cmdOpts);
206
+ });
207
+ // ---------------------------------------------------------------------------
178
208
  // batch
179
209
  // ---------------------------------------------------------------------------
180
210
  program
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE5E,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,OAAO,CAAS;gBAEZ,MAAM,EAAE,mBAAmB;IAMvC,OAAO,KAAK,OAAO,GAElB;IAED,OAAO,CAAC,OAAO;YAID,SAAS;YAwBT,QAAQ;YAQR,OAAO;IAOrB,OAAO,CAAC,qBAAqB;IAwBvB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAa/F,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAItG,IAAI,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAKpC,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAUxD,QAAQ,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAI/E,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAS/B,mBAAmB,CACvB,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACnC,OAAO,CAAC,sBAAsB,CAAC;IA6ClC,OAAO,CAAC,0BAA0B;YAmBpB,cAAc;IAe5B,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,QAAQ;YAIF,KAAK;CAGpB"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE5E,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,OAAO,CAAS;gBAEZ,MAAM,EAAE,mBAAmB;IAMvC,OAAO,KAAK,OAAO,GAElB;IAED,OAAO,CAAC,OAAO;YAID,SAAS;YAwBT,QAAQ;YAQR,OAAO;IAOrB,OAAO,CAAC,qBAAqB;IAyBvB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAa/F,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAItG,IAAI,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAKpC,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAUxD,QAAQ,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAI/E,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAS/B,mBAAmB,CACvB,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACnC,OAAO,CAAC,sBAAsB,CAAC;IA6ClC,OAAO,CAAC,0BAA0B;YAmBpB,cAAc;IAe5B,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,QAAQ;YAIF,KAAK;CAGpB"}
package/dist/client.js CHANGED
@@ -58,7 +58,8 @@ export class SmithUEClient {
58
58
  msg.includes('Failed to fetch') ||
59
59
  msg.includes('ENOTFOUND') ||
60
60
  msg.includes('connect ECONNREFUSED')) {
61
- return new Error(`SmithUE plugin unreachable at ${this.host}:${this.port}. Start UE Editor with SmithUE plugin enabled.`);
61
+ return new Error(`SmithUE plugin unreachable at ${this.host}:${this.port}. Start UE Editor with SmithUE plugin enabled.\n` +
62
+ ` Fallback: curl -s http://${this.host}:${this.port}/api/v1/execute -d '{"command":"ping","params":{}}'`);
62
63
  }
63
64
  return err instanceof Error ? err : new Error(String(err));
64
65
  }
@@ -0,0 +1,6 @@
1
+ export interface SkillOpts {
2
+ print?: boolean;
3
+ install?: string;
4
+ }
5
+ export declare function skillCommand(opts: SkillOpts): Promise<void>;
6
+ //# sourceMappingURL=skill.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill.d.ts","sourceRoot":"","sources":["../../src/commands/skill.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAmCjE"}
@@ -0,0 +1,38 @@
1
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
2
+ import { dirname, join, resolve } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { printError, printResult } from '../output.js';
5
+ import { SmithUEError } from '../portfile.js';
6
+ function getSkillPath() {
7
+ const here = dirname(fileURLToPath(import.meta.url));
8
+ return resolve(here, '..', '..', 'skill', 'SKILL.md');
9
+ }
10
+ export async function skillCommand(opts) {
11
+ try {
12
+ if (!opts.print && !opts.install) {
13
+ throw new SmithUEError('Specify --print to output SKILL.md, or --install <dir> to install it.', 1);
14
+ }
15
+ const skillPath = getSkillPath();
16
+ let content;
17
+ try {
18
+ content = await readFile(skillPath, 'utf-8');
19
+ }
20
+ catch {
21
+ throw new SmithUEError(`SKILL.md not found at ${skillPath}. Reinstall smithue-cli to fix.`, 4);
22
+ }
23
+ if (opts.print) {
24
+ process.stdout.write(content);
25
+ return;
26
+ }
27
+ if (opts.install) {
28
+ const dir = resolve(opts.install);
29
+ await mkdir(dir, { recursive: true });
30
+ const destPath = join(dir, 'SKILL.md');
31
+ await writeFile(destPath, content, 'utf-8');
32
+ printResult({ ok: true, installed: destPath });
33
+ }
34
+ }
35
+ catch (err) {
36
+ printError(err);
37
+ }
38
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAMD,wBAAsB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA4CnE"}
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAMD,wBAAsB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAgDnE"}
@@ -24,6 +24,8 @@ export async function statusCommand(opts) {
24
24
  ready: res.ready,
25
25
  version: res.version,
26
26
  pie_active: res.pie_active,
27
+ ...(discovered.selection_mode ? { selection_mode: discovered.selection_mode } : {}),
28
+ ...(discovered.busy ? { busy: true } : {}),
27
29
  });
28
30
  return;
29
31
  }
@@ -42,6 +44,8 @@ export async function statusCommand(opts) {
42
44
  ready: res.ready,
43
45
  version: res.version,
44
46
  pie_active: res.pie_active,
47
+ ...(discovered.selection_mode ? { selection_mode: discovered.selection_mode } : {}),
48
+ ...(discovered.busy ? { busy: true } : {}),
45
49
  });
46
50
  }
47
51
  }
@@ -0,0 +1,7 @@
1
+ export interface UseOpts {
2
+ pid?: number;
3
+ project?: string;
4
+ clear?: boolean;
5
+ }
6
+ export declare function useCommand(opts: UseOpts): Promise<void>;
7
+ //# sourceMappingURL=use.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use.d.ts","sourceRoot":"","sources":["../../src/commands/use.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,OAAO;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAkD7D"}
@@ -0,0 +1,45 @@
1
+ import { readPortfiles, getPortfileDir, SmithUEError } from '../portfile.js';
2
+ import { setPinned, clearPinned, getPinned } from '../registry.js';
3
+ import { projectId } from '../identity.js';
4
+ import { printResult, printError } from '../output.js';
5
+ export async function useCommand(opts) {
6
+ try {
7
+ if (opts.clear) {
8
+ await getPinned();
9
+ await clearPinned();
10
+ printResult({ ok: true, action: 'cleared', pinned: null });
11
+ return;
12
+ }
13
+ if (opts.pid === undefined && opts.project === undefined) {
14
+ throw new SmithUEError('Specify --pid <n> or --project <path> to pin an instance, or --clear to unpin.', 1);
15
+ }
16
+ const dir = getPortfileDir();
17
+ const all = await readPortfiles(dir);
18
+ const candidate = all.find((c) => {
19
+ if (opts.pid !== undefined)
20
+ return c.data.pid === opts.pid;
21
+ if (opts.project !== undefined) {
22
+ return c.data.project === opts.project || c.data.project_name === opts.project;
23
+ }
24
+ return false;
25
+ });
26
+ if (!candidate) {
27
+ throw new SmithUEError(opts.pid !== undefined
28
+ ? `No running SmithUE instance found with PID ${opts.pid}.`
29
+ : `No running SmithUE instance found for project "${opts.project}".`, 2);
30
+ }
31
+ const entry = {
32
+ projectId: projectId(candidate.data.project || ''),
33
+ pid: candidate.data.pid,
34
+ port: candidate.data.port,
35
+ project: candidate.data.project,
36
+ project_name: candidate.data.project_name,
37
+ lastConnectedAt: new Date().toISOString(),
38
+ };
39
+ await setPinned(entry);
40
+ printResult({ ok: true, action: 'pinned', pinned: entry });
41
+ }
42
+ catch (err) {
43
+ printError(err);
44
+ }
45
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Derive a stable, short identifier for an absolute project path.
3
+ * Inspired by Obsidian's path-hash vault identity — survives pid/port changes.
4
+ *
5
+ * Algorithm: normalize path (resolve + lowercase on Windows) → SHA-256 → first 16 hex chars.
6
+ */
7
+ export declare function projectId(absPath: string): string;
8
+ //# sourceMappingURL=identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGjD"}
@@ -0,0 +1,17 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { resolve } from 'node:path';
3
+ /**
4
+ * Derive a stable, short identifier for an absolute project path.
5
+ * Inspired by Obsidian's path-hash vault identity — survives pid/port changes.
6
+ *
7
+ * Algorithm: normalize path (resolve + lowercase on Windows) → SHA-256 → first 16 hex chars.
8
+ */
9
+ export function projectId(absPath) {
10
+ const normalized = normalizePath(absPath);
11
+ return createHash('sha256').update(normalized, 'utf8').digest('hex').slice(0, 16);
12
+ }
13
+ function normalizePath(p) {
14
+ const resolved = resolve(p);
15
+ // Windows paths are case-insensitive; normalize to lowercase for stable hashing
16
+ return process.platform === 'win32' ? resolved.toLowerCase() : resolved;
17
+ }
package/dist/output.d.ts CHANGED
@@ -2,6 +2,7 @@ export interface OutputOptions {
2
2
  terse?: boolean;
3
3
  outPath?: string;
4
4
  }
5
+ export declare function escapeNonAscii(s: string): string;
5
6
  export declare function setOutputOptions(opts: OutputOptions): void;
6
7
  export declare function printResult(data: unknown): void;
7
8
  export declare function printError(err: unknown): void;
@@ -1 +1 @@
1
- {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAID,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAE1D;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CA0B/C;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAiB7C"}
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAID,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAWhD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAE1D;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CA2B/C;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAkC7C"}
package/dist/output.js CHANGED
@@ -1,6 +1,19 @@
1
1
  import fs from 'node:fs';
2
2
  import { SmithUEError } from './portfile.js';
3
3
  let _opts = {};
4
+ export function escapeNonAscii(s) {
5
+ let out = '';
6
+ for (let i = 0; i < s.length; i++) {
7
+ const code = s.charCodeAt(i);
8
+ if (code < 0x80) {
9
+ out += s[i];
10
+ }
11
+ else {
12
+ out += `\\u${code.toString(16).padStart(4, '0')}`;
13
+ }
14
+ }
15
+ return out;
16
+ }
4
17
  export function setOutputOptions(opts) {
5
18
  _opts = { ..._opts, ...opts };
6
19
  }
@@ -17,14 +30,15 @@ export function printResult(data) {
17
30
  // path doesn't exist — fine, writeFileSync will create it
18
31
  }
19
32
  if (isDir) {
20
- process.stderr.write(JSON.stringify({ error: `outPath is a directory: ${_opts.outPath}`, exit_code: 1 }) + '\n');
33
+ process.stderr.write(escapeNonAscii(JSON.stringify({ error: `outPath is a directory: ${_opts.outPath}`, exit_code: 1 })) +
34
+ '\n');
21
35
  process.exit(1);
22
36
  return;
23
37
  }
24
38
  fs.writeFileSync(_opts.outPath, json, 'utf8');
25
39
  return;
26
40
  }
27
- process.stdout.write(json);
41
+ process.stdout.write(escapeNonAscii(json));
28
42
  }
29
43
  export function printError(err) {
30
44
  let message;
@@ -41,6 +55,21 @@ export function printError(err) {
41
55
  message = String(err);
42
56
  exitCode = 4;
43
57
  }
44
- process.stderr.write(JSON.stringify({ error: message, exit_code: exitCode }) + '\n');
58
+ // Extract curl fallback from message if present (written as " Fallback: curl ...")
59
+ const fallbackMatch = message.match(/\n\s+Fallback:\s+(curl\s+.+)/);
60
+ const fallback_cmd = fallbackMatch ? fallbackMatch[1].trim() : undefined;
61
+ const cleanMessage = message.split('\n')[0]; // first line for code-parseable summary
62
+ // Machine-readable error envelope (P3.3)
63
+ const envelope = {
64
+ ok: false,
65
+ error: {
66
+ message: cleanMessage,
67
+ full_message: message,
68
+ code: exitCode,
69
+ exit: exitCode,
70
+ ...(fallback_cmd ? { hint: 'Use fallback_cmd to verify connectivity.', fallback_cmd } : {}),
71
+ },
72
+ };
73
+ process.stderr.write(escapeNonAscii(JSON.stringify(envelope)) + '\n');
45
74
  process.exit(exitCode);
46
75
  }
@@ -16,11 +16,15 @@ export interface DiscoverResult {
16
16
  project: string;
17
17
  project_name: string;
18
18
  plugin_version?: string;
19
+ selection_mode?: 'pinned' | 'most-recent' | 'explicit';
20
+ busy?: boolean;
19
21
  }
20
22
  export interface DiscoverOpts {
21
23
  pid?: number;
22
24
  project?: string;
23
25
  port?: number;
26
+ /** When true, revert to hard-error on multi-instance (CI/script mode). Default: false. */
27
+ strict?: boolean;
24
28
  }
25
29
  export declare function getPortfileDir(): string;
26
30
  export declare function readPortfiles(dir: string): Promise<Array<{
@@ -1 +1 @@
1
- {"version":3,"file":"portfile.d.ts","sourceRoot":"","sources":["../src/portfile.ts"],"names":[],"mappings":"AASA,qBAAa,YAAa,SAAQ,KAAK;aAGnB,QAAQ,EAAE,MAAM;gBADhC,OAAO,EAAE,MAAM,EACC,QAAQ,EAAE,MAAM;CAKnC;AAMD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD,wBAAgB,cAAc,IAAI,MAAM,CASvC;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC,CAAC,CAuBrG;AA8CD,wBAAsB,YAAY,CAAC,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,cAAc,CAAC,CAmFnF"}
1
+ {"version":3,"file":"portfile.d.ts","sourceRoot":"","sources":["../src/portfile.ts"],"names":[],"mappings":"AAWA,qBAAa,YAAa,SAAQ,KAAK;aAGnB,QAAQ,EAAE,MAAM;gBADhC,OAAO,EAAE,MAAM,EACC,QAAQ,EAAE,MAAM;CAKnC;AAMD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,QAAQ,GAAG,aAAa,GAAG,UAAU,CAAC;IACvD,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0FAA0F;IAC1F,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAMD,wBAAgB,cAAc,IAAI,MAAM,CASvC;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC,CAAC,CAuBrG;AA+CD,wBAAsB,YAAY,CAAC,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,cAAc,CAAC,CAyKnF"}
package/dist/portfile.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { readdir, readFile, unlink } from 'fs/promises';
2
2
  import { join } from 'path';
3
3
  import { isProcessAlive } from './proc.js';
4
+ import * as registry from './registry.js';
5
+ import { projectId } from './identity.js';
4
6
  // ---------------------------------------------------------------------------
5
7
  // Error class
6
8
  // ---------------------------------------------------------------------------
@@ -53,18 +55,19 @@ async function checkLiveness(port, filePath, pid) {
53
55
  signal: AbortSignal.timeout(timeoutMs),
54
56
  });
55
57
  // any HTTP response = server is alive (including 503 during startup)
56
- return;
58
+ return { busy: false };
57
59
  }
58
60
  catch (err) {
59
61
  const error = err;
60
62
  // Timeout means the editor may be busy running a long command.
61
63
  // Keep the portfile and treat the instance as alive/busy.
62
64
  if (error.name === 'AbortError') {
63
- return;
65
+ return { busy: true };
64
66
  }
65
67
  const processAlive = pid > 0 && isProcessAlive(pid);
66
68
  if (processAlive) {
67
- throw new SmithUEError(`SmithUE instance on port ${port} is unreachable, but process ${pid} is still running. Try again or restart the editor.`, 2);
69
+ throw new SmithUEError(`SmithUE instance on port ${port} is unreachable, but process ${pid} is still running. Try again or restart the editor.\n` +
70
+ ` Fallback: curl -s http://127.0.0.1:${port}/api/v1/execute -d '{"command":"ping","params":{}}'`, 2);
68
71
  }
69
72
  // Connection-level failure is stale only when the owning process is dead.
70
73
  try {
@@ -87,12 +90,13 @@ export async function discoverPort(opts = {}) {
87
90
  if (isNaN(port) || port <= 0) {
88
91
  throw new SmithUEError(`SMITHUE_PORT is not a valid port number: "${envPort}"`, 1);
89
92
  }
90
- return { port, pid: 0, project: '', project_name: '' };
93
+ return { port, pid: 0, project: '', project_name: '', selection_mode: 'explicit', busy: false };
91
94
  }
92
95
  // 2. --port flag shortcut (already resolved by caller, treated same as env override)
93
96
  if (opts.port !== undefined) {
94
- return { port: opts.port, pid: 0, project: '', project_name: '' };
97
+ return { port: opts.port, pid: 0, project: '', project_name: '', selection_mode: 'explicit', busy: false };
95
98
  }
99
+ let selectionMode = 'explicit';
96
100
  // 3. Determine effective PID filter (--pid > SMITHUE_PID env)
97
101
  let pidFilter = opts.pid;
98
102
  if (pidFilter === undefined) {
@@ -108,7 +112,10 @@ export async function discoverPort(opts = {}) {
108
112
  const dir = getPortfileDir();
109
113
  const all = await readPortfiles(dir);
110
114
  if (all.length === 0) {
111
- throw new SmithUEError('No SmithUE portfiles found. Is the SmithUE plugin running in Unreal Editor?', 2);
115
+ throw new SmithUEError(`No SmithUE portfiles found. Is the SmithUE plugin running in Unreal Editor?\n` +
116
+ ` Check: status bar SmithUE green dot in UE Editor.\n` +
117
+ ` Port dir: ${dir}\n` +
118
+ ` Direct connect: set SMITHUE_PORT=<port> or use --port <port>.`, 2);
112
119
  }
113
120
  // 5. Apply filters
114
121
  let candidates = all;
@@ -119,27 +126,86 @@ export async function discoverPort(opts = {}) {
119
126
  }
120
127
  }
121
128
  else if (opts.project !== undefined) {
122
- // Exact absolute path comparison (M7)
123
- candidates = candidates.filter((c) => c.data.project === opts.project);
124
- if (candidates.length === 0) {
125
- throw new SmithUEError(`No SmithUE instance found for project "${opts.project}".`, 2);
129
+ const query = opts.project;
130
+ // 1. Try exact absolute path comparison (backward-compatible, M7)
131
+ let matched = candidates.filter((c) => c.data.project === query);
132
+ // 2. Fuzzy fallback: match by project_name or basename of project path
133
+ if (matched.length === 0) {
134
+ const q = query.toLowerCase();
135
+ matched = candidates.filter((c) => {
136
+ const name = c.data.project_name?.toLowerCase() ?? '';
137
+ const base = c.data.project.split(/[\\/]/).pop()?.toLowerCase() ?? '';
138
+ return name === q || base === q || name.includes(q);
139
+ });
140
+ }
141
+ if (matched.length === 0) {
142
+ throw new SmithUEError(`No SmithUE instance found for project "${query}". Use --pid to select by process ID.`, 2);
126
143
  }
144
+ // Multiple fuzzy matches → give list so user can disambiguate with --pid
145
+ if (matched.length > 1) {
146
+ const list = matched
147
+ .map((c) => ` PID ${c.data.pid} ${c.data.project_name} (port ${c.data.port})`)
148
+ .join('\n');
149
+ throw new SmithUEError(`Multiple SmithUE instances match "${query}". Use --pid to select one:\n${list}`, 1);
150
+ }
151
+ candidates = matched;
127
152
  }
128
- // 6. Multi-instance error (no disambiguation possible)
153
+ // 6. Multi-instance: select most-recent or hard-error in strict mode
129
154
  if (candidates.length > 1) {
130
- const list = candidates
131
- .map((c) => ` PID ${c.data.pid} ${c.data.project_name} (port ${c.data.port})`)
132
- .join('\n');
133
- throw new SmithUEError(`Multiple SmithUE instances are running. Use --pid or --project to select one:\n${list}`, 1);
155
+ if (opts.strict) {
156
+ const list = candidates
157
+ .map((c) => ` PID ${c.data.pid} ${c.data.project_name} (port ${c.data.port})`)
158
+ .join('\n');
159
+ throw new SmithUEError(`Multiple SmithUE instances are running. Use --pid or --project to select one:\n${list}`, 1);
160
+ }
161
+ const pinned = registry.getPinned ? await registry.getPinned() : undefined;
162
+ if (pinned) {
163
+ const pinnedCandidate = candidates.find((c) => c.data.pid === pinned.pid && c.data.port === pinned.port);
164
+ if (pinnedCandidate) {
165
+ process.stderr.write(`[smithue] selected PID ${pinned.pid} ${pinned.project_name} (pinned)\n`);
166
+ selectionMode = 'pinned';
167
+ candidates = [pinnedCandidate];
168
+ }
169
+ }
170
+ const recent = await registry.getMostRecent();
171
+ if (recent) {
172
+ const recentCandidate = candidates.find((c) => c.data.pid === recent.pid && c.data.port === recent.port);
173
+ if (recentCandidate) {
174
+ process.stderr.write(`[smithue] selected PID ${recent.pid} ${recent.project_name} (most recent)\n`);
175
+ selectionMode = 'most-recent';
176
+ candidates = [recentCandidate];
177
+ }
178
+ }
179
+ if (candidates.length > 1) {
180
+ const list = candidates
181
+ .map((c) => ` PID ${c.data.pid} ${c.data.project_name} (port ${c.data.port})`)
182
+ .join('\n');
183
+ throw new SmithUEError(`Multiple SmithUE instances are running. Use --pid or --project to select one:\n${list}`, 1);
184
+ }
134
185
  }
135
186
  // 7. Single candidate — liveness check
136
187
  const { file, data } = candidates[0];
137
- await checkLiveness(data.port, file, data.pid);
188
+ const liveness = await checkLiveness(data.port, file, data.pid);
189
+ try {
190
+ await registry.updateLastUsed({
191
+ projectId: projectId(data.project || ''),
192
+ pid: data.pid,
193
+ port: data.port,
194
+ project: data.project,
195
+ project_name: data.project_name,
196
+ lastConnectedAt: new Date().toISOString(),
197
+ });
198
+ }
199
+ catch {
200
+ // best effort
201
+ }
138
202
  return {
139
203
  port: data.port,
140
204
  pid: data.pid,
141
205
  project: data.project,
142
206
  project_name: data.project_name,
143
207
  plugin_version: data.plugin_version,
208
+ selection_mode: selectionMode,
209
+ busy: liveness.busy,
144
210
  };
145
211
  }
@@ -0,0 +1,19 @@
1
+ export interface RegistryEntry {
2
+ projectId: string;
3
+ pid: number;
4
+ port: number;
5
+ project: string;
6
+ project_name: string;
7
+ lastConnectedAt: string;
8
+ }
9
+ export interface Registry {
10
+ entries: RegistryEntry[];
11
+ pinned?: RegistryEntry;
12
+ }
13
+ export declare function readRegistry(): Promise<Registry>;
14
+ export declare function updateLastUsed(entry: RegistryEntry): Promise<void>;
15
+ export declare function getPinned(): Promise<RegistryEntry | undefined>;
16
+ export declare function setPinned(entry: RegistryEntry): Promise<void>;
17
+ export declare function clearPinned(): Promise<void>;
18
+ export declare function getMostRecent(): Promise<RegistryEntry | undefined>;
19
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAMD,wBAAsB,YAAY,IAAI,OAAO,CAAC,QAAQ,CAAC,CAOtD;AAED,wBAAsB,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAMxE;AAED,wBAAsB,SAAS,IAAI,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAGpE;AAED,wBAAsB,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAInE;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAIjD;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAGxE"}
@@ -0,0 +1,46 @@
1
+ import { readFile, writeFile, rename } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { getPortfileDir } from './portfile.js';
4
+ function getRegistryPath() {
5
+ return join(getPortfileDir(), 'last-used.json');
6
+ }
7
+ export async function readRegistry() {
8
+ try {
9
+ const raw = await readFile(getRegistryPath(), 'utf-8');
10
+ return JSON.parse(raw);
11
+ }
12
+ catch {
13
+ return { entries: [] };
14
+ }
15
+ }
16
+ export async function updateLastUsed(entry) {
17
+ const reg = await readRegistry();
18
+ reg.entries = reg.entries.filter((e) => e.projectId !== entry.projectId);
19
+ reg.entries.unshift(entry);
20
+ reg.entries = reg.entries.slice(0, 20);
21
+ await writeRegistryAtomic(reg);
22
+ }
23
+ export async function getPinned() {
24
+ const reg = await readRegistry();
25
+ return reg.pinned;
26
+ }
27
+ export async function setPinned(entry) {
28
+ const reg = await readRegistry();
29
+ reg.pinned = entry;
30
+ await writeRegistryAtomic(reg);
31
+ }
32
+ export async function clearPinned() {
33
+ const reg = await readRegistry();
34
+ delete reg.pinned;
35
+ await writeRegistryAtomic(reg);
36
+ }
37
+ export async function getMostRecent() {
38
+ const reg = await readRegistry();
39
+ return reg.entries[0];
40
+ }
41
+ async function writeRegistryAtomic(reg) {
42
+ const path = getRegistryPath();
43
+ const tmp = path + '.tmp';
44
+ await writeFile(tmp, JSON.stringify(reg, null, 2), 'utf-8');
45
+ await rename(tmp, path);
46
+ }
package/dist/types.d.ts CHANGED
@@ -47,4 +47,26 @@ export interface PurgeResult {
47
47
  errors: string[];
48
48
  warnings: string[];
49
49
  }
50
+ /** Persisted entry in last-used.json registry. */
51
+ export interface RegistryEntry {
52
+ projectId: string;
53
+ pid: number;
54
+ port: number;
55
+ project: string;
56
+ project_name: string;
57
+ lastConnectedAt: string;
58
+ }
59
+ /** Shape of last-used.json on disk. */
60
+ export interface Registry {
61
+ entries: RegistryEntry[];
62
+ pinned?: RegistryEntry;
63
+ }
64
+ /** Extends portfile DiscoverOpts with multi-instance selection flags. */
65
+ export interface DiscoverOptsExtended {
66
+ pid?: number;
67
+ project?: string;
68
+ port?: number;
69
+ /** If true, revert to hard-error on multi-instance (CI/script mode). Default: false. */
70
+ strict?: boolean;
71
+ }
50
72
  //# sourceMappingURL=types.d.ts.map
@@ -1 +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"}
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;AAMD,kDAAkD;AAClD,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,uCAAuC;AACvC,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,yEAAyE;AACzE,MAAM,WAAW,oBAAoB;IACnC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wFAAwF;IACxF,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB"}
package/package.json CHANGED
@@ -1,40 +1,40 @@
1
1
  {
2
- "name": "smithue-cli",
3
- "version": "0.9.1",
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
- }
2
+ "name": "smithue-cli",
3
+ "version": "0.10.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": ">=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
40
  }