@aexol/spectral 0.9.219 → 0.9.221
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/dist/relay/dispatcher.d.ts +1 -1
- package/dist/relay/dispatcher.d.ts.map +1 -1
- package/dist/relay/dispatcher.js +0 -9
- package/dist/server/handlers/paths-list.d.ts +6 -0
- package/dist/server/handlers/paths-list.d.ts.map +1 -1
- package/dist/server/handlers/paths-list.js +16 -7
- package/package.json +1 -1
- package/dist/server/handlers/paths-pick-directory.d.ts +0 -6
- package/dist/server/handlers/paths-pick-directory.d.ts.map +0 -1
- package/dist/server/handlers/paths-pick-directory.js +0 -175
|
@@ -50,7 +50,7 @@ import type { RelayClient } from "./client.js";
|
|
|
50
50
|
* `id` is populated when the route had an `:id` placeholder.
|
|
51
51
|
*/
|
|
52
52
|
interface RouteMatch {
|
|
53
|
-
route: "list_projects" | "create_project" | "update_project" | "delete_project" | "bind_studio" | "unbind_studio" | "get_project_observations" | "list_project_sessions" | "cleanup_project_sessions" | "cleanup_all_sessions" | "create_session" | "get_session" | "get_session_active_agent" | "update_session_active_agent" | "get_session_messages" | "update_session" | "delete_session" | "get_session_memory" | "get_session_memory_details" | "compact_session" | "remember_and_delete_session" | "fork_session" | "list_path_autocomplete" | "
|
|
53
|
+
route: "list_projects" | "create_project" | "update_project" | "delete_project" | "bind_studio" | "unbind_studio" | "get_project_observations" | "list_project_sessions" | "cleanup_project_sessions" | "cleanup_all_sessions" | "create_session" | "get_session" | "get_session_active_agent" | "update_session_active_agent" | "get_session_messages" | "update_session" | "delete_session" | "get_session_memory" | "get_session_memory_details" | "compact_session" | "remember_and_delete_session" | "fork_session" | "list_path_autocomplete" | "list_directory" | "get_home_directory" | "search_project_files" | "enqueue_prompt" | "get_prompt_queue" | "remove_prompt" | "clear_prompt_queue" | "list_mcp_status" | "reload_mcp_config" | "refresh_native_extensions" | "refresh_cloud_agents" | "get_settings" | "put_settings" | "get_agent_settings" | "put_agent_settings" | "get_prompt_mutation_settings" | "put_prompt_mutation_settings" | "wizard_login" | "list_agents" | "list_dev_processes" | "start_dev_process" | "kill_dev_process" | "restart_dev_process" | "scan_dev_servers" | "kill_dev_server";
|
|
54
54
|
id?: string;
|
|
55
55
|
/** Parsed query params, if the path carried a `?...` suffix. */
|
|
56
56
|
query?: URLSearchParams;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/relay/dispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAQH,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,SAAS,EACT,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACf,MAAM,uBAAuB,CAAC;AAK/B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/relay/dispatcher.ts"],"names":[],"mappings":"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"}
|
package/dist/relay/dispatcher.js
CHANGED
|
@@ -49,7 +49,6 @@ import { handleReloadMcpConfig } from "../server/handlers/mcp-reload.js";
|
|
|
49
49
|
import { handlePathAutocomplete } from "../server/handlers/paths-autocomplete.js";
|
|
50
50
|
import { handleGetHomeDirectory } from "../server/handlers/paths-home.js";
|
|
51
51
|
import { handleListDirectory } from "../server/handlers/paths-list.js";
|
|
52
|
-
import { handlePickDirectory } from "../server/handlers/paths-pick-directory.js";
|
|
53
52
|
import { handleSearchProjectFiles } from "../server/handlers/files-search.js";
|
|
54
53
|
import { handleBindStudioProject, handleUnbindStudioProject, handleCleanupProjectSessions, handleCreateProject, handleDeleteProject, handleGetProjectObservations, handleListProjectsAsync, handleListSessionsByProjectAsync, handleUpdateProject, } from "../server/handlers/projects.js";
|
|
55
54
|
import { handleCompactSession, handleCleanupAllSessions, handleCreateSession, handleDeleteSession, handleForkSession, handleRememberAndDeleteSession, handleGetSessionDetailAsync, handleGetSessionMessagesAsync, handleGetSessionMemoryDetails, handleGetSessionMemoryStatus, handleUpdateSession, handleGetSessionActiveAgentAsync, handleUpdateSessionActiveAgentAsync, } from "../server/handlers/sessions.js";
|
|
@@ -139,12 +138,6 @@ export function matchRoute(method, path) {
|
|
|
139
138
|
return { route: "list_path_autocomplete", query };
|
|
140
139
|
return null;
|
|
141
140
|
}
|
|
142
|
-
// /api/paths/pick-directory
|
|
143
|
-
if (cleanPath === "/api/paths/pick-directory") {
|
|
144
|
-
if (method === "POST")
|
|
145
|
-
return { route: "pick_directory" };
|
|
146
|
-
return null;
|
|
147
|
-
}
|
|
148
141
|
// /api/paths/list
|
|
149
142
|
if (cleanPath === "/api/paths/list") {
|
|
150
143
|
if (method === "POST")
|
|
@@ -1065,8 +1058,6 @@ async function dispatchRoute(match, body, deps) {
|
|
|
1065
1058
|
const prefix = match.query?.get("prefix") ?? "";
|
|
1066
1059
|
return await handlePathAutocomplete(prefix);
|
|
1067
1060
|
}
|
|
1068
|
-
case "pick_directory":
|
|
1069
|
-
return handlePickDirectory();
|
|
1070
1061
|
case "list_directory":
|
|
1071
1062
|
return await handleListDirectory(asObject(body));
|
|
1072
1063
|
case "get_home_directory":
|
|
@@ -13,6 +13,12 @@ export interface DirectoryEntry {
|
|
|
13
13
|
export interface ListDirectoryResult {
|
|
14
14
|
entries: DirectoryEntry[];
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Sort comparator for directory entries: directories first, then
|
|
18
|
+
* alphabetically by name (case-insensitive, natural/numeric so `proj2`
|
|
19
|
+
* sorts before `proj10`).
|
|
20
|
+
*/
|
|
21
|
+
export declare function compareEntries(a: Pick<DirectoryEntry, "name" | "isDirectory">, b: Pick<DirectoryEntry, "name" | "isDirectory">): number;
|
|
16
22
|
/**
|
|
17
23
|
* Read the directory at `absolutePath` and return its visible entries.
|
|
18
24
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths-list.d.ts","sourceRoot":"","sources":["../../../src/server/handlers/paths-list.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,mBAAmB,CAAC,
|
|
1
|
+
{"version":3,"file":"paths-list.d.ts","sourceRoot":"","sources":["../../../src/server/handlers/paths-list.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,aAAa,CAAC,EAC/C,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,aAAa,CAAC,GAC9C,MAAM,CAOR;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,mBAAmB,CAAC,CAsC9B"}
|
|
@@ -8,6 +8,21 @@
|
|
|
8
8
|
import { readdir } from "node:fs/promises";
|
|
9
9
|
import { join } from "node:path";
|
|
10
10
|
import { BadRequestError } from "./errors.js";
|
|
11
|
+
/**
|
|
12
|
+
* Sort comparator for directory entries: directories first, then
|
|
13
|
+
* alphabetically by name (case-insensitive, natural/numeric so `proj2`
|
|
14
|
+
* sorts before `proj10`).
|
|
15
|
+
*/
|
|
16
|
+
export function compareEntries(a, b) {
|
|
17
|
+
if (a.isDirectory && !b.isDirectory)
|
|
18
|
+
return -1;
|
|
19
|
+
if (!a.isDirectory && b.isDirectory)
|
|
20
|
+
return 1;
|
|
21
|
+
return a.name.localeCompare(b.name, undefined, {
|
|
22
|
+
sensitivity: "base",
|
|
23
|
+
numeric: true,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
11
26
|
/**
|
|
12
27
|
* Read the directory at `absolutePath` and return its visible entries.
|
|
13
28
|
*
|
|
@@ -45,12 +60,6 @@ export async function handleListDirectory(input) {
|
|
|
45
60
|
path: join(absolutePath, d.name),
|
|
46
61
|
isDirectory: d.dirent.isDirectory(),
|
|
47
62
|
}))
|
|
48
|
-
.sort(
|
|
49
|
-
if (a.isDirectory && !b.isDirectory)
|
|
50
|
-
return -1;
|
|
51
|
-
if (!a.isDirectory && b.isDirectory)
|
|
52
|
-
return 1;
|
|
53
|
-
return a.name.localeCompare(b.name, undefined, { sensitivity: "base" });
|
|
54
|
-
});
|
|
63
|
+
.sort(compareEntries);
|
|
55
64
|
return { entries };
|
|
56
65
|
}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"paths-pick-directory.d.ts","sourceRoot":"","sources":["../../../src/server/handlers/paths-pick-directory.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA8JD,wBAAgB,mBAAmB,IAAI,mBAAmB,CAmBzD"}
|
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
import { execSync } from "node:child_process";
|
|
2
|
-
import { platform } from "node:os";
|
|
3
|
-
function execErrMsg(err) {
|
|
4
|
-
if (err && typeof err === "object" && "message" in err) {
|
|
5
|
-
return String(err.message);
|
|
6
|
-
}
|
|
7
|
-
return String(err);
|
|
8
|
-
}
|
|
9
|
-
function execErrStatus(err) {
|
|
10
|
-
if (err && typeof err === "object" && "status" in err) {
|
|
11
|
-
const s = err.status;
|
|
12
|
-
return typeof s === "number" ? s : undefined;
|
|
13
|
-
}
|
|
14
|
-
return undefined;
|
|
15
|
-
}
|
|
16
|
-
function pickMacOS() {
|
|
17
|
-
const script = `
|
|
18
|
-
set folderPath to POSIX path of (choose folder with prompt "Select project directory")
|
|
19
|
-
return folderPath
|
|
20
|
-
`.trim();
|
|
21
|
-
try {
|
|
22
|
-
const result = execSync(`osascript -e '${script.replace(/'/g, "'\\''")}'`, {
|
|
23
|
-
encoding: "utf-8",
|
|
24
|
-
timeout: 180_000, // 3 min — user might take time to browse
|
|
25
|
-
});
|
|
26
|
-
const trimmed = result.trim();
|
|
27
|
-
if (!trimmed) {
|
|
28
|
-
return { path: null };
|
|
29
|
-
}
|
|
30
|
-
return { path: trimmed };
|
|
31
|
-
}
|
|
32
|
-
catch (err) {
|
|
33
|
-
if (execErrStatus(err) === 1) {
|
|
34
|
-
return { path: null }; // user cancelled
|
|
35
|
-
}
|
|
36
|
-
return {
|
|
37
|
-
path: null,
|
|
38
|
-
error: `Could not open folder picker (macOS): ${execErrMsg(err)}`,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
function tryDialog(cmd) {
|
|
43
|
-
try {
|
|
44
|
-
const result = execSync(cmd, { encoding: "utf-8", timeout: 180_000 });
|
|
45
|
-
return result.trim() || null;
|
|
46
|
-
}
|
|
47
|
-
catch (err) {
|
|
48
|
-
if (execErrStatus(err) === 1)
|
|
49
|
-
return null; // user cancelled
|
|
50
|
-
throw err;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
function pickLinux() {
|
|
54
|
-
try {
|
|
55
|
-
const p = tryDialog(`zenity --file-selection --directory --title="Select project directory"`);
|
|
56
|
-
return p ? { path: p } : { path: null };
|
|
57
|
-
}
|
|
58
|
-
catch {
|
|
59
|
-
}
|
|
60
|
-
try {
|
|
61
|
-
const p = tryDialog(`kdialog --getexistingdirectory "${process.env.HOME ?? "/"}" --title "Select project directory"`);
|
|
62
|
-
return p ? { path: p } : { path: null };
|
|
63
|
-
}
|
|
64
|
-
catch {
|
|
65
|
-
}
|
|
66
|
-
const tkResult = pickTkinter();
|
|
67
|
-
if (tkResult.path === null && !tkResult.error) {
|
|
68
|
-
return {
|
|
69
|
-
path: null,
|
|
70
|
-
error: "No folder picker available. Install zenity, kdialog, or python3-tk.",
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
return tkResult;
|
|
74
|
-
}
|
|
75
|
-
function pickWindows() {
|
|
76
|
-
const script = `
|
|
77
|
-
try {
|
|
78
|
-
Add-Type -AssemblyName System.Windows.Forms -ErrorAction Stop
|
|
79
|
-
$f = New-Object System.Windows.Forms.FolderBrowserDialog
|
|
80
|
-
$f.Description = "Select project directory"
|
|
81
|
-
$f.ShowNewFolderButton = $true
|
|
82
|
-
if ($f.ShowDialog() -eq "OK") { Write-Output $f.SelectedPath } else { Write-Output "__CANCELLED__" }
|
|
83
|
-
} catch {
|
|
84
|
-
Write-Error $_.Exception.Message
|
|
85
|
-
[Environment]::Exit(99)
|
|
86
|
-
}
|
|
87
|
-
`.trim();
|
|
88
|
-
// -EncodedCommand (UTF-16LE base64) avoids cmd.exe quote-escaping bugs
|
|
89
|
-
// that would corrupt -Command strings containing nested double-quotes.
|
|
90
|
-
const encoded = Buffer.from(script, "utf-16le").toString("base64");
|
|
91
|
-
try {
|
|
92
|
-
const result = execSync(`powershell -STA -NoProfile -EncodedCommand ${encoded}`, { encoding: "utf-8", timeout: 180_000 });
|
|
93
|
-
const trimmed = result.trim();
|
|
94
|
-
if (!trimmed || trimmed === "__CANCELLED__") {
|
|
95
|
-
return { path: null };
|
|
96
|
-
}
|
|
97
|
-
return { path: trimmed };
|
|
98
|
-
}
|
|
99
|
-
catch (err) {
|
|
100
|
-
const status = execErrStatus(err);
|
|
101
|
-
if (status === 99) {
|
|
102
|
-
const stderr = err && typeof err === "object" && "stderr" in err
|
|
103
|
-
? String(err.stderr).trim()
|
|
104
|
-
: "";
|
|
105
|
-
return {
|
|
106
|
-
path: null,
|
|
107
|
-
error: stderr || "Folder picker could not be displayed.",
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
return {
|
|
111
|
-
path: null,
|
|
112
|
-
error: `Could not open folder picker (Windows): ${execErrMsg(err)}`,
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
function pickTkinter() {
|
|
117
|
-
const script = `import tkinter as tk
|
|
118
|
-
from tkinter import filedialog
|
|
119
|
-
root = tk.Tk()
|
|
120
|
-
root.withdraw()
|
|
121
|
-
root.attributes('-topmost', True)
|
|
122
|
-
d = filedialog.askdirectory(title='Select project directory')
|
|
123
|
-
root.destroy()
|
|
124
|
-
print(d if d else "")
|
|
125
|
-
`.replace(/\n/g, ";").replace(/"/g, '\\"');
|
|
126
|
-
try {
|
|
127
|
-
const result = execSync(`python3 -c "${script}"`, {
|
|
128
|
-
encoding: "utf-8",
|
|
129
|
-
timeout: 180_000,
|
|
130
|
-
windowsHide: true,
|
|
131
|
-
});
|
|
132
|
-
const trimmed = result.trim();
|
|
133
|
-
return trimmed ? { path: trimmed } : { path: null };
|
|
134
|
-
}
|
|
135
|
-
catch {
|
|
136
|
-
try {
|
|
137
|
-
const result = execSync(`python -c "${script}"`, {
|
|
138
|
-
encoding: "utf-8",
|
|
139
|
-
timeout: 180_000,
|
|
140
|
-
});
|
|
141
|
-
const trimmed = result.trim();
|
|
142
|
-
return trimmed ? { path: trimmed } : { path: null };
|
|
143
|
-
}
|
|
144
|
-
catch {
|
|
145
|
-
return {
|
|
146
|
-
path: null,
|
|
147
|
-
error: "Python/tkinter not available for folder picker. Type the path manually.",
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
export function handlePickDirectory() {
|
|
153
|
-
const os = platform();
|
|
154
|
-
try {
|
|
155
|
-
if (os === "darwin") {
|
|
156
|
-
return pickMacOS();
|
|
157
|
-
}
|
|
158
|
-
else if (os === "linux") {
|
|
159
|
-
return pickLinux();
|
|
160
|
-
}
|
|
161
|
-
else if (os === "win32") {
|
|
162
|
-
return pickWindows();
|
|
163
|
-
}
|
|
164
|
-
else {
|
|
165
|
-
return pickTkinter();
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
catch (err) {
|
|
169
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
170
|
-
return {
|
|
171
|
-
path: null,
|
|
172
|
-
error: `Could not open folder picker (${os}): ${msg}`,
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
}
|