@aexol/spectral 0.9.220 → 0.9.222
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/agent/index.d.ts +7 -3
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +35 -8
- package/dist/extensions/aexol-backend-client.d.ts +85 -0
- package/dist/extensions/aexol-backend-client.d.ts.map +1 -0
- package/dist/extensions/aexol-backend-client.js +159 -0
- package/dist/extensions/aexol-mcp.d.ts +10 -6
- package/dist/extensions/aexol-mcp.d.ts.map +1 -1
- package/dist/extensions/aexol-mcp.js +21 -106
- package/dist/extensions/logic-trace-backend-draft.d.ts +68 -0
- package/dist/extensions/logic-trace-backend-draft.d.ts.map +1 -0
- package/dist/extensions/logic-trace-backend-draft.js +171 -0
- package/dist/extensions/logic-trace-validate.d.ts +33 -0
- package/dist/extensions/logic-trace-validate.d.ts.map +1 -0
- package/dist/extensions/logic-trace-validate.js +73 -0
- package/dist/extensions/logic-trace.d.ts +213 -0
- package/dist/extensions/logic-trace.d.ts.map +1 -0
- package/dist/extensions/logic-trace.js +1098 -0
- package/dist/generated/parser/lexer.d.ts +148 -0
- package/dist/generated/parser/lexer.d.ts.map +1 -0
- package/dist/generated/parser/lexer.js +877 -0
- package/dist/generated/parser/mod.d.ts +26 -0
- package/dist/generated/parser/mod.d.ts.map +1 -0
- package/dist/generated/parser/mod.js +30 -0
- package/dist/generated/parser/parser.d.ts +161 -0
- package/dist/generated/parser/parser.d.ts.map +1 -0
- package/dist/generated/parser/parser.js +754 -0
- package/dist/generated/parser/tokenizer.d.ts +107 -0
- package/dist/generated/parser/tokenizer.d.ts.map +1 -0
- package/dist/generated/parser/tokenizer.js +202 -0
- package/dist/generated/parser/validator.d.ts +45 -0
- package/dist/generated/parser/validator.d.ts.map +1 -0
- package/dist/generated/parser/validator.js +202 -0
- package/dist/generated/zeus/const.d.ts.map +1 -1
- package/dist/generated/zeus/const.js +4 -170
- package/dist/generated/zeus/index.d.ts +8 -873
- package/dist/generated/zeus/index.d.ts.map +1 -1
- package/dist/generated/zeus/index.js +0 -7
- package/dist/mcp/ui-stream-types.d.ts +2 -2
- package/dist/memory/tools/share-project-observation.js +1 -1
- package/dist/memory/tools/write-project-observation.d.ts.map +1 -1
- package/dist/memory/tools/write-project-observation.js +4 -3
- package/dist/sdk/agent-core/harness/types.d.ts +0 -1
- package/dist/sdk/agent-core/harness/types.d.ts.map +1 -1
- package/dist/sdk/agent-core/index.d.ts +0 -8
- package/dist/sdk/agent-core/index.d.ts.map +1 -1
- package/dist/sdk/agent-core/index.js +0 -9
- package/dist/sdk/coding-agent/core/extensions/index.d.ts +1 -1
- package/dist/sdk/coding-agent/core/extensions/index.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/extensions/native-extensions.js +2 -2
- package/dist/sdk/coding-agent/core/extensions/types.d.ts +20 -1
- package/dist/sdk/coding-agent/core/extensions/types.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/tools/tool-definition-wrapper.d.ts +9 -4
- package/dist/sdk/coding-agent/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/tools/tool-definition-wrapper.js +15 -2
- package/dist/sdk/coding-agent/index.d.ts +1 -1
- package/dist/sdk/coding-agent/index.d.ts.map +1 -1
- package/dist/server/agent-bridge/headless-ui.d.ts +20 -0
- package/dist/server/agent-bridge/headless-ui.d.ts.map +1 -0
- package/dist/server/agent-bridge/headless-ui.js +85 -0
- package/dist/server/agent-bridge/pricing.d.ts +37 -0
- package/dist/server/agent-bridge/pricing.d.ts.map +1 -0
- package/dist/server/agent-bridge/pricing.js +202 -0
- package/dist/server/agent-bridge/rehydrate.d.ts +35 -0
- package/dist/server/agent-bridge/rehydrate.d.ts.map +1 -0
- package/dist/server/agent-bridge/rehydrate.js +122 -0
- package/dist/server/agent-bridge/synthetic-model.d.ts +27 -0
- package/dist/server/agent-bridge/synthetic-model.d.ts.map +1 -0
- package/dist/server/agent-bridge/synthetic-model.js +92 -0
- package/dist/server/agent-bridge.d.ts +11 -1
- package/dist/server/agent-bridge.d.ts.map +1 -1
- package/dist/server/agent-bridge.js +42 -481
- package/dist/server/session-stream/compaction-events.d.ts +13 -0
- package/dist/server/session-stream/compaction-events.d.ts.map +1 -0
- package/dist/server/session-stream/compaction-events.js +32 -0
- package/dist/server/session-stream/history-prune.d.ts +35 -0
- package/dist/server/session-stream/history-prune.d.ts.map +1 -0
- package/dist/server/session-stream/history-prune.js +182 -0
- package/dist/server/session-stream/memory.d.ts +48 -0
- package/dist/server/session-stream/memory.d.ts.map +1 -0
- package/dist/server/session-stream/memory.js +136 -0
- package/dist/server/session-stream/replay-tail.d.ts +4 -0
- package/dist/server/session-stream/replay-tail.d.ts.map +1 -0
- package/dist/server/session-stream/replay-tail.js +39 -0
- package/dist/server/session-stream/turn-events.d.ts +33 -0
- package/dist/server/session-stream/turn-events.d.ts.map +1 -0
- package/dist/server/session-stream/turn-events.js +65 -0
- package/dist/server/session-stream/turn-silence.d.ts +8 -0
- package/dist/server/session-stream/turn-silence.d.ts.map +1 -0
- package/dist/server/session-stream/turn-silence.js +72 -0
- package/dist/server/session-stream.d.ts +137 -36
- package/dist/server/session-stream.d.ts.map +1 -1
- package/dist/server/session-stream.js +18 -509
- package/dist/server/storage/observation-ranking.d.ts +14 -0
- package/dist/server/storage/observation-ranking.d.ts.map +1 -0
- package/dist/server/storage/observation-ranking.js +37 -0
- package/dist/server/storage/preflight.d.ts +20 -0
- package/dist/server/storage/preflight.d.ts.map +1 -0
- package/dist/server/storage/preflight.js +22 -0
- package/dist/server/storage/project-binding.d.ts +5 -0
- package/dist/server/storage/project-binding.d.ts.map +1 -0
- package/dist/server/storage/project-binding.js +32 -0
- package/dist/server/storage/rows.d.ts +104 -0
- package/dist/server/storage/rows.d.ts.map +1 -0
- package/dist/server/storage/rows.js +2 -0
- package/dist/server/storage/schema.d.ts +20 -0
- package/dist/server/storage/schema.d.ts.map +1 -0
- package/dist/server/storage/schema.js +134 -0
- package/dist/server/storage/types.d.ts +66 -0
- package/dist/server/storage/types.d.ts.map +1 -0
- package/dist/server/storage/types.js +1 -0
- package/dist/server/storage.d.ts +7 -94
- package/dist/server/storage.d.ts.map +1 -1
- package/dist/server/storage.js +6 -224
- package/dist/server/wire.d.ts +6 -0
- package/dist/server/wire.d.ts.map +1 -1
- package/package.json +2 -1
- package/dist/sdk/agent-core/harness/agent-harness.d.ts +0 -92
- package/dist/sdk/agent-core/harness/agent-harness.d.ts.map +0 -1
- package/dist/sdk/agent-core/harness/agent-harness.js +0 -899
- package/dist/sdk/agent-core/harness/env/nodejs.d.ts +0 -51
- package/dist/sdk/agent-core/harness/env/nodejs.d.ts.map +0 -1
- package/dist/sdk/agent-core/harness/env/nodejs.js +0 -485
- package/dist/sdk/agent-core/harness/prompt-templates.d.ts +0 -48
- package/dist/sdk/agent-core/harness/prompt-templates.d.ts.map +0 -1
- package/dist/sdk/agent-core/harness/prompt-templates.js +0 -229
- package/dist/sdk/agent-core/harness/session/jsonl-repo.d.ts +0 -26
- package/dist/sdk/agent-core/harness/session/jsonl-repo.d.ts.map +0 -1
- package/dist/sdk/agent-core/harness/session/jsonl-repo.js +0 -100
- package/dist/sdk/agent-core/harness/session/jsonl-storage.d.ts +0 -33
- package/dist/sdk/agent-core/harness/session/jsonl-storage.d.ts.map +0 -1
- package/dist/sdk/agent-core/harness/session/jsonl-storage.js +0 -230
- package/dist/sdk/agent-core/harness/session/memory-repo.d.ts +0 -18
- package/dist/sdk/agent-core/harness/session/memory-repo.d.ts.map +0 -1
- package/dist/sdk/agent-core/harness/session/memory-repo.js +0 -41
- package/dist/sdk/agent-core/harness/session/memory-storage.d.ts +0 -25
- package/dist/sdk/agent-core/harness/session/memory-storage.d.ts.map +0 -1
- package/dist/sdk/agent-core/harness/session/memory-storage.js +0 -113
- package/dist/sdk/agent-core/harness/session/repo-utils.d.ts +0 -11
- package/dist/sdk/agent-core/harness/session/repo-utils.d.ts.map +0 -1
- package/dist/sdk/agent-core/harness/session/repo-utils.js +0 -38
- package/dist/sdk/agent-core/harness/skills.d.ts +0 -44
- package/dist/sdk/agent-core/harness/skills.d.ts.map +0 -1
- package/dist/sdk/agent-core/harness/skills.js +0 -310
- package/dist/sdk/agent-core/harness/utils/shell-output.d.ts +0 -14
- package/dist/sdk/agent-core/harness/utils/shell-output.d.ts.map +0 -1
- package/dist/sdk/agent-core/harness/utils/shell-output.js +0 -125
- package/dist/sdk/agent-core/node.d.ts +0 -3
- package/dist/sdk/agent-core/node.d.ts.map +0 -1
- package/dist/sdk/agent-core/node.js +0 -2
- package/dist/sdk/agent-core/proxy.d.ts +0 -69
- package/dist/sdk/agent-core/proxy.d.ts.map +0 -1
- package/dist/sdk/agent-core/proxy.js +0 -297
package/dist/agent/index.d.ts
CHANGED
|
@@ -22,13 +22,17 @@
|
|
|
22
22
|
* - Tool filtering (only the tools specified in agent config)
|
|
23
23
|
* - Model selection (session model preferred, agent-configured as fallback)
|
|
24
24
|
* - Signal propagation (abort passthrough)
|
|
25
|
-
* - Access to observational memory via the recall
|
|
25
|
+
* - Access to observational memory via the `recall` and
|
|
26
|
+
* `write_project_observation` tools, which run against a parent-session
|
|
27
|
+
* point-in-time snapshot (branch + session id); other observation tools
|
|
28
|
+
* (`share_project_observation`, `receive_agent_observations`,
|
|
29
|
+
* `compact_context`, `subagent`) remain excluded
|
|
26
30
|
*/
|
|
27
31
|
import type { AgentTool } from "../sdk/agent-core/index.js";
|
|
28
32
|
import { type ExtensionAPI, type ExtensionContext } from "../sdk/coding-agent/index.js";
|
|
29
33
|
import { type AgentConfig } from "./agents.js";
|
|
30
34
|
import type { ServerEvent } from "../server/wire.ts";
|
|
31
|
-
import type {
|
|
35
|
+
import type { ReadonlySessionManager } from "../sdk/coding-agent/core/session-manager.js";
|
|
32
36
|
/**
|
|
33
37
|
* Build the system prompt for a subagent session.
|
|
34
38
|
*
|
|
@@ -44,7 +48,7 @@ export declare function buildSubagentSystemPrompt(baseSystemPrompt: string | und
|
|
|
44
48
|
* Give subagents a point-in-time branch view without exposing the live parent
|
|
45
49
|
* SessionManager. Each getBranch call returns fresh clones of the snapshot.
|
|
46
50
|
*/
|
|
47
|
-
export declare function createSubagentSessionManagerSnapshot(sessionManager: ExtensionContext["sessionManager"]): Pick<
|
|
51
|
+
export declare function createSubagentSessionManagerSnapshot(sessionManager: ExtensionContext["sessionManager"]): Pick<ReadonlySessionManager, "getBranch" | "getSessionId">;
|
|
48
52
|
export declare function resolveSubagentTools(cwd: string, ext: ExtensionAPI, ctx: ExtensionContext): AgentTool[];
|
|
49
53
|
export default function subagentExtension(ext: ExtensionAPI, opts?: {
|
|
50
54
|
disabledAgents?: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAIX,SAAS,EAET,MAAM,4BAA4B,CAAC;AAUpC,OAAO,EACN,KAAK,YAAY,EACjB,KAAK,gBAAgB,EAErB,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EACN,KAAK,WAAW,EAKhB,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAQrD,OAAO,KAAK,EAAE,sBAAsB,EAAgB,MAAM,6CAA6C,CAAC;AAuGxG;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACxC,gBAAgB,EAAE,MAAM,GAAG,SAAS,EACpC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,cAAc,GAAG,OAAO,GAAG,QAAQ,CAAC,GACpF,MAAM,CAYR;AA0JD;;;GAGG;AACH,wBAAgB,oCAAoC,CACnD,cAAc,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,GAChD,IAAI,CAAC,sBAAsB,EAAE,WAAW,GAAG,cAAc,CAAC,CAe5D;AA6BD,wBAAgB,oBAAoB,CACnC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,YAAY,EACjB,GAAG,EAAE,gBAAgB,GACnB,SAAS,EAAE,CAwCb;AAycD,MAAM,CAAC,OAAO,UAAU,iBAAiB,CACxC,GAAG,EAAE,YAAY,EACjB,IAAI,CAAC,EAAE;IACN,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB,GACC,IAAI,CAgaN"}
|
package/dist/agent/index.js
CHANGED
|
@@ -22,7 +22,11 @@
|
|
|
22
22
|
* - Tool filtering (only the tools specified in agent config)
|
|
23
23
|
* - Model selection (session model preferred, agent-configured as fallback)
|
|
24
24
|
* - Signal propagation (abort passthrough)
|
|
25
|
-
* - Access to observational memory via the recall
|
|
25
|
+
* - Access to observational memory via the `recall` and
|
|
26
|
+
* `write_project_observation` tools, which run against a parent-session
|
|
27
|
+
* point-in-time snapshot (branch + session id); other observation tools
|
|
28
|
+
* (`share_project_observation`, `receive_agent_observations`,
|
|
29
|
+
* `compact_context`, `subagent`) remain excluded
|
|
26
30
|
*/
|
|
27
31
|
import { agentLoop } from "../sdk/agent-core/index.js";
|
|
28
32
|
import { buildIsolatedRequestTimePrunedMessagesResult, COMPACT_CONTEXT_TOOL_NAME, } from "../memory/tools/compact-context.js";
|
|
@@ -40,6 +44,7 @@ import { wrapToolDefinition } from "../sdk/coding-agent/core/tools/tool-definiti
|
|
|
40
44
|
import { RECALL_OBSERVATION_TOOL_NAME } from "../memory/tools/recall-observation.js";
|
|
41
45
|
import { RECEIVE_AGENT_OBSERVATIONS_TOOL_NAME } from "../memory/tools/receive-agent-observations.js";
|
|
42
46
|
import { SHARE_PROJECT_OBSERVATION_TOOL_NAME } from "../memory/tools/share-project-observation.js";
|
|
47
|
+
import { WRITE_PROJECT_OBSERVATION_TOOL_NAME } from "../memory/tools/write-project-observation.js";
|
|
43
48
|
import { compressSubagentToolResult } from "../memory/tool-output-compressor.js";
|
|
44
49
|
// ---------------------------------------------------------------------------
|
|
45
50
|
// Constants
|
|
@@ -230,8 +235,18 @@ function cloneSessionEntry(entry) {
|
|
|
230
235
|
*/
|
|
231
236
|
export function createSubagentSessionManagerSnapshot(sessionManager) {
|
|
232
237
|
const snapshot = sessionManager.getBranch().map(cloneSessionEntry);
|
|
238
|
+
// Optional call tolerates minimal branch-only snapshots in tests; a
|
|
239
|
+
// missing id falls through to the tools' `no_session` handling.
|
|
240
|
+
const sessionId = sessionManager.getSessionId?.();
|
|
233
241
|
return {
|
|
234
242
|
getBranch: () => snapshot.map(cloneSessionEntry),
|
|
243
|
+
// Captured eagerly so the session id and the branch snapshot come
|
|
244
|
+
// from the same point in time. fork/newSession mutate the live
|
|
245
|
+
// SessionManager's sessionId in place, so a lazy read could diverge
|
|
246
|
+
// from the point-in-time branch on a mid-run fork. Subagent
|
|
247
|
+
// observations must be attributed to the parent session id at
|
|
248
|
+
// snapshot creation, same branch semantics as `recall`.
|
|
249
|
+
getSessionId: () => sessionId,
|
|
235
250
|
};
|
|
236
251
|
}
|
|
237
252
|
/**
|
|
@@ -251,14 +266,27 @@ const SUBAGENT_EXCLUDED_TOOL_NAMES = new Set([
|
|
|
251
266
|
RECEIVE_AGENT_OBSERVATIONS_TOOL_NAME,
|
|
252
267
|
SHARE_PROJECT_OBSERVATION_TOOL_NAME,
|
|
253
268
|
]);
|
|
269
|
+
/**
|
|
270
|
+
* Extension tools that run with the parent session's point-in-time branch
|
|
271
|
+
* snapshot instead of the bare `{ cwd, getSystemPrompt }` isolated context.
|
|
272
|
+
*/
|
|
273
|
+
const SUBAGENT_SESSION_SNAPSHOT_TOOL_NAMES = new Set([
|
|
274
|
+
RECALL_OBSERVATION_TOOL_NAME,
|
|
275
|
+
WRITE_PROJECT_OBSERVATION_TOOL_NAME,
|
|
276
|
+
]);
|
|
254
277
|
export function resolveSubagentTools(cwd, ext, ctx) {
|
|
255
278
|
// Subagents receive every tool registered on the primary agent. Built-in
|
|
256
279
|
// tools are created fresh with the subagent's isolated cwd/jobs, and
|
|
257
|
-
// extension-registered tools are wrapped with
|
|
258
|
-
//
|
|
259
|
-
//
|
|
280
|
+
// extension-registered tools are wrapped with a `SubagentToolContext`:
|
|
281
|
+
// always `cwd` + `getSystemPrompt`, plus a point-in-time parent-session
|
|
282
|
+
// branch snapshot for the observation tools that need branch/session
|
|
283
|
+
// semantics. Everything else (ui, modelRegistry, live sessionManager) is
|
|
284
|
+
// absent at runtime, so handlers must guard those members.
|
|
260
285
|
const tools = [];
|
|
261
286
|
const jobs = new BashJobRegistry();
|
|
287
|
+
// One shared snapshot per invocation so all snapshot-routed tools observe
|
|
288
|
+
// the same parent-session epoch (branch + session id).
|
|
289
|
+
const sharedSnapshot = createSubagentSessionManagerSnapshot(ctx.sessionManager);
|
|
262
290
|
for (const toolInfo of ext.getAllTools()) {
|
|
263
291
|
const name = toolInfo.name;
|
|
264
292
|
if (SUBAGENT_EXCLUDED_TOOL_NAMES.has(name))
|
|
@@ -278,11 +306,10 @@ export function resolveSubagentTools(cwd, ext, ctx) {
|
|
|
278
306
|
const toolDef = ext.getToolDefinition(name);
|
|
279
307
|
if (!toolDef)
|
|
280
308
|
continue;
|
|
281
|
-
const isolatedContext = name
|
|
282
|
-
? { cwd, sessionManager:
|
|
309
|
+
const isolatedContext = SUBAGENT_SESSION_SNAPSHOT_TOOL_NAMES.has(name)
|
|
310
|
+
? { cwd, sessionManager: sharedSnapshot, getSystemPrompt: ctx.getSystemPrompt }
|
|
283
311
|
: { cwd, getSystemPrompt: ctx.getSystemPrompt };
|
|
284
|
-
|
|
285
|
-
tools.push(wrapToolDefinition(toolDef, () => isolatedContextWithNoParent));
|
|
312
|
+
tools.push(wrapToolDefinition(toolDef, () => isolatedContext));
|
|
286
313
|
}
|
|
287
314
|
return tools;
|
|
288
315
|
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Aexol-backend MCP client bootstrap for native extensions.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `aexol-mcp.ts` (behavior-preserving: identical config/
|
|
5
|
+
* token resolution, identical tools/list bootstrap and OAuth re-auth flow,
|
|
6
|
+
* identical diagnostic strings) so other extensions that talk to the same
|
|
7
|
+
* JSON-RPC MCP backend can reuse one chunk of logic.
|
|
8
|
+
*
|
|
9
|
+
* Responsibilities:
|
|
10
|
+
* 1. Reads ~/.spectral/config.json (written by `spectral login`).
|
|
11
|
+
* 2. Resolves the effective API URL: SPECTRAL_MCP_URL > stored > default.
|
|
12
|
+
* 3. Resolves the auth token: teamApiKey > userJwt.
|
|
13
|
+
* 4. Instantiates AexolMcpClient and performs the initial tools/list call.
|
|
14
|
+
* 5. On 401/403 from tools/list, runs the OAuth re-auth flow once and
|
|
15
|
+
* retries the catalog fetch with a fresh token.
|
|
16
|
+
*
|
|
17
|
+
* Failure modes are non-fatal: instead of throwing, the factory returns a
|
|
18
|
+
* discriminated outcome. Transient diagnostics are streamed through an
|
|
19
|
+
* optional `warn` sink so each caller can render them with its own log
|
|
20
|
+
* prefix; the terminal failure reason travels in the returned outcome.
|
|
21
|
+
*/
|
|
22
|
+
import { AexolMcpClient, type McpContentItem, type McpTool } from "../mcp-client.js";
|
|
23
|
+
import { ensureAuthenticated } from "../auth-helper.js";
|
|
24
|
+
/** Sink for transient bootstrap diagnostics (line without prefix/newline). */
|
|
25
|
+
export type BootstrapWarn = (line: string) => void;
|
|
26
|
+
export interface CreateAexolBackendClientOptions {
|
|
27
|
+
/**
|
|
28
|
+
* Receives transient diagnostics (tools/list failure, re-auth progress).
|
|
29
|
+
* Defaults to writing `[aexol-backend-client] <line>` to stderr — extension
|
|
30
|
+
* callers should pass a sink with their own prefix.
|
|
31
|
+
*/
|
|
32
|
+
warn?: BootstrapWarn;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Successfully-bootstrapped client handle.
|
|
36
|
+
*
|
|
37
|
+
* NOTE: if the initial tools/list hit a 401/403 and re-auth succeeded, `tools`
|
|
38
|
+
* comes from a retry client while `client` is still the initially-created one.
|
|
39
|
+
* This intentionally mirrors the original aexol-mcp.ts behavior (call-time
|
|
40
|
+
* tools/call kept using the boot-time client).
|
|
41
|
+
*/
|
|
42
|
+
export interface AexolBackendClient {
|
|
43
|
+
/** Ready-to-use JSON-RPC MCP client for tools/call (and tools/list). */
|
|
44
|
+
client: AexolMcpClient;
|
|
45
|
+
/** Effective backend URL (SPECTRAL_MCP_URL > stored config > default). */
|
|
46
|
+
apiUrl: string;
|
|
47
|
+
/** Tool catalog returned by the initial tools/list call. */
|
|
48
|
+
tools: McpTool[];
|
|
49
|
+
/**
|
|
50
|
+
* Re-auth helper (OAuth browser flow) for later 401/403 recovery; see
|
|
51
|
+
* `../auth-helper.js` for semantics (no-op failure in non-UI sessions).
|
|
52
|
+
* The caller owns rebuilding the client from the returned fresh config.
|
|
53
|
+
*/
|
|
54
|
+
ensureAuthenticated: typeof ensureAuthenticated;
|
|
55
|
+
/** Render backend tool result content into one model-readable string. */
|
|
56
|
+
renderContentToString: typeof renderContentToString;
|
|
57
|
+
}
|
|
58
|
+
export type AexolBackendBootstrapFailureReason = "no-config" | "no-token" | "catalog-failed";
|
|
59
|
+
export interface AexolBackendBootstrapFailure {
|
|
60
|
+
ok: false;
|
|
61
|
+
reason: AexolBackendBootstrapFailureReason;
|
|
62
|
+
/** Fully-formed diagnostic, ready to be prefixed and written by the caller. */
|
|
63
|
+
message: string;
|
|
64
|
+
}
|
|
65
|
+
export type AexolBackendBootstrap = ({
|
|
66
|
+
ok: true;
|
|
67
|
+
} & AexolBackendClient) | AexolBackendBootstrapFailure;
|
|
68
|
+
/**
|
|
69
|
+
* Render a backend tool result into a single string for ext.
|
|
70
|
+
*
|
|
71
|
+
* The Aexol backend wraps results as `{ content: [{ type: "json", json: ... }] }`
|
|
72
|
+
* but may also send `{ type: "text", text: ... }`. We pick the first content
|
|
73
|
+
* item, prefer JSON when present (pretty-print so the model can read it),
|
|
74
|
+
* fall back to text, and last-resort stringify the whole content array.
|
|
75
|
+
*/
|
|
76
|
+
export declare function renderContentToString(content: McpContentItem[]): string;
|
|
77
|
+
/**
|
|
78
|
+
* Bootstrap a connection to the Aexol backend MCP endpoint.
|
|
79
|
+
*
|
|
80
|
+
* Non-fatal by design: returns a failure outcome (never throws) when the
|
|
81
|
+
* config or token is missing, or when the initial tools/list call cannot be
|
|
82
|
+
* completed even after the OAuth re-auth attempt.
|
|
83
|
+
*/
|
|
84
|
+
export declare function createAexolBackendClient(options?: CreateAexolBackendClientOptions): Promise<AexolBackendBootstrap>;
|
|
85
|
+
//# sourceMappingURL=aexol-backend-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aexol-backend-client.d.ts","sourceRoot":"","sources":["../../src/extensions/aexol-backend-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EACL,cAAc,EAEd,KAAK,cAAc,EACnB,KAAK,OAAO,EACb,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,8EAA8E;AAC9E,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;AAEnD,MAAM,WAAW,+BAA+B;IAC9C;;;;OAIG;IACH,IAAI,CAAC,EAAE,aAAa,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,wEAAwE;IACxE,MAAM,EAAE,cAAc,CAAC;IACvB,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB;;;;OAIG;IACH,mBAAmB,EAAE,OAAO,mBAAmB,CAAC;IAChD,yEAAyE;IACzE,qBAAqB,EAAE,OAAO,qBAAqB,CAAC;CACrD;AAED,MAAM,MAAM,kCAAkC,GAC1C,WAAW,GACX,UAAU,GACV,gBAAgB,CAAC;AAErB,MAAM,WAAW,4BAA4B;IAC3C,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,kCAAkC,CAAC;IAC3C,+EAA+E;IAC/E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,qBAAqB,GAC7B,CAAC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG,kBAAkB,CAAC,GACnC,4BAA4B,CAAC;AAEjC;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,MAAM,CA+BvE;AAED;;;;;;GAMG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,GAAE,+BAAoC,GAC5C,OAAO,CAAC,qBAAqB,CAAC,CAmFhC"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Aexol-backend MCP client bootstrap for native extensions.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `aexol-mcp.ts` (behavior-preserving: identical config/
|
|
5
|
+
* token resolution, identical tools/list bootstrap and OAuth re-auth flow,
|
|
6
|
+
* identical diagnostic strings) so other extensions that talk to the same
|
|
7
|
+
* JSON-RPC MCP backend can reuse one chunk of logic.
|
|
8
|
+
*
|
|
9
|
+
* Responsibilities:
|
|
10
|
+
* 1. Reads ~/.spectral/config.json (written by `spectral login`).
|
|
11
|
+
* 2. Resolves the effective API URL: SPECTRAL_MCP_URL > stored > default.
|
|
12
|
+
* 3. Resolves the auth token: teamApiKey > userJwt.
|
|
13
|
+
* 4. Instantiates AexolMcpClient and performs the initial tools/list call.
|
|
14
|
+
* 5. On 401/403 from tools/list, runs the OAuth re-auth flow once and
|
|
15
|
+
* retries the catalog fetch with a fresh token.
|
|
16
|
+
*
|
|
17
|
+
* Failure modes are non-fatal: instead of throwing, the factory returns a
|
|
18
|
+
* discriminated outcome. Transient diagnostics are streamed through an
|
|
19
|
+
* optional `warn` sink so each caller can render them with its own log
|
|
20
|
+
* prefix; the terminal failure reason travels in the returned outcome.
|
|
21
|
+
*/
|
|
22
|
+
import { AexolMcpClient, AexolMcpError, } from "../mcp-client.js";
|
|
23
|
+
import { getApiUrl, getConfigFile, readConfig } from "../config.js";
|
|
24
|
+
import { ensureAuthenticated } from "../auth-helper.js";
|
|
25
|
+
/**
|
|
26
|
+
* Render a backend tool result into a single string for ext.
|
|
27
|
+
*
|
|
28
|
+
* The Aexol backend wraps results as `{ content: [{ type: "json", json: ... }] }`
|
|
29
|
+
* but may also send `{ type: "text", text: ... }`. We pick the first content
|
|
30
|
+
* item, prefer JSON when present (pretty-print so the model can read it),
|
|
31
|
+
* fall back to text, and last-resort stringify the whole content array.
|
|
32
|
+
*/
|
|
33
|
+
export function renderContentToString(content) {
|
|
34
|
+
if (content.length === 0)
|
|
35
|
+
return "";
|
|
36
|
+
const first = content[0];
|
|
37
|
+
if (first.json !== undefined) {
|
|
38
|
+
try {
|
|
39
|
+
return JSON.stringify(first.json, null, 2);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return String(first.json);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (typeof first.text === "string")
|
|
46
|
+
return first.text;
|
|
47
|
+
// For image/audio/binary content types, return a metadata placeholder
|
|
48
|
+
// instead of serializing the raw base64 data into the model context.
|
|
49
|
+
if (first.type === "image" || first.type === "audio") {
|
|
50
|
+
const mimeType = typeof first.mimeType === "string" ? first.mimeType : first.type;
|
|
51
|
+
const dataLen = typeof first.data === "string" ? first.data.length : 0;
|
|
52
|
+
return `[${first.type}: ${mimeType}${dataLen ? `, ${dataLen.toLocaleString()} bytes base64` : ""}]`;
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
// Strip large binary fields from serialization to prevent context overflow.
|
|
56
|
+
const safe = content.map((c) => {
|
|
57
|
+
const copy = { ...c };
|
|
58
|
+
if ("data" in copy && typeof copy.data === "string" && copy.data.length > 200) {
|
|
59
|
+
copy.data = `[${copy.data.length.toLocaleString()} bytes base64 omitted]`;
|
|
60
|
+
}
|
|
61
|
+
return copy;
|
|
62
|
+
});
|
|
63
|
+
return JSON.stringify(safe, null, 2);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return String(content);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Bootstrap a connection to the Aexol backend MCP endpoint.
|
|
71
|
+
*
|
|
72
|
+
* Non-fatal by design: returns a failure outcome (never throws) when the
|
|
73
|
+
* config or token is missing, or when the initial tools/list call cannot be
|
|
74
|
+
* completed even after the OAuth re-auth attempt.
|
|
75
|
+
*/
|
|
76
|
+
export async function createAexolBackendClient(options = {}) {
|
|
77
|
+
const warn = options.warn ??
|
|
78
|
+
((line) => process.stderr.write(`[aexol-backend-client] ${line}\n`));
|
|
79
|
+
const cfg = await readConfig();
|
|
80
|
+
if (!cfg) {
|
|
81
|
+
// Pre-flight in cli.ts should have caught this. Returning a diagnostic is
|
|
82
|
+
// enough; the caller decides how (or whether) to surface it.
|
|
83
|
+
return {
|
|
84
|
+
ok: false,
|
|
85
|
+
reason: "no-config",
|
|
86
|
+
message: `No config found at ${getConfigFile()}; Aexol tools disabled. Run \`spectral login\`.`,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
const apiUrl = getApiUrl(cfg.apiUrl);
|
|
90
|
+
const token = cfg.teamApiKey || cfg.userJwt || "";
|
|
91
|
+
if (!token) {
|
|
92
|
+
return {
|
|
93
|
+
ok: false,
|
|
94
|
+
reason: "no-token",
|
|
95
|
+
message: `No auth token in ${getConfigFile()}; Aexol tools disabled. Run \`spectral login\`.`,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
const client = new AexolMcpClient(apiUrl, token);
|
|
99
|
+
let tools;
|
|
100
|
+
try {
|
|
101
|
+
tools = await client.listTools();
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
const msg = err instanceof AexolMcpError || err instanceof Error ? err.message : String(err);
|
|
105
|
+
warn(`Failed to fetch tool catalog from ${apiUrl}: ${msg}`);
|
|
106
|
+
// Attempt auto-reauth via OAuth browser flow on auth errors
|
|
107
|
+
if (err instanceof AexolMcpError && (err.status === 401 || err.status === 403)) {
|
|
108
|
+
const authResult = await ensureAuthenticated();
|
|
109
|
+
if (authResult.ok && authResult.config) {
|
|
110
|
+
const newToken = authResult.config.teamApiKey || authResult.config.userJwt || "";
|
|
111
|
+
if (newToken && newToken !== token) {
|
|
112
|
+
warn("Re-authenticated — retrying tool catalog fetch...");
|
|
113
|
+
const newClient = new AexolMcpClient(apiUrl, newToken);
|
|
114
|
+
try {
|
|
115
|
+
tools = await newClient.listTools();
|
|
116
|
+
}
|
|
117
|
+
catch (retryErr) {
|
|
118
|
+
const retryMsg = retryErr instanceof Error ? retryErr.message : String(retryErr);
|
|
119
|
+
warn(`Retry also failed: ${retryMsg}`);
|
|
120
|
+
return {
|
|
121
|
+
ok: false,
|
|
122
|
+
reason: "catalog-failed",
|
|
123
|
+
message: "Continuing without Aexol tools.",
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
return {
|
|
129
|
+
ok: false,
|
|
130
|
+
reason: "catalog-failed",
|
|
131
|
+
message: "Re-authentication did not produce a new token. Continuing without Aexol tools.",
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
return {
|
|
137
|
+
ok: false,
|
|
138
|
+
reason: "catalog-failed",
|
|
139
|
+
message: `Re-authentication failed: ${authResult.reason ?? "unknown"}. Continuing without Aexol tools.`,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
return {
|
|
145
|
+
ok: false,
|
|
146
|
+
reason: "catalog-failed",
|
|
147
|
+
message: "Continuing without Aexol tools.",
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
ok: true,
|
|
153
|
+
client,
|
|
154
|
+
apiUrl,
|
|
155
|
+
tools,
|
|
156
|
+
ensureAuthenticated,
|
|
157
|
+
renderContentToString,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
@@ -2,13 +2,17 @@
|
|
|
2
2
|
* Aexol MCP spectral extension.
|
|
3
3
|
*
|
|
4
4
|
* Loaded by the spectral wrapper via `--extension <abs-path>`. On startup it:
|
|
5
|
-
* 1.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* 1. Boots the Aexol backend MCP client via the shared
|
|
6
|
+
* `createAexolBackendClient()` factory in ./aexol-backend-client.ts
|
|
7
|
+
* (config load, token resolution, initial tools/list call, OAuth
|
|
8
|
+
* re-auth on 401/403).
|
|
9
|
+
* 2. Reads the local Studio binding (`.aexol/aexol.jsonc`) so remote tools
|
|
10
|
+
* auto-inherit `teamId` / `projectId`; the binding itself is managed from
|
|
11
|
+
* agent via the `local_bind_project` / `local_unbind_project` tools
|
|
12
|
+
* registered at startup (see step 4).
|
|
13
|
+
* 3. Registers every returned remote tool through ext.registerTool() so the
|
|
10
14
|
* model can call them like built-in tools.
|
|
11
|
-
*
|
|
15
|
+
* 4. Registers local binding-management tools (`local_bind_project`,
|
|
12
16
|
* `local_unbind_project`, `local_get_binding`) so users can bind a
|
|
13
17
|
* directory to an Aexol Studio project from within the agent.
|
|
14
18
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aexol-mcp.d.ts","sourceRoot":"","sources":["../../src/extensions/aexol-mcp.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"aexol-mcp.d.ts","sourceRoot":"","sources":["../../src/extensions/aexol-mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAoC,MAAM,8BAA8B,CAAC;AAqHnG,wBAA8B,iBAAiB,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA0PhF"}
|
|
@@ -2,13 +2,17 @@
|
|
|
2
2
|
* Aexol MCP spectral extension.
|
|
3
3
|
*
|
|
4
4
|
* Loaded by the spectral wrapper via `--extension <abs-path>`. On startup it:
|
|
5
|
-
* 1.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* 1. Boots the Aexol backend MCP client via the shared
|
|
6
|
+
* `createAexolBackendClient()` factory in ./aexol-backend-client.ts
|
|
7
|
+
* (config load, token resolution, initial tools/list call, OAuth
|
|
8
|
+
* re-auth on 401/403).
|
|
9
|
+
* 2. Reads the local Studio binding (`.aexol/aexol.jsonc`) so remote tools
|
|
10
|
+
* auto-inherit `teamId` / `projectId`; the binding itself is managed from
|
|
11
|
+
* agent via the `local_bind_project` / `local_unbind_project` tools
|
|
12
|
+
* registered at startup (see step 4).
|
|
13
|
+
* 3. Registers every returned remote tool through ext.registerTool() so the
|
|
10
14
|
* model can call them like built-in tools.
|
|
11
|
-
*
|
|
15
|
+
* 4. Registers local binding-management tools (`local_bind_project`,
|
|
12
16
|
* `local_unbind_project`, `local_get_binding`) so users can bind a
|
|
13
17
|
* directory to an Aexol Studio project from within the agent.
|
|
14
18
|
*
|
|
@@ -20,55 +24,10 @@
|
|
|
20
24
|
* backend is unreachable we log a warning and return, leaving spectral to start
|
|
21
25
|
* without Aexol tools rather than crashing the whole agent.
|
|
22
26
|
*/
|
|
23
|
-
import {
|
|
24
|
-
import { AexolMcpClient, AexolMcpError } from "../mcp-client.js";
|
|
27
|
+
import { createAexolBackendClient, renderContentToString } from "./aexol-backend-client.js";
|
|
25
28
|
import { stat } from "node:fs/promises";
|
|
26
29
|
import { join } from "node:path";
|
|
27
30
|
import { readStudioBinding, writeStudioBinding, deleteStudioBinding, } from "../studio-binding.js";
|
|
28
|
-
/**
|
|
29
|
-
* Render a backend tool result into a single string for ext.
|
|
30
|
-
*
|
|
31
|
-
* The Aexol backend wraps results as `{ content: [{ type: "json", json: ... }] }`
|
|
32
|
-
* but may also send `{ type: "text", text: ... }`. We pick the first content
|
|
33
|
-
* item, prefer JSON when present (pretty-print so the model can read it),
|
|
34
|
-
* fall back to text, and last-resort stringify the whole content array.
|
|
35
|
-
*/
|
|
36
|
-
function renderContentToString(content) {
|
|
37
|
-
if (content.length === 0)
|
|
38
|
-
return "";
|
|
39
|
-
const first = content[0];
|
|
40
|
-
if (first.json !== undefined) {
|
|
41
|
-
try {
|
|
42
|
-
return JSON.stringify(first.json, null, 2);
|
|
43
|
-
}
|
|
44
|
-
catch {
|
|
45
|
-
return String(first.json);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
if (typeof first.text === "string")
|
|
49
|
-
return first.text;
|
|
50
|
-
// For image/audio/binary content types, return a metadata placeholder
|
|
51
|
-
// instead of serializing the raw base64 data into the model context.
|
|
52
|
-
if (first.type === "image" || first.type === "audio") {
|
|
53
|
-
const mimeType = typeof first.mimeType === "string" ? first.mimeType : first.type;
|
|
54
|
-
const dataLen = typeof first.data === "string" ? first.data.length : 0;
|
|
55
|
-
return `[${first.type}: ${mimeType}${dataLen ? `, ${dataLen.toLocaleString()} bytes base64` : ""}]`;
|
|
56
|
-
}
|
|
57
|
-
try {
|
|
58
|
-
// Strip large binary fields from serialization to prevent context overflow.
|
|
59
|
-
const safe = content.map((c) => {
|
|
60
|
-
const copy = { ...c };
|
|
61
|
-
if ("data" in copy && typeof copy.data === "string" && copy.data.length > 200) {
|
|
62
|
-
copy.data = `[${copy.data.length.toLocaleString()} bytes base64 omitted]`;
|
|
63
|
-
}
|
|
64
|
-
return copy;
|
|
65
|
-
});
|
|
66
|
-
return JSON.stringify(safe, null, 2);
|
|
67
|
-
}
|
|
68
|
-
catch {
|
|
69
|
-
return String(content);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
31
|
/** Build a one-line human label from a tool name like "remote_cloud_search". */
|
|
73
32
|
function toLabel(name) {
|
|
74
33
|
return name
|
|
@@ -127,8 +86,6 @@ async function refreshBindingForCwd(cwd) {
|
|
|
127
86
|
*/
|
|
128
87
|
const MODEL_INJECTING_TOOLS = new Set([
|
|
129
88
|
"remote_start_from",
|
|
130
|
-
"remote_start_inference",
|
|
131
|
-
"remote_refine_inference_artifact",
|
|
132
89
|
"remote_refine_from_task",
|
|
133
90
|
"remote_refine_aexol_content",
|
|
134
91
|
]);
|
|
@@ -163,19 +120,18 @@ function augmentParams(toolName, params, ctx, binding) {
|
|
|
163
120
|
return { params: augmented };
|
|
164
121
|
}
|
|
165
122
|
export default async function aexolMcpExtension(ext) {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
process.stderr.write(`[aexol-mcp] No auth token in ${getConfigFile()}; Aexol tools disabled. Run \`spectral login\`.\n`);
|
|
123
|
+
// Shared bootstrap (config load, token resolution, client + initial
|
|
124
|
+
// tools/list call, OAuth re-auth on 401/403) lives in
|
|
125
|
+
// ./aexol-backend-client.ts. Diagnostics stream through this sink so the
|
|
126
|
+
// extension's stderr output is unchanged.
|
|
127
|
+
const boot = await createAexolBackendClient({
|
|
128
|
+
warn: (line) => process.stderr.write(`[aexol-mcp] ${line}\n`),
|
|
129
|
+
});
|
|
130
|
+
if (!boot.ok) {
|
|
131
|
+
process.stderr.write(`[aexol-mcp] ${boot.message}\n`);
|
|
176
132
|
return;
|
|
177
133
|
}
|
|
178
|
-
const client
|
|
134
|
+
const { client, apiUrl, tools } = boot;
|
|
179
135
|
// ---- Load local Studio binding on session start --------------------------
|
|
180
136
|
ext.on("session_start", async (_event, ctx) => {
|
|
181
137
|
try {
|
|
@@ -193,47 +149,6 @@ export default async function aexolMcpExtension(ext) {
|
|
|
193
149
|
// Non-fatal — remote tools still work with explicit teamId/projectId.
|
|
194
150
|
}
|
|
195
151
|
});
|
|
196
|
-
let tools;
|
|
197
|
-
try {
|
|
198
|
-
tools = await client.listTools();
|
|
199
|
-
}
|
|
200
|
-
catch (err) {
|
|
201
|
-
const msg = err instanceof AexolMcpError || err instanceof Error ? err.message : String(err);
|
|
202
|
-
process.stderr.write(`[aexol-mcp] Failed to fetch tool catalog from ${apiUrl}: ${msg}\n`);
|
|
203
|
-
// Attempt auto-reauth via OAuth browser flow on auth errors
|
|
204
|
-
if (err instanceof AexolMcpError && (err.status === 401 || err.status === 403)) {
|
|
205
|
-
const { ensureAuthenticated } = await import("../auth-helper.js");
|
|
206
|
-
const authResult = await ensureAuthenticated();
|
|
207
|
-
if (authResult.ok && authResult.config) {
|
|
208
|
-
const newToken = authResult.config.teamApiKey || authResult.config.userJwt || "";
|
|
209
|
-
if (newToken && newToken !== token) {
|
|
210
|
-
process.stderr.write("[aexol-mcp] Re-authenticated — retrying tool catalog fetch...\n");
|
|
211
|
-
const newClient = new AexolMcpClient(apiUrl, newToken);
|
|
212
|
-
try {
|
|
213
|
-
tools = await newClient.listTools();
|
|
214
|
-
}
|
|
215
|
-
catch (retryErr) {
|
|
216
|
-
const retryMsg = retryErr instanceof Error ? retryErr.message : String(retryErr);
|
|
217
|
-
process.stderr.write(`[aexol-mcp] Retry also failed: ${retryMsg}\n`);
|
|
218
|
-
process.stderr.write("[aexol-mcp] Continuing without Aexol tools.\n");
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
else {
|
|
223
|
-
process.stderr.write("[aexol-mcp] Re-authentication did not produce a new token. Continuing without Aexol tools.\n");
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
else {
|
|
228
|
-
process.stderr.write(`[aexol-mcp] Re-authentication failed: ${authResult.reason ?? "unknown"}. Continuing without Aexol tools.\n`);
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
else {
|
|
233
|
-
process.stderr.write("[aexol-mcp] Continuing without Aexol tools.\n");
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
152
|
let registered = 0;
|
|
238
153
|
for (const tool of tools) {
|
|
239
154
|
// Defensive defaults: an empty-object schema is valid JSON Schema and
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backend refine draft adapter for the logic-trace extension.
|
|
3
|
+
*
|
|
4
|
+
* Implements the `LogicTraceDraftRunner` seam (see logic-trace.ts) on top of
|
|
5
|
+
* the backend from/refine pipeline instead of the local LLM agent loop:
|
|
6
|
+
* 1. `remote_refine_aexol_content` — submits the CURRENT remote logic.aexol
|
|
7
|
+
* content plus a compressed merge instruction prompt (full-spec rewrite,
|
|
8
|
+
* "merge, never append-only", grammar + leak rules) and the serialized
|
|
9
|
+
* recent-activity delta. Answers `{ ok, task: { id, status } }`. The
|
|
10
|
+
* session model is intentionally NOT sent — the backend resolves the
|
|
11
|
+
* team's default model.
|
|
12
|
+
* 2. `remote_get_from_task` — polled locally (NOT via remote_wait_task,
|
|
13
|
+
* whose internal wait exceeds the MCP client's 30s fetch abort) until a
|
|
14
|
+
* terminal status or the configured timeout. Answers
|
|
15
|
+
* `{ ok, task: { id, status, aexolCode, … } }`.
|
|
16
|
+
* 3. COMPLETED with an `aexolCode` → `{ submitted: { content, changed } }`
|
|
17
|
+
* where `changed` is a plain string comparison against the current
|
|
18
|
+
* remote content.
|
|
19
|
+
* 4. Anything else (FAILED / CANCELLED / poll timeout / missing content /
|
|
20
|
+
* any error) → `{}` — the empty outcome is the seam's fallback signal
|
|
21
|
+
* and attemptLogicTraceSync retries with the local draft runner. The
|
|
22
|
+
* adapter NEVER throws past the seam.
|
|
23
|
+
*
|
|
24
|
+
* This file only adapts the draft STEP; the downstream sanitize → parser
|
|
25
|
+
* gate → hash dedupe → push flow stays in logic-trace.ts untouched.
|
|
26
|
+
*/
|
|
27
|
+
import { AexolMcpClient } from "../mcp-client.js";
|
|
28
|
+
import type { LogicTraceDraftRunner } from "./logic-trace.js";
|
|
29
|
+
/** Default cadence between `remote_get_from_task` polls. */
|
|
30
|
+
export declare const DEFAULT_DRAFT_BACKEND_POLL_INTERVAL_MS = 2000;
|
|
31
|
+
/** Default total wait for a refine task to reach a terminal status. */
|
|
32
|
+
export declare const DEFAULT_DRAFT_BACKEND_POLL_TIMEOUT_MS = 120000;
|
|
33
|
+
export interface BackendRefineDraftRunnerOptions {
|
|
34
|
+
/** Bootstrapped Aexol backend MCP client (from the extension's bootstrap). */
|
|
35
|
+
client: AexolMcpClient;
|
|
36
|
+
/** Bound Studio project id (every remote_* call carries it). */
|
|
37
|
+
projectId: string;
|
|
38
|
+
/**
|
|
39
|
+
* Bound team id — injected on every refine/get call so team access
|
|
40
|
+
* resolves to the BOUND project's team, not the token's first membership.
|
|
41
|
+
*/
|
|
42
|
+
teamId?: string;
|
|
43
|
+
/** Poll cadence for `remote_get_from_task` (default 2s). */
|
|
44
|
+
pollIntervalMs?: number;
|
|
45
|
+
/** Total wait for a terminal task status (default 120s). */
|
|
46
|
+
pollTimeoutMs?: number;
|
|
47
|
+
/** Optional retry hint forwarded to `remote_refine_aexol_content`. */
|
|
48
|
+
maxRetries?: number;
|
|
49
|
+
/** Optional guidance forwarded to `remote_refine_aexol_content`. */
|
|
50
|
+
guidance?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Constraint block (grammar + leak rules) merged into the refinement
|
|
53
|
+
* prompt. Supplied by the caller so the adapter stays decoupled from the
|
|
54
|
+
* logic-trace grammar constant. Only the shared leak-rule list is imported
|
|
55
|
+
* from logic-trace.ts directly, and it is read lazily inside
|
|
56
|
+
* buildRefinementPrompt (never at module-eval time) to stay safe within
|
|
57
|
+
* the logic-trace ↔ backend-draft import cycle.
|
|
58
|
+
*/
|
|
59
|
+
promptRules?: string;
|
|
60
|
+
/** Injectable sleep (tests). */
|
|
61
|
+
sleep?: (ms: number) => Promise<void>;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Build a `LogicTraceDraftRunner` that delegates the .aexol draft step to the
|
|
65
|
+
* backend from/refine pipeline. See the module doc for the outcome contract.
|
|
66
|
+
*/
|
|
67
|
+
export declare function createBackendRefineDraftRunner(options: BackendRefineDraftRunnerOptions): LogicTraceDraftRunner;
|
|
68
|
+
//# sourceMappingURL=logic-trace-backend-draft.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logic-trace-backend-draft.d.ts","sourceRoot":"","sources":["../../src/extensions/logic-trace-backend-draft.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,cAAc,EAAuB,MAAM,kBAAkB,CAAC;AAEvE,OAAO,KAAK,EAGX,qBAAqB,EACrB,MAAM,kBAAkB,CAAC;AAI1B,4DAA4D;AAC5D,eAAO,MAAM,sCAAsC,OAAQ,CAAC;AAC5D,uEAAuE;AACvE,eAAO,MAAM,qCAAqC,SAAU,CAAC;AAqB7D,MAAM,WAAW,+BAA+B;IAC/C,8EAA8E;IAC9E,MAAM,EAAE,cAAc,CAAC;IACvB,gEAAgE;IAChE,SAAS,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4DAA4D;IAC5D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gCAAgC;IAChC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAqBD;;;GAGG;AACH,wBAAgB,8BAA8B,CAC7C,OAAO,EAAE,+BAA+B,GACtC,qBAAqB,CAoGvB"}
|