@aexol/spectral 0.9.31 → 0.9.32

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.
@@ -1 +1 @@
1
- {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAsBH,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,CAsWlF;AAiED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAa5E"}
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"}
@@ -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)
@@ -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);
@@ -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,QAySnD"}
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, executeList, executeSearch, executeStatus, executeUiMessages } from "./proxy-modes.js";
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":"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"}
1
+ {"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/relay/dispatcher.ts"],"names":[],"mappings":"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"}
@@ -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":"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"}
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
- // Load spectral-mcp-adapter via jiti so tsc never crawls its .ts files in
447
- // node_modules. The static `import` was causing tsc to type-check
448
- // spectral-mcp-adapter's source and fail the build on its type errors.
449
- // jiti is the same loader spectral uses internally for all extensions.
450
- const mcpAdapterPath = resolveMcpAdapterEntry();
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;AAIlE,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,CAoC3B;AAED,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,YAAY,EACnB,EAAE,EAAE,MAAM,GACT,kBAAkB,EAAE,CAItB"}
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
- // Re-read to pick up the freshly written studio fields
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)
@@ -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"}
@@ -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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aexol/spectral",
3
- "version": "0.9.31",
3
+ "version": "0.9.32",
4
4
  "description": "AI coding agent for Aexol with relay-based browser access.",
5
5
  "type": "module",
6
6
  "private": false,