@aexol/spectral 0.9.31 → 0.9.33
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/commands/serve.d.ts.map +1 -1
- package/dist/commands/serve.js +36 -0
- package/dist/mcp/commands.js +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +101 -100
- package/dist/relay/dispatcher.d.ts +1 -1
- package/dist/relay/dispatcher.d.ts.map +1 -1
- package/dist/relay/dispatcher.js +20 -2
- package/dist/server/agent-bridge.d.ts.map +1 -1
- package/dist/server/agent-bridge.js +6 -36
- package/dist/server/handlers/projects.d.ts +13 -0
- package/dist/server/handlers/projects.d.ts.map +1 -1
- package/dist/server/handlers/projects.js +34 -2
- package/dist/studio-binding.d.ts +5 -0
- package/dist/studio-binding.d.ts.map +1 -1
- package/dist/studio-binding.js +16 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAuBH,OAAO,EAAE,WAAW,EAAmB,MAAM,oBAAoB,CAAC;AASlE,OAAO,KAAK,EAAE,aAAa,EAAc,MAAM,6BAA6B,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAGnE,OAAO,EAAmB,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAsBrE;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAazD;AAED,MAAM,WAAW,eAAe;IAC9B,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,cAAc,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,eAAe,CA6B9D;AAED,MAAM,WAAW,eAAe;IAC9B,iEAAiE;IACjE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,uCAAuC;IACvC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,4CAA4C;IAC5C,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,+DAA+D;IAC/D,aAAa,CAAC,EAAE,qBAAqB,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC;CAC/E;AAED,MAAM,WAAW,cAAc;IAC7B,qCAAqC;IACrC,KAAK,EAAE,YAAY,CAAC;IACpB,wDAAwD;IACxD,OAAO,EAAE,oBAAoB,CAAC;IAC9B,4CAA4C;IAC5C,KAAK,EAAE,WAAW,CAAC;IACnB,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,wBAAsB,QAAQ,CAAC,IAAI,GAAE,eAAoB,GAAG,OAAO,CAAC,cAAc,CAAC,CAyYlF;AAiED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAa5E"}
|
package/dist/commands/serve.js
CHANGED
|
@@ -32,6 +32,7 @@ import { hostname } from "node:os";
|
|
|
32
32
|
import { dirname, join, resolve } from "node:path";
|
|
33
33
|
import { fileURLToPath } from "node:url";
|
|
34
34
|
import { getConfigDir } from "../config.js";
|
|
35
|
+
import { readStudioBinding } from "../studio-binding.js";
|
|
35
36
|
import { NATIVE_EXTENSIONS, buildNativeExtensionsInfo } from "../sdk/coding-agent/core/extensions/native-extensions.js";
|
|
36
37
|
import { SettingsManager } from "../sdk/coding-agent/core/settings-manager.js";
|
|
37
38
|
import { getAgentDir } from "../sdk/coding-agent/config.js";
|
|
@@ -345,6 +346,7 @@ export async function runServe(opts = {}) {
|
|
|
345
346
|
});
|
|
346
347
|
wireRelay(relay);
|
|
347
348
|
relay.connect();
|
|
349
|
+
reconcileStudioBinding();
|
|
348
350
|
if (!silent) {
|
|
349
351
|
process.stdout.write(`Re-registered machine "${newReg.record.machineName}" (${newReg.record.machineId}); reconnecting…\n`);
|
|
350
352
|
}
|
|
@@ -368,6 +370,40 @@ export async function runServe(opts = {}) {
|
|
|
368
370
|
});
|
|
369
371
|
wireRelay(relay);
|
|
370
372
|
relay.connect();
|
|
373
|
+
// ---- Reconcile Studio binding on (re)connect ---------------------------
|
|
374
|
+
// Re-emit `project_studio_bound` whenever spectral starts with an existing
|
|
375
|
+
// `.aexol/aexol.jsonc` in cwd. This rehydrates the backend's in-memory
|
|
376
|
+
// machine→project attribution cache after a backend restart AND closes the
|
|
377
|
+
// attribution blind spot for bindings created via `spectral bind` or the
|
|
378
|
+
// `local_bind_project` tool (which don't otherwise emit the meta-event).
|
|
379
|
+
// RelayClient buffers the frame until the socket opens, so this is safe to
|
|
380
|
+
// fire synchronously after connect().
|
|
381
|
+
const reconcileStudioBinding = () => {
|
|
382
|
+
void (async () => {
|
|
383
|
+
try {
|
|
384
|
+
const binding = await readStudioBinding();
|
|
385
|
+
if (!binding)
|
|
386
|
+
return;
|
|
387
|
+
// The CLI-local projectId field is required by the meta-event shape.
|
|
388
|
+
// Resolve it from the local SQLite project matching cwd when possible;
|
|
389
|
+
// fall back to the studioProjectId so the event stays valid (the backend
|
|
390
|
+
// only consumes studioProjectId for attribution; projectId is a hint for
|
|
391
|
+
// browser refetch, and no browser may be subscribed yet).
|
|
392
|
+
const localProjectId = store.getProjectByCwd(cwd) ?? binding.projectId;
|
|
393
|
+
deferredPublishMetaEvent({
|
|
394
|
+
type: "project_studio_bound",
|
|
395
|
+
projectId: localProjectId,
|
|
396
|
+
studioProjectId: binding.projectId,
|
|
397
|
+
studioProjectName: binding.name,
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
catch (err) {
|
|
401
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
402
|
+
process.stderr.write(`[serve] Studio binding reconcile failed: ${msg}\n`);
|
|
403
|
+
}
|
|
404
|
+
})();
|
|
405
|
+
};
|
|
406
|
+
reconcileStudioBinding();
|
|
371
407
|
let closed = false;
|
|
372
408
|
const close = async () => {
|
|
373
409
|
if (closed)
|
package/dist/mcp/commands.js
CHANGED
|
@@ -136,7 +136,7 @@ export async function showSetupStatus(state, ext, ctx, configOverridePath) {
|
|
|
136
136
|
await showStatus(state, ctx);
|
|
137
137
|
if (!ctx.hasUI)
|
|
138
138
|
return;
|
|
139
|
-
const discovery = getMcpDiscoverySummary(configOverridePath);
|
|
139
|
+
const discovery = getMcpDiscoverySummary(configOverridePath, ctx.cwd);
|
|
140
140
|
const onboardingState = loadOnboardingState();
|
|
141
141
|
if (discovery.hasSharedServers && !onboardingState.sharedConfigHintShown) {
|
|
142
142
|
const sharedSources = discovery.sources.filter((source) => source.kind === "shared" && source.serverCount > 0);
|
package/dist/mcp/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAY,MAAM,8BAA8B,CAAC;AAa3E,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,GAAG,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAY,MAAM,8BAA8B,CAAC;AAa3E,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,GAAG,EAAE,YAAY,QAqSnD"}
|
package/dist/mcp/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { loadMcpConfig } from "./config.js";
|
|
|
5
5
|
import { buildProxyDescription, createDirectToolExecutor, getMissingConfiguredDirectToolServers, resolveDirectTools } from "./direct-tools.js";
|
|
6
6
|
import { flushMetadataCache, initializeMcp, updateStatusBar } from "./init.js";
|
|
7
7
|
import { loadMetadataCache } from "./metadata-cache.js";
|
|
8
|
-
import { executeCall, executeConnect, executeDescribe,
|
|
8
|
+
import { executeCall, executeConnect, executeDescribe, executeSearch, executeStatus, executeUiMessages } from "./proxy-modes.js";
|
|
9
9
|
import { getConfigPathFromArgv, truncateAtWord } from "./utils.js";
|
|
10
10
|
import { initializeOAuth, shutdownOAuth } from "./mcp-auth-flow.js";
|
|
11
11
|
export default function mcpAdapter(ext) {
|
|
@@ -43,28 +43,8 @@ export default function mcpAdapter(ext) {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
const earlyConfigPath = getConfigPathFromArgv();
|
|
46
|
-
const earlyConfig = loadMcpConfig(earlyConfigPath);
|
|
47
|
-
const earlyCache = loadMetadataCache();
|
|
48
|
-
const prefix = earlyConfig.settings?.toolPrefix ?? "server";
|
|
49
|
-
const envRaw = process.env.MCP_DIRECT_TOOLS;
|
|
50
|
-
const directSpecs = envRaw === "__none__"
|
|
51
|
-
? []
|
|
52
|
-
: resolveDirectTools(earlyConfig, earlyCache, prefix, envRaw?.split(",").map(s => s.trim()).filter(Boolean));
|
|
53
|
-
const missingConfiguredDirectToolServers = getMissingConfiguredDirectToolServers(earlyConfig, earlyCache);
|
|
54
|
-
const shouldRegisterProxyTool = earlyConfig.settings?.disableProxyTool !== true
|
|
55
|
-
|| directSpecs.length === 0
|
|
56
|
-
|| missingConfiguredDirectToolServers.length > 0;
|
|
57
|
-
for (const spec of directSpecs) {
|
|
58
|
-
ext.registerTool({
|
|
59
|
-
name: spec.prefixedName,
|
|
60
|
-
label: `MCP: ${spec.originalName}`,
|
|
61
|
-
description: spec.description || "(no description)",
|
|
62
|
-
promptSnippet: truncateAtWord(spec.description, 100) || `MCP tool from ${spec.serverName}`,
|
|
63
|
-
parameters: Type.Unsafe(spec.inputSchema || { type: "object", properties: {} }),
|
|
64
|
-
execute: createDirectToolExecutor(() => state, () => initPromise, spec),
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
46
|
const getSpectralTools = () => ext.getAllTools();
|
|
47
|
+
let toolsRegistered = false;
|
|
68
48
|
ext.registerFlag("mcp-config", {
|
|
69
49
|
description: "Path to MCP config file",
|
|
70
50
|
type: "string",
|
|
@@ -86,6 +66,105 @@ export default function mcpAdapter(ext) {
|
|
|
86
66
|
if (generation !== lifecycleGeneration) {
|
|
87
67
|
return;
|
|
88
68
|
}
|
|
69
|
+
if (!toolsRegistered) {
|
|
70
|
+
toolsRegistered = true;
|
|
71
|
+
const earlyConfig = loadMcpConfig(earlyConfigPath, ctx.cwd);
|
|
72
|
+
const earlyCache = loadMetadataCache();
|
|
73
|
+
const prefix = earlyConfig.settings?.toolPrefix ?? "server";
|
|
74
|
+
const envRaw = process.env.MCP_DIRECT_TOOLS;
|
|
75
|
+
const directSpecs = envRaw === "__none__"
|
|
76
|
+
? []
|
|
77
|
+
: resolveDirectTools(earlyConfig, earlyCache, prefix, envRaw?.split(",").map(s => s.trim()).filter(Boolean));
|
|
78
|
+
const missingConfiguredDirectToolServers = getMissingConfiguredDirectToolServers(earlyConfig, earlyCache);
|
|
79
|
+
const shouldRegisterProxyTool = earlyConfig.settings?.disableProxyTool !== true
|
|
80
|
+
|| directSpecs.length === 0
|
|
81
|
+
|| missingConfiguredDirectToolServers.length > 0;
|
|
82
|
+
for (const spec of directSpecs) {
|
|
83
|
+
ext.registerTool({
|
|
84
|
+
name: spec.prefixedName,
|
|
85
|
+
label: `MCP: ${spec.originalName}`,
|
|
86
|
+
description: spec.description || "(no description)",
|
|
87
|
+
promptSnippet: truncateAtWord(spec.description, 100) || `MCP tool from ${spec.serverName}`,
|
|
88
|
+
parameters: Type.Unsafe(spec.inputSchema || { type: "object", properties: {} }),
|
|
89
|
+
execute: createDirectToolExecutor(() => state, () => initPromise, spec),
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
if (shouldRegisterProxyTool) {
|
|
93
|
+
ext.registerTool({
|
|
94
|
+
name: "mcp",
|
|
95
|
+
label: "MCP",
|
|
96
|
+
description: buildProxyDescription(earlyConfig, earlyCache, directSpecs),
|
|
97
|
+
promptSnippet: "MCP gateway - connect to MCP servers and call their tools",
|
|
98
|
+
parameters: Type.Object({
|
|
99
|
+
tool: Type.Optional(Type.String({ description: "Tool name to call (e.g., 'xcodebuild_list_sims')" })),
|
|
100
|
+
args: Type.Optional(Type.String({ description: "Arguments as JSON string (e.g., '{\"key\": \"value\"}')" })),
|
|
101
|
+
connect: Type.Optional(Type.String({ description: "Server name to connect (closes any stale connection first, forces fresh reconnect)" })),
|
|
102
|
+
describe: Type.Optional(Type.String({ description: "Tool name to describe (shows parameters)" })),
|
|
103
|
+
search: Type.Optional(Type.String({ description: "Search tools by name/description" })),
|
|
104
|
+
regex: Type.Optional(Type.Boolean({ description: "Treat search as regex (default: substring match)" })),
|
|
105
|
+
includeSchemas: Type.Optional(Type.Boolean({ description: "Include parameter schemas in search results (default: true)" })),
|
|
106
|
+
server: Type.Optional(Type.String({ description: "Filter to specific server (also disambiguates tool calls)" })),
|
|
107
|
+
action: Type.Optional(Type.String({ description: "Action: 'ui-messages' to retrieve prompts/intents from UI sessions" })),
|
|
108
|
+
restart: Type.Optional(Type.String({ description: "Force restart a dead server process. Use when server returns 'Not connected' or calls fail." })),
|
|
109
|
+
}),
|
|
110
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
111
|
+
let parsedArgs;
|
|
112
|
+
if (params.args) {
|
|
113
|
+
try {
|
|
114
|
+
parsedArgs = JSON.parse(params.args);
|
|
115
|
+
if (typeof parsedArgs !== "object" || parsedArgs === null || Array.isArray(parsedArgs)) {
|
|
116
|
+
const gotType = Array.isArray(parsedArgs) ? "array" : parsedArgs === null ? "null" : typeof parsedArgs;
|
|
117
|
+
throw new Error(`Invalid args: expected a JSON object, got ${gotType}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
if (error instanceof SyntaxError) {
|
|
122
|
+
throw new Error(`Invalid args JSON: ${error.message}`, { cause: error });
|
|
123
|
+
}
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (!state && initPromise) {
|
|
128
|
+
try {
|
|
129
|
+
state = await initPromise;
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
133
|
+
return {
|
|
134
|
+
content: [{ type: "text", text: `MCP initialization failed: ${message}` }],
|
|
135
|
+
details: { error: "init_failed", message },
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (!state) {
|
|
140
|
+
return {
|
|
141
|
+
content: [{ type: "text", text: "MCP not initialized" }],
|
|
142
|
+
details: { error: "not_initialized" },
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
if (params.action === "ui-messages") {
|
|
146
|
+
return executeUiMessages(state);
|
|
147
|
+
}
|
|
148
|
+
if (params.tool) {
|
|
149
|
+
return executeCall(state, params.tool, parsedArgs, params.server, getSpectralTools);
|
|
150
|
+
}
|
|
151
|
+
if (params.restart) {
|
|
152
|
+
return executeConnect(state, params.restart);
|
|
153
|
+
}
|
|
154
|
+
if (params.connect) {
|
|
155
|
+
return executeConnect(state, params.connect);
|
|
156
|
+
}
|
|
157
|
+
if (params.describe) {
|
|
158
|
+
return executeDescribe(state, params.describe);
|
|
159
|
+
}
|
|
160
|
+
if (params.search) {
|
|
161
|
+
return executeSearch(state, params.search, params.regex, params.server, params.includeSchemas);
|
|
162
|
+
}
|
|
163
|
+
return executeStatus(state);
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
89
168
|
await initializeOAuth().catch(err => {
|
|
90
169
|
console.error("MCP OAuth initialization failed:", err);
|
|
91
170
|
});
|
|
@@ -198,82 +277,4 @@ export default function mcpAdapter(ext) {
|
|
|
198
277
|
await authenticateServer(serverName, state.config, ctx);
|
|
199
278
|
},
|
|
200
279
|
});
|
|
201
|
-
if (shouldRegisterProxyTool) {
|
|
202
|
-
ext.registerTool({
|
|
203
|
-
name: "mcp",
|
|
204
|
-
label: "MCP",
|
|
205
|
-
description: buildProxyDescription(earlyConfig, earlyCache, directSpecs),
|
|
206
|
-
promptSnippet: "MCP gateway - connect to MCP servers and call their tools",
|
|
207
|
-
parameters: Type.Object({
|
|
208
|
-
tool: Type.Optional(Type.String({ description: "Tool name to call (e.g., 'xcodebuild_list_sims')" })),
|
|
209
|
-
args: Type.Optional(Type.String({ description: "Arguments as JSON string (e.g., '{\"key\": \"value\"}')" })),
|
|
210
|
-
connect: Type.Optional(Type.String({ description: "Server name to connect (closes any stale connection first, forces fresh reconnect)" })),
|
|
211
|
-
describe: Type.Optional(Type.String({ description: "Tool name to describe (shows parameters)" })),
|
|
212
|
-
search: Type.Optional(Type.String({ description: "Search tools by name/description" })),
|
|
213
|
-
regex: Type.Optional(Type.Boolean({ description: "Treat search as regex (default: substring match)" })),
|
|
214
|
-
includeSchemas: Type.Optional(Type.Boolean({ description: "Include parameter schemas in search results (default: true)" })),
|
|
215
|
-
server: Type.Optional(Type.String({ description: "Filter to specific server (also disambiguates tool calls)" })),
|
|
216
|
-
action: Type.Optional(Type.String({ description: "Action: 'ui-messages' to retrieve prompts/intents from UI sessions" })),
|
|
217
|
-
restart: Type.Optional(Type.String({ description: "Force restart a dead server process. Use when server returns 'Not connected' or calls fail." })),
|
|
218
|
-
}),
|
|
219
|
-
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
220
|
-
let parsedArgs;
|
|
221
|
-
if (params.args) {
|
|
222
|
-
try {
|
|
223
|
-
parsedArgs = JSON.parse(params.args);
|
|
224
|
-
if (typeof parsedArgs !== "object" || parsedArgs === null || Array.isArray(parsedArgs)) {
|
|
225
|
-
const gotType = Array.isArray(parsedArgs) ? "array" : parsedArgs === null ? "null" : typeof parsedArgs;
|
|
226
|
-
throw new Error(`Invalid args: expected a JSON object, got ${gotType}`);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
catch (error) {
|
|
230
|
-
if (error instanceof SyntaxError) {
|
|
231
|
-
throw new Error(`Invalid args JSON: ${error.message}`, { cause: error });
|
|
232
|
-
}
|
|
233
|
-
throw error;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
if (!state && initPromise) {
|
|
237
|
-
try {
|
|
238
|
-
state = await initPromise;
|
|
239
|
-
}
|
|
240
|
-
catch (error) {
|
|
241
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
242
|
-
return {
|
|
243
|
-
content: [{ type: "text", text: `MCP initialization failed: ${message}` }],
|
|
244
|
-
details: { error: "init_failed", message },
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
if (!state) {
|
|
249
|
-
return {
|
|
250
|
-
content: [{ type: "text", text: "MCP not initialized" }],
|
|
251
|
-
details: { error: "not_initialized" },
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
if (params.action === "ui-messages") {
|
|
255
|
-
return executeUiMessages(state);
|
|
256
|
-
}
|
|
257
|
-
if (params.tool) {
|
|
258
|
-
return executeCall(state, params.tool, parsedArgs, params.server, getSpectralTools);
|
|
259
|
-
}
|
|
260
|
-
if (params.restart) {
|
|
261
|
-
return executeConnect(state, params.restart);
|
|
262
|
-
}
|
|
263
|
-
if (params.connect) {
|
|
264
|
-
return executeConnect(state, params.connect);
|
|
265
|
-
}
|
|
266
|
-
if (params.describe) {
|
|
267
|
-
return executeDescribe(state, params.describe);
|
|
268
|
-
}
|
|
269
|
-
if (params.search) {
|
|
270
|
-
return executeSearch(state, params.search, params.regex, params.server, params.includeSchemas);
|
|
271
|
-
}
|
|
272
|
-
if (params.server) {
|
|
273
|
-
return executeList(state, params.server);
|
|
274
|
-
}
|
|
275
|
-
return executeStatus(state);
|
|
276
|
-
},
|
|
277
|
-
});
|
|
278
|
-
}
|
|
279
280
|
}
|
|
@@ -48,7 +48,7 @@ import type { RelayClient } from "./client.js";
|
|
|
48
48
|
* `id` is populated when the route had an `:id` placeholder.
|
|
49
49
|
*/
|
|
50
50
|
interface RouteMatch {
|
|
51
|
-
route: "list_projects" | "create_project" | "update_project" | "delete_project" | "bind_studio" | "get_project_observations" | "list_project_sessions" | "create_session" | "get_session" | "update_session" | "delete_session" | "get_session_memory" | "get_session_memory_details" | "compact_session" | "remember_and_delete_session" | "fork_session" | "list_path_autocomplete" | "pick_directory" | "search_project_files" | "enqueue_prompt" | "get_prompt_queue" | "remove_prompt" | "clear_prompt_queue" | "list_mcp_status" | "get_settings" | "put_settings" | "get_agent_settings" | "put_agent_settings" | "list_agents";
|
|
51
|
+
route: "list_projects" | "create_project" | "update_project" | "delete_project" | "bind_studio" | "unbind_studio" | "get_project_observations" | "list_project_sessions" | "create_session" | "get_session" | "update_session" | "delete_session" | "get_session_memory" | "get_session_memory_details" | "compact_session" | "remember_and_delete_session" | "fork_session" | "list_path_autocomplete" | "pick_directory" | "search_project_files" | "enqueue_prompt" | "get_prompt_queue" | "remove_prompt" | "clear_prompt_queue" | "list_mcp_status" | "get_settings" | "put_settings" | "get_agent_settings" | "put_agent_settings" | "list_agents";
|
|
52
52
|
id?: string;
|
|
53
53
|
/** Parsed query params, if the path carried a `?...` suffix. */
|
|
54
54
|
query?: URLSearchParams;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/relay/dispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAIH,OAAO,KAAK,EACV,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,SAAS,EACT,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACf,MAAM,uBAAuB,CAAC;AAI/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
|
@@ -44,7 +44,7 @@ import { handleListMcpStatus } from "../server/handlers/mcp-status.js";
|
|
|
44
44
|
import { handlePathAutocomplete } from "../server/handlers/paths-autocomplete.js";
|
|
45
45
|
import { handlePickDirectory } from "../server/handlers/paths-pick-directory.js";
|
|
46
46
|
import { handleSearchProjectFiles } from "../server/handlers/files-search.js";
|
|
47
|
-
import { handleBindStudioProject, handleCreateProject, handleDeleteProject, handleGetProjectObservations, handleListProjects, handleListSessionsByProject, handleUpdateProject, } from "../server/handlers/projects.js";
|
|
47
|
+
import { handleBindStudioProject, handleUnbindStudioProject, handleCreateProject, handleDeleteProject, handleGetProjectObservations, handleListProjects, handleListSessionsByProject, handleUpdateProject, } from "../server/handlers/projects.js";
|
|
48
48
|
import { handleCompactSession, handleCreateSession, handleDeleteSession, handleForkSession, handleRememberAndDeleteSession, handleGetSessionDetail, handleGetSessionMemoryDetails, handleGetSessionMemoryStatus, handleUpdateSession, } from "../server/handlers/sessions.js";
|
|
49
49
|
import { handleClearPromptQueue, handleEnqueuePrompt, handleGetPromptQueue, handleRemovePrompt, } from "../server/handlers/queue.js";
|
|
50
50
|
import { handleGetAgentSettings, handleListAgents, handlePutAgentSettings, } from "../server/handlers/agent-settings.js";
|
|
@@ -125,7 +125,7 @@ export function matchRoute(method, path) {
|
|
|
125
125
|
return { route: "search_project_files", id, query };
|
|
126
126
|
return null;
|
|
127
127
|
}
|
|
128
|
-
// /api/projects/:id/bind-studio
|
|
128
|
+
// /api/projects/:id/bind-studio and /api/projects/:id/unbind-studio
|
|
129
129
|
const bindStudioMatch = /^\/api\/projects\/([^/]+)\/bind-studio$/.exec(cleanPath);
|
|
130
130
|
if (bindStudioMatch) {
|
|
131
131
|
const id = decodeURIComponent(bindStudioMatch[1]);
|
|
@@ -133,6 +133,13 @@ export function matchRoute(method, path) {
|
|
|
133
133
|
return { route: "bind_studio", id };
|
|
134
134
|
return null;
|
|
135
135
|
}
|
|
136
|
+
const unbindStudioMatch = /^\/api\/projects\/([^/]+)\/unbind-studio$/.exec(cleanPath);
|
|
137
|
+
if (unbindStudioMatch) {
|
|
138
|
+
const id = decodeURIComponent(unbindStudioMatch[1]);
|
|
139
|
+
if (method === "POST")
|
|
140
|
+
return { route: "unbind_studio", id };
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
136
143
|
// /api/projects/:id/observations
|
|
137
144
|
const projectObsMatch = /^\/api\/projects\/([^/]+)\/observations$/.exec(cleanPath);
|
|
138
145
|
if (projectObsMatch) {
|
|
@@ -353,6 +360,17 @@ async function dispatchRoute(match, body, deps) {
|
|
|
353
360
|
});
|
|
354
361
|
return result;
|
|
355
362
|
}
|
|
363
|
+
case "unbind_studio": {
|
|
364
|
+
const result = await handleUnbindStudioProject(store, id);
|
|
365
|
+
if (result.studioProjectId) {
|
|
366
|
+
safePublish(publishMetaEvent, logger, {
|
|
367
|
+
type: "project_studio_unbound",
|
|
368
|
+
projectId: id,
|
|
369
|
+
studioProjectId: result.studioProjectId,
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
return result;
|
|
373
|
+
}
|
|
356
374
|
case "get_project_observations": {
|
|
357
375
|
const limitVal = Number(match.query?.get("limit") ?? 30);
|
|
358
376
|
return handleGetProjectObservations(store, id, Math.max(1, Math.min(100, limitVal || 30)));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-bridge.d.ts","sourceRoot":"","sources":["../../src/server/agent-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;
|
|
1
|
+
{"version":3,"file":"agent-bridge.d.ts","sourceRoot":"","sources":["../../src/server/agent-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -48,13 +48,12 @@
|
|
|
48
48
|
* a single spectral session also work normally (the same AgentSession
|
|
49
49
|
* instance is reused across `prompt()` calls).
|
|
50
50
|
*/
|
|
51
|
-
import { createJiti } from "@mariozechner/jiti";
|
|
52
51
|
import { AuthStorage, createAgentSession, DefaultResourceLoader, ModelRegistry, SessionManager, SettingsManager, } from "../sdk/coding-agent/index.js";
|
|
53
52
|
import { randomUUID } from "node:crypto";
|
|
54
53
|
import { existsSync, statSync } from "node:fs";
|
|
55
54
|
import { dirname, join, resolve } from "node:path";
|
|
56
|
-
import { fileURLToPath } from "node:url";
|
|
57
55
|
import aexolMcpExtension from "../extensions/aexol-mcp.js";
|
|
56
|
+
import mcpAdapterFactory from "../mcp/index.js";
|
|
58
57
|
import { discoverPrimaryAgent, injectPrimaryAgentPrompt } from "../agent/agents.js";
|
|
59
58
|
import { loadAgentSettings } from "./handlers/agent-settings.js";
|
|
60
59
|
import kanbanBridgeExtension from "../extensions/kanban-bridge.js";
|
|
@@ -129,20 +128,6 @@ function extractTextFromContent(content) {
|
|
|
129
128
|
}
|
|
130
129
|
return out;
|
|
131
130
|
}
|
|
132
|
-
/**
|
|
133
|
-
* Resolve the entry point of the spectral-mcp-adapter extension.
|
|
134
|
-
* Uses the bundled copy in dist/mcp/index.js (same directory as this file).
|
|
135
|
-
* Returns the absolute path, or null if the bundled file is missing.
|
|
136
|
-
*/
|
|
137
|
-
function resolveMcpAdapterEntry() {
|
|
138
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
139
|
-
// agent-bridge.ts compiles to dist/server/agent-bridge.js;
|
|
140
|
-
// the bundled MCP adapter sits next door at dist/mcp/index.js.
|
|
141
|
-
const bundledIndex = resolve(__dirname, "..", "mcp", "index.js");
|
|
142
|
-
if (existsSync(bundledIndex))
|
|
143
|
-
return bundledIndex;
|
|
144
|
-
return null;
|
|
145
|
-
}
|
|
146
131
|
/**
|
|
147
132
|
* Token pricing per model (USD per 1M tokens). Matches provider list
|
|
148
133
|
* prices as of May 2026. Used to compute token cost server-side when
|
|
@@ -443,26 +428,11 @@ export class AgentBridge {
|
|
|
443
428
|
if (agentSettings.subagentsEnabled) {
|
|
444
429
|
extensionFactories.splice(4, 0, async (ext) => { subagentExt(ext, { disabledAgents: agentSettings.disabledSubagents }); });
|
|
445
430
|
}
|
|
446
|
-
//
|
|
447
|
-
//
|
|
448
|
-
//
|
|
449
|
-
//
|
|
450
|
-
|
|
451
|
-
if (mcpAdapterPath) {
|
|
452
|
-
try {
|
|
453
|
-
const jiti = createJiti(import.meta.url, { moduleCache: false });
|
|
454
|
-
const mcpAdapterFactory = await jiti.import(mcpAdapterPath, { default: true });
|
|
455
|
-
if (typeof mcpAdapterFactory === "function") {
|
|
456
|
-
extensionFactories.push(async (ext) => mcpAdapterFactory(ext));
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
catch {
|
|
460
|
-
console.info("[AgentBridge] spectral-mcp-adapter not found; standard MCP servers disabled.");
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
else {
|
|
464
|
-
console.info("[AgentBridge] spectral-mcp-adapter not found; standard MCP servers disabled.");
|
|
465
|
-
}
|
|
431
|
+
// Register the bundled MCP adapter. Static import is required so the
|
|
432
|
+
// adapter is included in compiled standalone binaries (Bun build), where
|
|
433
|
+
// filesystem-based discovery via jiti fails because the source files are
|
|
434
|
+
// embedded in the binary rather than present on disk.
|
|
435
|
+
extensionFactories.push(async (ext) => { mcpAdapterFactory(ext); });
|
|
466
436
|
// ResourceLoader with extensions wired in via factories.
|
|
467
437
|
// Each factory's signature `(ext: ExtensionAPI) => Promise<void>` matches
|
|
468
438
|
// the ExtensionFactory type exactly, so we can pass them directly.
|
|
@@ -62,5 +62,18 @@ export interface BindStudioResult {
|
|
|
62
62
|
* `.aexol/aexol.jsonc` into the project's filesystem path.
|
|
63
63
|
*/
|
|
64
64
|
export declare function handleBindStudioProject(store: SessionStore, id: string, body: BindStudioInputRaw): Promise<BindStudioResult>;
|
|
65
|
+
export interface UnbindStudioResult {
|
|
66
|
+
project: WireProject;
|
|
67
|
+
studioProjectId: string | null;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Unbind a local project directory from its Aexol Studio project by
|
|
71
|
+
* removing `.aexol/aexol.jsonc` from the project's filesystem path.
|
|
72
|
+
*
|
|
73
|
+
* Returns the studioProjectId that was previously bound (null when there
|
|
74
|
+
* was no binding), so callers can emit a `project_studio_unbound` meta-event
|
|
75
|
+
* with the correct id even though the file is already gone on return.
|
|
76
|
+
*/
|
|
77
|
+
export declare function handleUnbindStudioProject(store: SessionStore, id: string): Promise<UnbindStudioResult>;
|
|
65
78
|
export declare function handleListSessionsByProject(store: SessionStore, id: string): WireSessionSummary[];
|
|
66
79
|
//# sourceMappingURL=projects.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../../src/server/handlers/projects.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../../src/server/handlers/projects.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAQlE,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,YAAY,EACnB,EAAE,EAAE,MAAM,EACV,KAAK,SAAK,GACT,sBAAsB,EAAE,CAI1B;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,GAAG,WAAW,EAAE,CAErE;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,qBAAqB,GAC1B,WAAW,CAYb;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,CAI7E;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,YAAY,EACnB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,qBAAqB,GAC1B,WAAW,CAwBb;AAED,MAAM,WAAW,mBAAmB;IAClC,kEAAkE;IAClE,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,YAAY,EACnB,EAAE,EAAE,MAAM,GACT,mBAAmB,CAMrB;AAED,MAAM,WAAW,kBAAkB;IACjC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,WAAW,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,YAAY,EACnB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,gBAAgB,CAAC,CA6C3B;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,WAAW,CAAC;IACrB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,YAAY,EACnB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,kBAAkB,CAAC,CAkB7B;AAED,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,YAAY,EACnB,EAAE,EAAE,MAAM,GACT,kBAAkB,EAAE,CAItB"}
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
*/
|
|
22
22
|
import { validateProjectPath } from "../paths.js";
|
|
23
23
|
import { BadRequestError, NotFoundError } from "./errors.js";
|
|
24
|
-
import { writeStudioBindingAt } from "../../studio-binding.js";
|
|
24
|
+
import { writeStudioBindingAt, deleteStudioBindingAt, } from "../../studio-binding.js";
|
|
25
25
|
export function handleGetProjectObservations(store, id, limit = 30) {
|
|
26
26
|
const project = store.getProject(id);
|
|
27
27
|
if (!project)
|
|
@@ -110,7 +110,15 @@ export async function handleBindStudioProject(store, id, body) {
|
|
|
110
110
|
...(studioProjectName ? { name: studioProjectName } : {}),
|
|
111
111
|
};
|
|
112
112
|
await writeStudioBindingAt(project.path, binding);
|
|
113
|
-
//
|
|
113
|
+
// Studio → Agent name sync (bind-time): the Studio project is the canonical
|
|
114
|
+
// identity for bound projects, so adopt its name on the local SQLite row
|
|
115
|
+
// too. This keeps the /agent sidebar title, sessions list, and the Studio
|
|
116
|
+
// project name identical from the moment of binding. A no-op when the
|
|
117
|
+
// names already match or when no Studio name was supplied.
|
|
118
|
+
if (studioProjectName && studioProjectName !== project.name) {
|
|
119
|
+
store.updateProject(id, { name: studioProjectName });
|
|
120
|
+
}
|
|
121
|
+
// Re-read to pick up the freshly written studio fields (and renamed row)
|
|
114
122
|
const updated = store.getProject(id);
|
|
115
123
|
return {
|
|
116
124
|
project: updated,
|
|
@@ -119,6 +127,30 @@ export async function handleBindStudioProject(store, id, body) {
|
|
|
119
127
|
...(studioTeamId ? { studioTeamId } : {}),
|
|
120
128
|
};
|
|
121
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* Unbind a local project directory from its Aexol Studio project by
|
|
132
|
+
* removing `.aexol/aexol.jsonc` from the project's filesystem path.
|
|
133
|
+
*
|
|
134
|
+
* Returns the studioProjectId that was previously bound (null when there
|
|
135
|
+
* was no binding), so callers can emit a `project_studio_unbound` meta-event
|
|
136
|
+
* with the correct id even though the file is already gone on return.
|
|
137
|
+
*/
|
|
138
|
+
export async function handleUnbindStudioProject(store, id) {
|
|
139
|
+
const project = store.getProject(id);
|
|
140
|
+
if (!project)
|
|
141
|
+
throw new NotFoundError("Project not found");
|
|
142
|
+
// Capture the previously-bound studioProjectId BEFORE deleting the file
|
|
143
|
+
// so the dispatcher can broadcast `project_studio_unbound` with the id.
|
|
144
|
+
// `applyBindingFields` (called by getProject) already attached it.
|
|
145
|
+
const previousStudioProjectId = project.studioProjectId ?? null;
|
|
146
|
+
await deleteStudioBindingAt(project.path);
|
|
147
|
+
// Re-read so the returned project no longer carries studio fields.
|
|
148
|
+
const updated = store.getProject(id);
|
|
149
|
+
return {
|
|
150
|
+
project: updated,
|
|
151
|
+
studioProjectId: previousStudioProjectId,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
122
154
|
export function handleListSessionsByProject(store, id) {
|
|
123
155
|
const project = store.getProject(id);
|
|
124
156
|
if (!project)
|
package/dist/studio-binding.d.ts
CHANGED
|
@@ -41,4 +41,9 @@ export declare function writeStudioBindingAt(projectPath: string, binding: Studi
|
|
|
41
41
|
* Returns `true` when the file existed and was deleted, `false` otherwise (no-op).
|
|
42
42
|
*/
|
|
43
43
|
export declare function deleteStudioBinding(): Promise<boolean>;
|
|
44
|
+
/**
|
|
45
|
+
* Remove the Studio binding file at an arbitrary project path.
|
|
46
|
+
* Returns `true` when the file existed and was deleted, `false` otherwise (no-op).
|
|
47
|
+
*/
|
|
48
|
+
export declare function deleteStudioBindingAt(projectPath: string): Promise<boolean>;
|
|
44
49
|
//# sourceMappingURL=studio-binding.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"studio-binding.d.ts","sourceRoot":"","sources":["../src/studio-binding.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAaD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAItD;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAUvE;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAa/B;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC,CAS5D"}
|
|
1
|
+
{"version":3,"file":"studio-binding.d.ts","sourceRoot":"","sources":["../src/studio-binding.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAaD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAItD;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAUvE;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAa/B;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC,CAS5D;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CASjF"}
|
package/dist/studio-binding.js
CHANGED
|
@@ -115,3 +115,19 @@ export async function deleteStudioBinding() {
|
|
|
115
115
|
throw err;
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* Remove the Studio binding file at an arbitrary project path.
|
|
120
|
+
* Returns `true` when the file existed and was deleted, `false` otherwise (no-op).
|
|
121
|
+
*/
|
|
122
|
+
export async function deleteStudioBindingAt(projectPath) {
|
|
123
|
+
try {
|
|
124
|
+
await unlink(join(projectPath, BINDING_DIR, BINDING_FILE));
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
const code = err.code;
|
|
129
|
+
if (code === "ENOENT")
|
|
130
|
+
return false;
|
|
131
|
+
throw err;
|
|
132
|
+
}
|
|
133
|
+
}
|