@lsproxy/cli 0.3.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 (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +167 -0
  3. package/dist/apply.d.ts +139 -0
  4. package/dist/apply.d.ts.map +1 -0
  5. package/dist/apply.js +325 -0
  6. package/dist/apply.js.map +1 -0
  7. package/dist/build-commands.d.ts +6 -0
  8. package/dist/build-commands.d.ts.map +1 -0
  9. package/dist/build-commands.js +111 -0
  10. package/dist/build-commands.js.map +1 -0
  11. package/dist/cli.d.ts +30 -0
  12. package/dist/cli.d.ts.map +1 -0
  13. package/dist/cli.js +207 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/commands/move-file.d.ts +13 -0
  16. package/dist/commands/move-file.d.ts.map +1 -0
  17. package/dist/commands/move-file.js +84 -0
  18. package/dist/commands/move-file.js.map +1 -0
  19. package/dist/commands/move-symbol.d.ts +70 -0
  20. package/dist/commands/move-symbol.d.ts.map +1 -0
  21. package/dist/commands/move-symbol.js +154 -0
  22. package/dist/commands/move-symbol.js.map +1 -0
  23. package/dist/commands/query.d.ts +14 -0
  24. package/dist/commands/query.d.ts.map +1 -0
  25. package/dist/commands/query.js +46 -0
  26. package/dist/commands/query.js.map +1 -0
  27. package/dist/commands/rename.d.ts +14 -0
  28. package/dist/commands/rename.d.ts.map +1 -0
  29. package/dist/commands/rename.js +42 -0
  30. package/dist/commands/rename.js.map +1 -0
  31. package/dist/connect.d.ts +10 -0
  32. package/dist/connect.d.ts.map +1 -0
  33. package/dist/connect.js +63 -0
  34. package/dist/connect.js.map +1 -0
  35. package/dist/discover.d.ts +17 -0
  36. package/dist/discover.d.ts.map +1 -0
  37. package/dist/discover.js +46 -0
  38. package/dist/discover.js.map +1 -0
  39. package/dist/index.d.ts +15 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +12 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/io.d.ts +76 -0
  44. package/dist/io.d.ts.map +1 -0
  45. package/dist/io.js +150 -0
  46. package/dist/io.js.map +1 -0
  47. package/dist/session.d.ts +89 -0
  48. package/dist/session.d.ts.map +1 -0
  49. package/dist/session.js +286 -0
  50. package/dist/session.js.map +1 -0
  51. package/dist/zod-to-commander.d.ts +11 -0
  52. package/dist/zod-to-commander.d.ts.map +1 -0
  53. package/dist/zod-to-commander.js +351 -0
  54. package/dist/zod-to-commander.js.map +1 -0
  55. package/package.json +65 -0
@@ -0,0 +1,6 @@
1
+ import { Command } from 'commander';
2
+ import type { ServerCapabilities } from '@lspeasy/core';
3
+ import type { RefactorSession } from './session.js';
4
+ import type { GlobalFlags } from './io.js';
5
+ export declare function buildCommandTree(program: Command, capabilities: ServerCapabilities, session: RefactorSession, flags: GlobalFlags): void;
6
+ //# sourceMappingURL=build-commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-commands.d.ts","sourceRoot":"","sources":["../src/build-commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAKxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AA0D3C,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,OAAO,EAChB,YAAY,EAAE,kBAAkB,EAChC,OAAO,EAAE,eAAe,EACxB,KAAK,EAAE,WAAW,GACjB,IAAI,CA4DN"}
@@ -0,0 +1,111 @@
1
+ import { Command } from 'commander';
2
+ import { LSPSchemas, getSchemaForMethod, getCapabilityForRequestMethod } from '@lspeasy/core';
3
+ import { zodToCommander, printAppliedChanges } from './zod-to-commander.js';
4
+ import { applyWorkspaceEdit, planWorkspaceEdit } from './apply.js';
5
+ function getNestedValue(obj, path) {
6
+ return path
7
+ .split('.')
8
+ .reduce((acc, key) => acc != null && typeof acc === 'object' ? acc[key] : undefined, obj);
9
+ }
10
+ function capabilityObject(value) {
11
+ return typeof value === 'object' && value !== null ? value : null;
12
+ }
13
+ function stringArray(value) {
14
+ return Array.isArray(value) && value.length > 0 ? value : null;
15
+ }
16
+ /**
17
+ * Enrich subcommand help text with runtime-discovered capability metadata.
18
+ * Resolves the server capability provider for the method, then scans its
19
+ * string and string-array fields — booleans and nested objects are skipped.
20
+ * Works generically for any LSP method; no per-method hardcoding required.
21
+ */
22
+ function enrichCommandFromCapabilities(method, cmd, capabilities) {
23
+ const capPath = getCapabilityForRequestMethod(method);
24
+ if (capPath === 'alwaysOn')
25
+ return;
26
+ const obj = capabilityObject(getNestedValue(capabilities, capPath));
27
+ if (!obj)
28
+ return;
29
+ const lines = [];
30
+ for (const [key, val] of Object.entries(obj)) {
31
+ const arr = stringArray(val);
32
+ if (arr) {
33
+ lines.push(`${key}: ${arr.map((v) => JSON.stringify(v)).join(' ')}`);
34
+ }
35
+ else if (typeof val === 'string' && val.length > 0) {
36
+ lines.push(`${key}: ${JSON.stringify(val)}`);
37
+ }
38
+ }
39
+ if (lines.length)
40
+ cmd.addHelpText('after', `\nCapability options:\n ${lines.join('\n ')}`);
41
+ }
42
+ // Some methods share a top-level capability path with sibling methods, so the
43
+ // top-level check alone is insufficient. Map those methods to a more specific
44
+ // sub-path that must also be truthy before exposing the command.
45
+ // e.g. semanticTokens/full shares 'semanticTokensProvider' with range/delta,
46
+ // but requires 'semanticTokensProvider.full' to actually be supported.
47
+ const CAPABILITY_REFINEMENTS = {
48
+ 'textDocument/semanticTokens/full': 'semanticTokensProvider.full'
49
+ };
50
+ export function buildCommandTree(program, capabilities, session, flags) {
51
+ for (const method of Object.keys(LSPSchemas)) {
52
+ const schema = getSchemaForMethod(method);
53
+ if (!schema)
54
+ continue;
55
+ const capPath = getCapabilityForRequestMethod(method);
56
+ if (capPath === 'alwaysOn')
57
+ continue;
58
+ if (!getNestedValue(capabilities, capPath))
59
+ continue;
60
+ const refinedCapPath = CAPABILITY_REFINEMENTS[method];
61
+ if (refinedCapPath && !getNestedValue(capabilities, refinedCapPath))
62
+ continue;
63
+ const parts = method.split('/');
64
+ if (parts.length < 2)
65
+ continue;
66
+ const [namespace] = parts;
67
+ let nsCmd = program.commands.find((c) => c.name() === namespace);
68
+ if (!nsCmd) {
69
+ nsCmd = new Command(namespace).description(`${namespace} operations`);
70
+ program.addCommand(nsCmd);
71
+ }
72
+ const subCmd = zodToCommander(method, schema, session, flags);
73
+ enrichCommandFromCapabilities(method, subCmd, capabilities);
74
+ nsCmd.addCommand(subCmd);
75
+ }
76
+ program
77
+ .command('call <method>')
78
+ .description('Send any LSP request by method name with raw JSON params')
79
+ .option('--params <json>', 'LSP params as JSON')
80
+ .action(async (method, opts) => {
81
+ try {
82
+ const params = opts.params ? JSON.parse(opts.params) : {};
83
+ const result = await session.lsp.sendRequest(method, params);
84
+ const capturedEdits = session.takeCapturedEdits();
85
+ if (capturedEdits.length > 0) {
86
+ const guard = {
87
+ root: flags.root,
88
+ allowOutsideRoot: flags.allowOutsideRoot
89
+ };
90
+ const allChanges = capturedEdits.flatMap((edit) => flags.dryRun ? planWorkspaceEdit(edit, guard) : applyWorkspaceEdit(edit, guard));
91
+ printAppliedChanges(allChanges, method, flags.dryRun, flags.json);
92
+ }
93
+ else if (flags.json) {
94
+ process.stdout.write(JSON.stringify({ ok: true, method, result }) + '\n');
95
+ }
96
+ else {
97
+ process.stdout.write(JSON.stringify(result, null, 2) + '\n');
98
+ }
99
+ }
100
+ catch (err) {
101
+ if (flags.json) {
102
+ process.stdout.write(JSON.stringify({ ok: false, error: String(err) }) + '\n');
103
+ }
104
+ else {
105
+ process.stderr.write(`error: ${String(err)}\n`);
106
+ }
107
+ process.exit(1);
108
+ }
109
+ });
110
+ }
111
+ //# sourceMappingURL=build-commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-commands.js","sourceRoot":"","sources":["../src/build-commands.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * lspeasy CLI entry point.
4
+ *
5
+ * Two-pass parse: util.parseArgs extracts global flags first (no Commander),
6
+ * then the CLI connects to the server, reads capabilities, builds a
7
+ * namespace/subcommand Commander tree, and hands process.argv back to
8
+ * Commander for final dispatch.
9
+ */
10
+ import { type GlobalFlags } from './io.js';
11
+ /** Parsed raw flag values from the first pass. */
12
+ export type ParsedOptionValues = {
13
+ server?: string;
14
+ root?: string;
15
+ 'dry-run'?: boolean;
16
+ json?: boolean;
17
+ wait?: string;
18
+ verbose?: boolean;
19
+ 'allow-outside-root'?: boolean;
20
+ 'no-proxy'?: boolean;
21
+ };
22
+ /**
23
+ * Validate raw flag values and project them onto {@link GlobalFlags}.
24
+ *
25
+ * `--wait` must parse to a finite, non-negative number; a typo like
26
+ * `--wait abc` would otherwise become NaN, which setTimeout coerces to 0,
27
+ * silently skipping the index wait refactor requests depend on.
28
+ */
29
+ export declare function buildFlags(values: ParsedOptionValues): GlobalFlags;
30
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AASH,OAAO,EAAwB,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAwCjE,kDAAkD;AAClD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,kBAAkB,GAAG,WAAW,CAiBlE"}
package/dist/cli.js ADDED
@@ -0,0 +1,207 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * lspeasy CLI entry point.
4
+ *
5
+ * Two-pass parse: util.parseArgs extracts global flags first (no Commander),
6
+ * then the CLI connects to the server, reads capabilities, builds a
7
+ * namespace/subcommand Commander tree, and hands process.argv back to
8
+ * Commander for final dispatch.
9
+ */
10
+ import { parseArgs } from 'node:util';
11
+ import { argv, exit } from 'node:process';
12
+ import { extname } from 'node:path';
13
+ import { realpathSync } from 'node:fs';
14
+ import { fileURLToPath } from 'node:url';
15
+ import { Command } from 'commander';
16
+ import { fail, resolvePathArg } from './io.js';
17
+ import { discoverServer } from '@lspeasy/core';
18
+ import { RefactorSession } from './session.js';
19
+ import { connectViaProxy } from './connect.js';
20
+ import { buildCommandTree } from './build-commands.js';
21
+ const STATIC_HELP = `lspeasy — LSP-driven CLI
22
+
23
+ Usage:
24
+ lspeasy <namespace> <command> [args]
25
+ lspeasy call <method> --params <json>
26
+
27
+ Available commands depend on the connected server's advertised capabilities.
28
+ Run with a file argument to see available commands for that language:
29
+ lspeasy textDocument hover --help src/foo.ts
30
+
31
+ Global flags:
32
+ --server <cmd> LSP server launch command (overrides lsp.json discovery)
33
+ --root <dir> Project root (default: cwd)
34
+ --dry-run Print changes; do not write
35
+ --json Machine-readable JSON on stdout; diagnostics to stderr
36
+ --wait <ms> Server index wait in ms (default: 15000)
37
+ --verbose Progress logging to stderr
38
+ --allow-outside-root Allow file paths outside --root
39
+ --no-proxy Bypass proxy daemon; connect directly to language server
40
+ -h, --help Show this help
41
+ `;
42
+ const GLOBAL_OPTION_CONFIG = {
43
+ server: { type: 'string' },
44
+ root: { type: 'string' },
45
+ 'dry-run': { type: 'boolean', default: false },
46
+ json: { type: 'boolean', default: false },
47
+ wait: { type: 'string', default: '15000' },
48
+ verbose: { type: 'boolean', default: false },
49
+ 'allow-outside-root': { type: 'boolean', default: false },
50
+ 'no-proxy': { type: 'boolean', default: false },
51
+ help: { type: 'boolean', short: 'h', default: false }
52
+ };
53
+ /**
54
+ * Validate raw flag values and project them onto {@link GlobalFlags}.
55
+ *
56
+ * `--wait` must parse to a finite, non-negative number; a typo like
57
+ * `--wait abc` would otherwise become NaN, which setTimeout coerces to 0,
58
+ * silently skipping the index wait refactor requests depend on.
59
+ */
60
+ export function buildFlags(values) {
61
+ const json = values.json === true;
62
+ const waitMs = Number(values.wait ?? '15000');
63
+ if (!Number.isFinite(waitMs) || waitMs < 0) {
64
+ fail(`--wait must be a non-negative number of milliseconds, got "${values.wait}"`, json);
65
+ }
66
+ return {
67
+ server: values.server ?? '',
68
+ root: values.root ?? process.cwd(),
69
+ dryRun: values['dry-run'] === true,
70
+ json,
71
+ verbose: values.verbose === true,
72
+ waitMs,
73
+ allowOutsideRoot: values['allow-outside-root'] === true,
74
+ noProxy: values['no-proxy'] === true,
75
+ overwrite: false // move-file removed; the flag is kept in GlobalFlags for io.ts compatibility
76
+ };
77
+ }
78
+ async function main() {
79
+ const { values, positionals } = parseArgs({
80
+ args: argv.slice(2),
81
+ options: GLOBAL_OPTION_CONFIG,
82
+ allowPositionals: true,
83
+ strict: false
84
+ });
85
+ if (!positionals.length) {
86
+ process.stdout.write(STATIC_HELP);
87
+ exit(0);
88
+ }
89
+ const flags = buildFlags(values);
90
+ let serverCommand;
91
+ let languageId = 'plaintext';
92
+ // positionals[0] = namespace, positionals[1] = method/command.
93
+ // The source file can only appear at positionals[2] (the first subcommand
94
+ // argument). A value is file-like only when it has an extension AND is not
95
+ // a JSON literal (--params values that parseArgs left in positionals).
96
+ // workspace/* methods (e.g. workspace/symbol) take a query string as their
97
+ // first argument, not a file — skip file detection for that namespace to avoid
98
+ // treating dotted identifiers like React.Component as file paths.
99
+ const isFileLike = (p) => extname(p) !== '' && !p.startsWith('{') && !p.startsWith('[') && !p.startsWith('"');
100
+ const firstSubArg = positionals[2];
101
+ const subArgFile = positionals[0] !== 'workspace' && firstSubArg !== undefined && isFileLike(firstSubArg)
102
+ ? firstSubArg
103
+ : undefined;
104
+ if (flags.server) {
105
+ serverCommand = flags.server;
106
+ // Infer languageId from the file extension when --server bypasses discovery.
107
+ if (subArgFile) {
108
+ const ext = extname(subArgFile);
109
+ const discovered = discoverServer(flags.root, ext);
110
+ if (discovered)
111
+ languageId = discovered.languageId;
112
+ }
113
+ }
114
+ else {
115
+ const ext = subArgFile ? extname(subArgFile) : '';
116
+ if (!ext) {
117
+ // No file argument — try lsp.json discovery with a wildcard lookup so
118
+ // file-less commands (e.g. workspace/symbol) can still find a server.
119
+ const discovered = discoverServer(flags.root, '');
120
+ if (discovered) {
121
+ serverCommand = discovered.serverCommand;
122
+ languageId = discovered.languageId;
123
+ }
124
+ else {
125
+ fail('Cannot determine language: pass a file argument or use --server <cmd>.', flags.json);
126
+ }
127
+ }
128
+ else {
129
+ const discovered = discoverServer(flags.root, ext);
130
+ if (!discovered) {
131
+ fail(`No LSP server configured for ${ext} files.\n` +
132
+ 'Add an lsp.json to your project (or ~/.claude/lsp.json) or use --server <cmd>.\n' +
133
+ 'Format: { "lspServers": { "lang": { "command": "...", "args": [...], "fileExtensions": { ".ext": "languageId" } } } }', flags.json);
134
+ }
135
+ serverCommand = discovered.serverCommand;
136
+ languageId = discovered.languageId;
137
+ }
138
+ }
139
+ let session;
140
+ if (flags.noProxy || !!flags.server || !serverCommand) {
141
+ session = new RefactorSession({
142
+ serverCommand,
143
+ languageId,
144
+ root: flags.root,
145
+ indexWaitMs: flags.waitMs,
146
+ verbose: flags.verbose
147
+ });
148
+ await session.start();
149
+ }
150
+ else {
151
+ session = await connectViaProxy({
152
+ root: flags.root,
153
+ languageId,
154
+ indexWaitMs: flags.waitMs,
155
+ verbose: flags.verbose
156
+ });
157
+ }
158
+ try {
159
+ if (subArgFile && !values.help) {
160
+ const absPath = resolvePathArg(subArgFile, flags);
161
+ await session.open(absPath);
162
+ }
163
+ const program = new Command('lspeasy');
164
+ // Declare global options so Commander does not reject them in pass 2
165
+ program
166
+ .option('--server <cmd>')
167
+ .option('--root <dir>')
168
+ .option('--dry-run')
169
+ .option('--json')
170
+ .option('--wait <ms>')
171
+ .option('--verbose')
172
+ .option('--allow-outside-root')
173
+ .option('--no-proxy');
174
+ buildCommandTree(program, session.capabilities, session, flags);
175
+ await program.parseAsync(argv);
176
+ }
177
+ finally {
178
+ await session.stop();
179
+ }
180
+ }
181
+ /**
182
+ * True when this module is the process entry point (vs. imported by a test).
183
+ *
184
+ * Compares resolved real paths of import.meta.url and argv[1]. The bin
185
+ * (lspeasy) is installed as a symlink to dist/cli.js, so argv[1] is the
186
+ * symlink path while import.meta.url is Node's realpath — a plain compare
187
+ * would mismatch and never run main(). realpathSync on both sides makes the
188
+ * symlinked-bin and direct-invocation cases agree.
189
+ */
190
+ function isEntryPoint() {
191
+ const entry = argv[1];
192
+ if (!entry)
193
+ return false;
194
+ try {
195
+ return realpathSync(fileURLToPath(import.meta.url)) === realpathSync(entry);
196
+ }
197
+ catch {
198
+ return false;
199
+ }
200
+ }
201
+ if (isEntryPoint()) {
202
+ main().catch((err) => {
203
+ process.stderr.write(`fatal: ${err instanceof Error ? err.message : String(err)}\n`);
204
+ exit(1);
205
+ });
206
+ }
207
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,IAAI,EAAE,cAAc,EAAoB,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;CAoBnB,CAAC;AAEF,MAAM,oBAAoB,GAAG;IAC3B,MAAM,EAAE,EAAE,IAAI,EAAE,QAAiB,EAAE;IACnC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAiB,EAAE;IACjC,SAAS,EAAE,EAAE,IAAI,EAAE,SAAkB,EAAE,OAAO,EAAE,KAAK,EAAE;IACvD,IAAI,EAAE,EAAE,IAAI,EAAE,SAAkB,EAAE,OAAO,EAAE,KAAK,EAAE;IAClD,IAAI,EAAE,EAAE,IAAI,EAAE,QAAiB,EAAE,OAAO,EAAE,OAAO,EAAE;IACnD,OAAO,EAAE,EAAE,IAAI,EAAE,SAAkB,EAAE,OAAO,EAAE,KAAK,EAAE;IACrD,oBAAoB,EAAE,EAAE,IAAI,EAAE,SAAkB,EAAE,OAAO,EAAE,KAAK,EAAE;IAClE,UAAU,EAAE,EAAE,IAAI,EAAE,SAAkB,EAAE,OAAO,EAAE,KAAK,EAAE;IACxD,IAAI,EAAE,EAAE,IAAI,EAAE,SAAkB,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE;CAC/D,CAAC;AAcF;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,MAA0B;IACnD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,KAAK,IAAI,CAAC;IAClC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,IAAI,OAAO,CAAC,CAAC;IAC9C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3C,IAAI,CAAC,8DAA8D,MAAM,CAAC,IAAI,GAAG,EAAE,IAAI,CAAC,CAAC;IAC3F,CAAC;IACD,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;QAC3B,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,EAAE;QAClC,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,KAAK,IAAI;QAClC,IAAI;QACJ,OAAO,EAAE,MAAM,CAAC,OAAO,KAAK,IAAI;QAChC,MAAM;QACN,gBAAgB,EAAE,MAAM,CAAC,oBAAoB,CAAC,KAAK,IAAI;QACvD,OAAO,EAAE,MAAM,CAAC,UAAU,CAAC,KAAK,IAAI;QACpC,SAAS,EAAE,KAAK,CAAC,6EAA6E;KAC/F,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;QACxC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QACnB,OAAO,EAAE,oBAAoB;QAC7B,gBAAgB,EAAE,IAAI;QACtB,MAAM,EAAE,KAAK;KACd,CAAC,CAAC;IAEH,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;QACxB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAClC,IAAI,CAAC,CAAC,CAAC,CAAC;IACV,CAAC;IAED,MAAM,KAAK,GAAG,UAAU,CAAC,MAA4B,CAAC,CAAC;IAEvD,IAAI,aAAqB,CAAC;IAC1B,IAAI,UAAU,GAAG,WAAW,CAAC;IAE7B,+DAA+D;IAC/D,0EAA0E;IAC1E,2EAA2E;IAC3E,uEAAuE;IACvE,2EAA2E;IAC3E,+EAA+E;IAC/E,kEAAkE;IAClE,MAAM,UAAU,GAAG,CAAC,CAAS,EAAE,EAAE,CAC/B,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IACtF,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,UAAU,GACd,WAAW,CAAC,CAAC,CAAC,KAAK,WAAW,IAAI,WAAW,KAAK,SAAS,IAAI,UAAU,CAAC,WAAW,CAAC;QACpF,CAAC,CAAC,WAAW;QACb,CAAC,CAAC,SAAS,CAAC;IAEhB,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjB,aAAa,GAAG,KAAK,CAAC,MAAM,CAAC;QAC7B,6EAA6E;QAC7E,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;YAChC,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YACnD,IAAI,UAAU;gBAAE,UAAU,GAAG,UAAU,CAAC,UAAU,CAAC;QACrD,CAAC;IACH,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAElD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,sEAAsE;YACtE,sEAAsE;YACtE,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAClD,IAAI,UAAU,EAAE,CAAC;gBACf,aAAa,GAAG,UAAU,CAAC,aAAa,CAAC;gBACzC,UAAU,GAAG,UAAU,CAAC,UAAU,CAAC;YACrC,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,wEAAwE,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YAC7F,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YACnD,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,IAAI,CACF,gCAAgC,GAAG,WAAW;oBAC5C,kFAAkF;oBAClF,uHAAuH,EACzH,KAAK,CAAC,IAAI,CACX,CAAC;YACJ,CAAC;YACD,aAAa,GAAG,UAAU,CAAC,aAAa,CAAC;YACzC,UAAU,GAAG,UAAU,CAAC,UAAU,CAAC;QACrC,CAAC;IACH,CAAC;IAED,IAAI,OAAwB,CAAC;IAC7B,IAAI,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QACtD,OAAO,GAAG,IAAI,eAAe,CAAC;YAC5B,aAAa;YACb,UAAU;YACV,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,WAAW,EAAE,KAAK,CAAC,MAAM;YACzB,OAAO,EAAE,KAAK,CAAC,OAAO;SACvB,CAAC,CAAC;QACH,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,MAAM,eAAe,CAAC;YAC9B,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,UAAU;YACV,WAAW,EAAE,KAAK,CAAC,MAAM;YACzB,OAAO,EAAE,KAAK,CAAC,OAAO;SACvB,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC;QACH,IAAI,UAAU,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YAC/B,MAAM,OAAO,GAAG,cAAc,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;YAClD,MAAM,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC9B,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC;QAEvC,qEAAqE;QACrE,OAAO;aACJ,MAAM,CAAC,gBAAgB,CAAC;aACxB,MAAM,CAAC,cAAc,CAAC;aACtB,MAAM,CAAC,WAAW,CAAC;aACnB,MAAM,CAAC,QAAQ,CAAC;aAChB,MAAM,CAAC,aAAa,CAAC;aACrB,MAAM,CAAC,WAAW,CAAC;aACnB,MAAM,CAAC,sBAAsB,CAAC;aAC9B,MAAM,CAAC,YAAY,CAAC,CAAC;QAExB,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,YAAY,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;QAEhE,MAAM,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;IACvB,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,YAAY;IACnB,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,YAAY,CAAC,KAAK,CAAC,CAAC;IAC9E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,IAAI,YAAY,EAAE,EAAE,CAAC;IACnB,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrF,IAAI,CAAC,CAAC,CAAC,CAAC;IACV,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * `lspeasy move-file <oldPath> <newPath>`
3
+ *
4
+ * Asks the server for importer path updates via `workspace/willRenameFiles`,
5
+ * applies them, then physically moves the file. Uses `git mv` when the file is
6
+ * tracked (so history follows), falling back to a plain rename.
7
+ */
8
+ import { type GlobalFlags } from '../io.js';
9
+ export declare function runMoveFile(args: {
10
+ oldPath: string;
11
+ newPath: string;
12
+ }, flags: GlobalFlags): Promise<void>;
13
+ //# sourceMappingURL=move-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"move-file.d.ts","sourceRoot":"","sources":["../../src/commands/move-file.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAcH,OAAO,EAAoC,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAgC9E,wBAAsB,WAAW,CAC/B,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAC1C,KAAK,EAAE,WAAW,GACjB,OAAO,CAAC,IAAI,CAAC,CAoDf"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * `lspeasy move-file <oldPath> <newPath>`
3
+ *
4
+ * Asks the server for importer path updates via `workspace/willRenameFiles`,
5
+ * applies them, then physically moves the file. Uses `git mv` when the file is
6
+ * tracked (so history follows), falling back to a plain rename.
7
+ */
8
+ import { execFileSync } from 'node:child_process';
9
+ import { existsSync, mkdirSync, renameSync } from 'node:fs';
10
+ import { dirname } from 'node:path';
11
+ import { pathToFileURL } from 'node:url';
12
+ import { applyWorkspaceEdit, planWorkspaceEdit, stripResourceOps } from '../apply.js';
13
+ import { emitResult, fail, resolvePathArg } from '../io.js';
14
+ import { RefactorSession } from '../session.js';
15
+ function isGitTracked(root, path) {
16
+ try {
17
+ execFileSync('git', ['ls-files', '--error-unmatch', path], { cwd: root, stdio: 'ignore' });
18
+ return true;
19
+ }
20
+ catch {
21
+ return false;
22
+ }
23
+ }
24
+ function physicallyMove(root, from, to, dryRun, overwrite) {
25
+ if (!dryRun) {
26
+ mkdirSync(dirname(to), { recursive: true });
27
+ if (isGitTracked(root, from)) {
28
+ // `git mv` refuses an existing destination; `-f` is required to clobber.
29
+ const gitArgs = overwrite ? ['mv', '-f', from, to] : ['mv', from, to];
30
+ execFileSync('git', gitArgs, { cwd: root });
31
+ }
32
+ else {
33
+ renameSync(from, to);
34
+ }
35
+ }
36
+ return { kind: 'rename', path: from, toPath: to };
37
+ }
38
+ export async function runMoveFile(args, flags) {
39
+ const from = resolvePathArg(args.oldPath, flags);
40
+ const to = resolvePathArg(args.newPath, flags);
41
+ if (!existsSync(from))
42
+ fail(`source file not found: ${from}`, flags.json);
43
+ // Refuse to clobber an existing destination unless --overwrite was given.
44
+ // `renameSync` (the untracked-file path) silently destroys the destination on
45
+ // POSIX, and `git mv` (without -f) refuses — so guard up-front, before
46
+ // spawning the server, so dry-run predicts the refusal too.
47
+ if (existsSync(to) && !flags.overwrite) {
48
+ fail(`destination already exists: ${to} (pass --overwrite to replace)`, flags.json);
49
+ }
50
+ const session = new RefactorSession({
51
+ serverCommand: flags.server,
52
+ root: flags.root,
53
+ indexWaitMs: flags.waitMs,
54
+ verbose: flags.verbose
55
+ });
56
+ try {
57
+ await session.start();
58
+ await session.openAndWait(from);
59
+ const edit = await session.requestWithRetry(() => session.lsp.sendRequest('workspace/willRenameFiles', {
60
+ files: [{ oldUri: pathToFileURL(from).href, newUri: pathToFileURL(to).href }]
61
+ }));
62
+ // A null edit just means no importers needed updating — still do the move.
63
+ // Strip ONLY the rename the server folded in that duplicates our physical
64
+ // move below (so `git mv` history is preserved); applying that rename here
65
+ // too would double-move and break a re-run with "source not found". Other
66
+ // resource ops the server emits (e.g. a `create shim.ts`) are preserved.
67
+ const importerEdit = edit ? stripResourceOps(edit, { from, to }) : undefined;
68
+ // Validate the SERVER-RETURNED edit against --root before applying it.
69
+ const guard = { root: flags.root, allowOutsideRoot: flags.allowOutsideRoot };
70
+ const importerChanges = importerEdit
71
+ ? flags.dryRun
72
+ ? planWorkspaceEdit(importerEdit, guard)
73
+ : applyWorkspaceEdit(importerEdit, guard)
74
+ : [];
75
+ const moveChange = physicallyMove(flags.root, from, to, flags.dryRun, flags.overwrite);
76
+ emitResult('move-file', [...importerChanges, moveChange], flags, {
77
+ importerFilesUpdated: importerChanges.length
78
+ });
79
+ }
80
+ finally {
81
+ await session.stop();
82
+ }
83
+ }
84
+ //# sourceMappingURL=move-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"move-file.js","sourceRoot":"","sources":["../../src/commands/move-file.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * `lspeasy move-symbol <file> <line:col> <targetFile>`
3
+ *
4
+ * Moves the symbol at the given position into `targetFile`, updating all
5
+ * importers. Driven by `textDocument/codeAction` (kind `refactor.move`).
6
+ *
7
+ * Two server shapes are supported:
8
+ * 1. The code action (or its `codeAction/resolve`) returns a `WorkspaceEdit`
9
+ * directly — applied as-is.
10
+ * 2. The action carries a `command`. We execute it via
11
+ * `workspace/executeCommand`; many servers (notably
12
+ * typescript-language-server's `_typescript.applyRefactoring`) then push
13
+ * the edit back through a `workspace/applyEdit` request, which the session
14
+ * captures. For TS, we inject the destination as
15
+ * `interactiveRefactorArguments.targetFile` so the move targets an existing
16
+ * file rather than prompting for a new one.
17
+ */
18
+ import { type WorkspaceEdit } from '../apply.js';
19
+ import { type GlobalFlags } from '../io.js';
20
+ interface LspCommand {
21
+ title: string;
22
+ command: string;
23
+ arguments?: unknown[];
24
+ }
25
+ /**
26
+ * A `textDocument/codeAction` response item. Per the LSP spec the response is
27
+ * `(Command | CodeAction)[]`, so an item may be a full {@link CodeAction} OR a
28
+ * raw {@link LspCommand} — the latter carries its payload in a TOP-LEVEL
29
+ * `arguments` field (and `command` is then a `string`). We model both so a
30
+ * command-only action's `arguments` are not dropped.
31
+ */
32
+ interface CodeAction {
33
+ title: string;
34
+ kind?: string;
35
+ edit?: WorkspaceEdit;
36
+ /** Nested command (CodeAction shape) or a command name (raw Command shape). */
37
+ command?: LspCommand | string;
38
+ /** Present only on the raw `Command` shape, alongside a string `command`. */
39
+ arguments?: unknown[];
40
+ data?: unknown;
41
+ }
42
+ /**
43
+ * Normalize the `command` of a code action into an {@link LspCommand}, preserving
44
+ * arguments for BOTH shapes:
45
+ * - nested object command → used as-is;
46
+ * - raw `Command` (string `command`) → its top-level `arguments` are retained
47
+ * (dropping them left command-only `_typescript.applyRefactoring` moves with
48
+ * an empty arg list, so the refactor could not run).
49
+ */
50
+ export declare function toLspCommand(action: CodeAction): LspCommand | undefined;
51
+ /**
52
+ * Resolve the ordered list of {@link WorkspaceEdit}s a `refactor.move` action
53
+ * produces, honoring the LSP `edit` + `command` contract:
54
+ * - if the action has an inline `edit`, it is applied FIRST;
55
+ * - if it also (or instead) has a `command`, the command is executed AFTER the
56
+ * inline edit, and EVERY edit the server then pushes via `workspace/applyEdit`
57
+ * (possibly several, in sequence) is appended in arrival order.
58
+ *
59
+ * Pure with respect to disk: it only sequences edits. `execute` runs the command
60
+ * (injecting the move target); `drainCapturedEdits` returns all server-pushed
61
+ * edits captured since the last drain.
62
+ */
63
+ export declare function resolveMoveEdits(action: CodeAction, targetFile: string, execute: (cmd: LspCommand) => Promise<void>, drainCapturedEdits: () => WorkspaceEdit[]): Promise<WorkspaceEdit[]>;
64
+ export declare function runMoveSymbol(args: {
65
+ file: string;
66
+ position: string;
67
+ targetFile: string;
68
+ }, flags: GlobalFlags): Promise<void>;
69
+ export {};
70
+ //# sourceMappingURL=move-symbol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"move-symbol.d.ts","sourceRoot":"","sources":["../../src/commands/move-symbol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,OAAO,EAAyC,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AACxF,OAAO,EAML,KAAK,WAAW,EAEjB,MAAM,UAAU,CAAC;AAGlB,UAAU,UAAU;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC;CACvB;AACD;;;;;;GAMG;AACH,UAAU,UAAU;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IAC9B,6EAA6E;IAC7E,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,CAQvE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,EAC3C,kBAAkB,EAAE,MAAM,aAAa,EAAE,GACxC,OAAO,CAAC,aAAa,EAAE,CAAC,CAS1B;AAyBD,wBAAsB,aAAa,CACjC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,EAC5D,KAAK,EAAE,WAAW,GACjB,OAAO,CAAC,IAAI,CAAC,CAmFf"}