smithue-cli 0.9.2 → 0.11.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 +21 -0
- package/dist/cli.js +35 -5
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -1
- package/dist/commands/exec.d.ts +1 -3
- package/dist/commands/exec.d.ts.map +1 -1
- package/dist/commands/exec.js +1 -5
- package/dist/commands/list.d.ts +0 -1
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/list.js +1 -5
- package/dist/commands/search.d.ts +0 -1
- package/dist/commands/search.d.ts.map +1 -1
- package/dist/commands/search.js +1 -5
- package/dist/commands/skill.d.ts +6 -0
- package/dist/commands/skill.d.ts.map +1 -0
- package/dist/commands/skill.js +38 -0
- package/dist/commands/status.d.ts +0 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +4 -3
- package/dist/commands/use.d.ts +7 -0
- package/dist/commands/use.d.ts.map +1 -0
- package/dist/commands/use.js +45 -0
- package/dist/identity.d.ts +8 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +17 -0
- package/dist/output.d.ts.map +1 -1
- package/dist/output.js +16 -1
- package/dist/portfile.d.ts +4 -0
- package/dist/portfile.d.ts.map +1 -1
- package/dist/portfile.js +82 -16
- package/dist/registry.d.ts +19 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +46 -0
- package/dist/types.d.ts +22 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
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
|
|
@@ -45,7 +52,7 @@ program
|
|
|
45
52
|
return;
|
|
46
53
|
}
|
|
47
54
|
}
|
|
48
|
-
await execCommand(command, parsedParams, { ...globals
|
|
55
|
+
await execCommand(command, parsedParams, { ...globals });
|
|
49
56
|
});
|
|
50
57
|
// ---------------------------------------------------------------------------
|
|
51
58
|
// list
|
|
@@ -55,7 +62,7 @@ program
|
|
|
55
62
|
.description('List available tools, optionally filtered by domain')
|
|
56
63
|
.action(async (domain) => {
|
|
57
64
|
const globals = program.opts();
|
|
58
|
-
await listCommand(domain, { ...globals
|
|
65
|
+
await listCommand(domain, { ...globals });
|
|
59
66
|
});
|
|
60
67
|
// ---------------------------------------------------------------------------
|
|
61
68
|
// search
|
|
@@ -65,7 +72,7 @@ program
|
|
|
65
72
|
.description('Search tools by keyword')
|
|
66
73
|
.action(async (keyword) => {
|
|
67
74
|
const globals = program.opts();
|
|
68
|
-
await searchCommand(keyword, { ...globals
|
|
75
|
+
await searchCommand(keyword, { ...globals });
|
|
69
76
|
});
|
|
70
77
|
// ---------------------------------------------------------------------------
|
|
71
78
|
// status
|
|
@@ -76,7 +83,19 @@ program
|
|
|
76
83
|
.option('--wait <seconds>', 'wait up to N seconds for editor to be ready', parseInt)
|
|
77
84
|
.action(async (cmdOpts) => {
|
|
78
85
|
const globals = program.opts();
|
|
79
|
-
await statusCommand({ ...globals, wait: cmdOpts.wait
|
|
86
|
+
await statusCommand({ ...globals, wait: cmdOpts.wait });
|
|
87
|
+
});
|
|
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);
|
|
80
99
|
});
|
|
81
100
|
// ---------------------------------------------------------------------------
|
|
82
101
|
// prune
|
|
@@ -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
|
package/dist/client.d.ts.map
CHANGED
|
@@ -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;
|
|
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
|
}
|
package/dist/commands/exec.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { type DiscoverOpts } from '../portfile.js';
|
|
2
|
-
export
|
|
3
|
-
cliVersion?: string;
|
|
4
|
-
}
|
|
2
|
+
export type ExecOpts = DiscoverOpts;
|
|
5
3
|
export declare function execCommand(command: string, params: Record<string, unknown>, opts?: ExecOpts): Promise<void>;
|
|
6
4
|
//# sourceMappingURL=exec.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/commands/exec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/commands/exec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAIjE,MAAM,MAAM,QAAQ,GAAG,YAAY,CAAC;AAEpC,wBAAsB,WAAW,CAC/B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,IAAI,GAAE,QAAa,GAClB,OAAO,CAAC,IAAI,CAAC,CASf"}
|
package/dist/commands/exec.js
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { discoverPort } from '../portfile.js';
|
|
2
2
|
import { SmithUEClient } from '../client.js';
|
|
3
3
|
import { printResult, printError } from '../output.js';
|
|
4
|
-
import { checkVersionCompat } from '../version-check.js';
|
|
5
4
|
export async function execCommand(command, params, opts = {}) {
|
|
6
5
|
try {
|
|
7
|
-
const
|
|
8
|
-
if (opts.cliVersion)
|
|
9
|
-
checkVersionCompat(opts.cliVersion, discovered.plugin_version);
|
|
10
|
-
const { port } = discovered;
|
|
6
|
+
const { port } = await discoverPort(opts);
|
|
11
7
|
const client = new SmithUEClient({ host: '127.0.0.1', port });
|
|
12
8
|
const result = await client.executeCommand(command, params);
|
|
13
9
|
printResult(result);
|
package/dist/commands/list.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,QAAQ;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAS3F"}
|
package/dist/commands/list.js
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { discoverPort } from '../portfile.js';
|
|
2
2
|
import { SmithUEClient } from '../client.js';
|
|
3
3
|
import { printResult, printError } from '../output.js';
|
|
4
|
-
import { checkVersionCompat } from '../version-check.js';
|
|
5
4
|
export async function listCommand(domain, opts) {
|
|
6
5
|
try {
|
|
7
|
-
const
|
|
8
|
-
if (opts.cliVersion)
|
|
9
|
-
checkVersionCompat(opts.cliVersion, discovered.plugin_version);
|
|
10
|
-
const { port } = discovered;
|
|
6
|
+
const { port } = await discoverPort(opts);
|
|
11
7
|
const client = new SmithUEClient({ host: '127.0.0.1', port });
|
|
12
8
|
const result = await client.listTools(domain);
|
|
13
9
|
printResult(result);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/commands/search.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/commands/search.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBpF"}
|
package/dist/commands/search.js
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { discoverPort } from '../portfile.js';
|
|
2
2
|
import { SmithUEClient } from '../client.js';
|
|
3
3
|
import { printResult, printError } from '../output.js';
|
|
4
|
-
import { checkVersionCompat } from '../version-check.js';
|
|
5
4
|
export async function searchCommand(keyword, opts) {
|
|
6
5
|
try {
|
|
7
|
-
const
|
|
8
|
-
if (opts.cliVersion)
|
|
9
|
-
checkVersionCompat(opts.cliVersion, discovered.plugin_version);
|
|
10
|
-
const { port } = discovered;
|
|
6
|
+
const { port } = await discoverPort(opts);
|
|
11
7
|
const client = new SmithUEClient({ host: '127.0.0.1', port });
|
|
12
8
|
const domains = await client.listTools();
|
|
13
9
|
const kw = keyword.toLowerCase();
|
|
@@ -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":"
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAIA,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;CACf;AAMD,wBAAsB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA+CnE"}
|
package/dist/commands/status.js
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
import { SmithUEClient } from '../client.js';
|
|
2
2
|
import { discoverPort, SmithUEError } from '../portfile.js';
|
|
3
3
|
import { printResult, printError } from '../output.js';
|
|
4
|
-
import { checkVersionCompat } from '../version-check.js';
|
|
5
4
|
async function sleep(ms) {
|
|
6
5
|
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
7
6
|
}
|
|
8
7
|
export async function statusCommand(opts) {
|
|
9
8
|
try {
|
|
10
9
|
const discovered = await discoverPort(opts);
|
|
11
|
-
if (opts.cliVersion)
|
|
12
|
-
checkVersionCompat(opts.cliVersion, discovered.plugin_version);
|
|
13
10
|
const client = new SmithUEClient({ host: '127.0.0.1', port: discovered.port });
|
|
14
11
|
if (opts.wait !== undefined && opts.wait > 0) {
|
|
15
12
|
const timeoutMs = opts.wait * 1000;
|
|
@@ -24,6 +21,8 @@ export async function statusCommand(opts) {
|
|
|
24
21
|
ready: res.ready,
|
|
25
22
|
version: res.version,
|
|
26
23
|
pie_active: res.pie_active,
|
|
24
|
+
...(discovered.selection_mode ? { selection_mode: discovered.selection_mode } : {}),
|
|
25
|
+
...(discovered.busy ? { busy: true } : {}),
|
|
27
26
|
});
|
|
28
27
|
return;
|
|
29
28
|
}
|
|
@@ -42,6 +41,8 @@ export async function statusCommand(opts) {
|
|
|
42
41
|
ready: res.ready,
|
|
43
42
|
version: res.version,
|
|
44
43
|
pie_active: res.pie_active,
|
|
44
|
+
...(discovered.selection_mode ? { selection_mode: discovered.selection_mode } : {}),
|
|
45
|
+
...(discovered.busy ? { busy: true } : {}),
|
|
45
46
|
});
|
|
46
47
|
}
|
|
47
48
|
}
|
|
@@ -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"}
|
package/dist/identity.js
ADDED
|
@@ -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.map
CHANGED
|
@@ -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,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,
|
|
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
|
@@ -55,6 +55,21 @@ export function printError(err) {
|
|
|
55
55
|
message = String(err);
|
|
56
56
|
exitCode = 4;
|
|
57
57
|
}
|
|
58
|
-
|
|
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');
|
|
59
74
|
process.exit(exitCode);
|
|
60
75
|
}
|
package/dist/portfile.d.ts
CHANGED
|
@@ -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<{
|
package/dist/portfile.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"portfile.d.ts","sourceRoot":"","sources":["../src/portfile.ts"],"names":[],"mappings":"
|
|
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
|
|
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(
|
|
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
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
|
153
|
+
// 6. Multi-instance: select most-recent or hard-error in strict mode
|
|
129
154
|
if (candidates.length > 1) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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"}
|
package/dist/registry.js
ADDED
|
@@ -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
|
package/dist/types.d.ts.map
CHANGED
|
@@ -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"}
|