@sonenta/mcp 0.35.0 → 0.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/bin/sonenta-mcp.js +245 -26
- package/bin/sonenta-mcp.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Model Context Protocol server for **Sonenta** translation management — **pure TypeScript**, no Python, no `uv`, no bundled wheel. Runs on Node ≥18.
|
|
4
4
|
|
|
5
|
-
Wires Claude Desktop and other MCP clients into your Sonenta project's keys, translations, accessibility surfaces, source-health, and glossary tools.
|
|
5
|
+
Wires Claude Desktop and other MCP clients into your Sonenta project's keys, translations, accessibility surfaces, source-health, and glossary tools — plus **agent-observability** tools (`session_start` / `annotate` / `human_needed` / `session_end`) that surface an agent's run as a live, timestamped thread in the Sonenta dashboard.
|
|
6
6
|
|
|
7
7
|
## Use
|
|
8
8
|
|
package/bin/sonenta-mcp.js
CHANGED
|
@@ -8388,21 +8388,21 @@ var init_protocol = __esm({
|
|
|
8388
8388
|
* the error appropriately (e.g., by failing the task, logging, etc.). The Protocol layer
|
|
8389
8389
|
* simply propagates the error.
|
|
8390
8390
|
*/
|
|
8391
|
-
async _enqueueTaskMessage(taskId, message,
|
|
8391
|
+
async _enqueueTaskMessage(taskId, message, sessionId2) {
|
|
8392
8392
|
if (!this._taskStore || !this._taskMessageQueue) {
|
|
8393
8393
|
throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");
|
|
8394
8394
|
}
|
|
8395
8395
|
const maxQueueSize = this._options?.maxTaskQueueSize;
|
|
8396
|
-
await this._taskMessageQueue.enqueue(taskId, message,
|
|
8396
|
+
await this._taskMessageQueue.enqueue(taskId, message, sessionId2, maxQueueSize);
|
|
8397
8397
|
}
|
|
8398
8398
|
/**
|
|
8399
8399
|
* Clears the message queue for a task and rejects any pending request resolvers.
|
|
8400
8400
|
* @param taskId The task ID whose queue should be cleared
|
|
8401
8401
|
* @param sessionId Optional session ID for binding the operation to a specific session
|
|
8402
8402
|
*/
|
|
8403
|
-
async _clearTaskQueue(taskId,
|
|
8403
|
+
async _clearTaskQueue(taskId, sessionId2) {
|
|
8404
8404
|
if (this._taskMessageQueue) {
|
|
8405
|
-
const messages = await this._taskMessageQueue.dequeueAll(taskId,
|
|
8405
|
+
const messages = await this._taskMessageQueue.dequeueAll(taskId, sessionId2);
|
|
8406
8406
|
for (const message of messages) {
|
|
8407
8407
|
if (message.type === "request" && isJSONRPCRequest(message.message)) {
|
|
8408
8408
|
const requestId = message.message.id;
|
|
@@ -8445,7 +8445,7 @@ var init_protocol = __esm({
|
|
|
8445
8445
|
}, { once: true });
|
|
8446
8446
|
});
|
|
8447
8447
|
}
|
|
8448
|
-
requestTaskStore(request,
|
|
8448
|
+
requestTaskStore(request, sessionId2) {
|
|
8449
8449
|
const taskStore = this._taskStore;
|
|
8450
8450
|
if (!taskStore) {
|
|
8451
8451
|
throw new Error("No task store configured");
|
|
@@ -8458,18 +8458,18 @@ var init_protocol = __esm({
|
|
|
8458
8458
|
return await taskStore.createTask(taskParams, request.id, {
|
|
8459
8459
|
method: request.method,
|
|
8460
8460
|
params: request.params
|
|
8461
|
-
},
|
|
8461
|
+
}, sessionId2);
|
|
8462
8462
|
},
|
|
8463
8463
|
getTask: async (taskId) => {
|
|
8464
|
-
const task = await taskStore.getTask(taskId,
|
|
8464
|
+
const task = await taskStore.getTask(taskId, sessionId2);
|
|
8465
8465
|
if (!task) {
|
|
8466
8466
|
throw new McpError(ErrorCode.InvalidParams, "Failed to retrieve task: Task not found");
|
|
8467
8467
|
}
|
|
8468
8468
|
return task;
|
|
8469
8469
|
},
|
|
8470
8470
|
storeTaskResult: async (taskId, status, result) => {
|
|
8471
|
-
await taskStore.storeTaskResult(taskId, status, result,
|
|
8472
|
-
const task = await taskStore.getTask(taskId,
|
|
8471
|
+
await taskStore.storeTaskResult(taskId, status, result, sessionId2);
|
|
8472
|
+
const task = await taskStore.getTask(taskId, sessionId2);
|
|
8473
8473
|
if (task) {
|
|
8474
8474
|
const notification = TaskStatusNotificationSchema.parse({
|
|
8475
8475
|
method: "notifications/tasks/status",
|
|
@@ -8482,18 +8482,18 @@ var init_protocol = __esm({
|
|
|
8482
8482
|
}
|
|
8483
8483
|
},
|
|
8484
8484
|
getTaskResult: (taskId) => {
|
|
8485
|
-
return taskStore.getTaskResult(taskId,
|
|
8485
|
+
return taskStore.getTaskResult(taskId, sessionId2);
|
|
8486
8486
|
},
|
|
8487
8487
|
updateTaskStatus: async (taskId, status, statusMessage) => {
|
|
8488
|
-
const task = await taskStore.getTask(taskId,
|
|
8488
|
+
const task = await taskStore.getTask(taskId, sessionId2);
|
|
8489
8489
|
if (!task) {
|
|
8490
8490
|
throw new McpError(ErrorCode.InvalidParams, `Task "${taskId}" not found - it may have been cleaned up`);
|
|
8491
8491
|
}
|
|
8492
8492
|
if (isTerminal(task.status)) {
|
|
8493
8493
|
throw new McpError(ErrorCode.InvalidParams, `Cannot update task "${taskId}" from terminal status "${task.status}" to "${status}". Terminal states (completed, failed, cancelled) cannot transition to other states.`);
|
|
8494
8494
|
}
|
|
8495
|
-
await taskStore.updateTaskStatus(taskId, status, statusMessage,
|
|
8496
|
-
const updatedTask = await taskStore.getTask(taskId,
|
|
8495
|
+
await taskStore.updateTaskStatus(taskId, status, statusMessage, sessionId2);
|
|
8496
|
+
const updatedTask = await taskStore.getTask(taskId, sessionId2);
|
|
8497
8497
|
if (updatedTask) {
|
|
8498
8498
|
const notification = TaskStatusNotificationSchema.parse({
|
|
8499
8499
|
method: "notifications/tasks/status",
|
|
@@ -8506,7 +8506,7 @@ var init_protocol = __esm({
|
|
|
8506
8506
|
}
|
|
8507
8507
|
},
|
|
8508
8508
|
listTasks: (cursor) => {
|
|
8509
|
-
return taskStore.listTasks(cursor,
|
|
8509
|
+
return taskStore.listTasks(cursor, sessionId2);
|
|
8510
8510
|
}
|
|
8511
8511
|
};
|
|
8512
8512
|
}
|
|
@@ -15724,8 +15724,8 @@ var init_server2 = __esm({
|
|
|
15724
15724
|
this._serverInfo = _serverInfo;
|
|
15725
15725
|
this._loggingLevels = /* @__PURE__ */ new Map();
|
|
15726
15726
|
this.LOG_LEVEL_SEVERITY = new Map(LoggingLevelSchema.options.map((level, index) => [level, index]));
|
|
15727
|
-
this.isMessageIgnored = (level,
|
|
15728
|
-
const currentLevel = this._loggingLevels.get(
|
|
15727
|
+
this.isMessageIgnored = (level, sessionId2) => {
|
|
15728
|
+
const currentLevel = this._loggingLevels.get(sessionId2);
|
|
15729
15729
|
return currentLevel ? this.LOG_LEVEL_SEVERITY.get(level) < this.LOG_LEVEL_SEVERITY.get(currentLevel) : false;
|
|
15730
15730
|
};
|
|
15731
15731
|
this._capabilities = options?.capabilities ?? {};
|
|
@@ -16068,9 +16068,9 @@ var init_server2 = __esm({
|
|
|
16068
16068
|
* @param params
|
|
16069
16069
|
* @param sessionId optional for stateless and backward compatibility
|
|
16070
16070
|
*/
|
|
16071
|
-
async sendLoggingMessage(params,
|
|
16071
|
+
async sendLoggingMessage(params, sessionId2) {
|
|
16072
16072
|
if (this._capabilities.logging) {
|
|
16073
|
-
if (!this.isMessageIgnored(params.level,
|
|
16073
|
+
if (!this.isMessageIgnored(params.level, sessionId2)) {
|
|
16074
16074
|
return this.notification({ method: "notifications/message", params });
|
|
16075
16075
|
}
|
|
16076
16076
|
}
|
|
@@ -16873,7 +16873,7 @@ async function unpack(res) {
|
|
|
16873
16873
|
const text2 = await res.text().catch(() => "");
|
|
16874
16874
|
let body = text2;
|
|
16875
16875
|
try {
|
|
16876
|
-
body =
|
|
16876
|
+
body = parse3(text2);
|
|
16877
16877
|
} catch {
|
|
16878
16878
|
}
|
|
16879
16879
|
throw new SonentaApiError(res.status, body);
|
|
@@ -16904,12 +16904,32 @@ var init_client = __esm({
|
|
|
16904
16904
|
this.config = config3;
|
|
16905
16905
|
}
|
|
16906
16906
|
config;
|
|
16907
|
+
/**
|
|
16908
|
+
* Active agent-observability session (contract §0). Set by `session_start`;
|
|
16909
|
+
* while non-null it is attached as `X-MCP-Session-Id` to EVERY subsequent MCP
|
|
16910
|
+
* request so the backend can auto-attach captured mutations to the thread.
|
|
16911
|
+
* Cleared by `session_end` so later calls don't bind to a closed session.
|
|
16912
|
+
*/
|
|
16913
|
+
sessionId = null;
|
|
16914
|
+
setSession(id) {
|
|
16915
|
+
this.sessionId = id;
|
|
16916
|
+
}
|
|
16917
|
+
clearSession() {
|
|
16918
|
+
this.sessionId = null;
|
|
16919
|
+
}
|
|
16907
16920
|
buildUrl(path, params) {
|
|
16908
16921
|
const base = this.config.apiBase.replace(/\/+$/, "");
|
|
16909
16922
|
const url = new URL(`${base}${path}`);
|
|
16910
16923
|
if (params) {
|
|
16911
16924
|
for (const [k, v] of Object.entries(params)) {
|
|
16912
|
-
if (v
|
|
16925
|
+
if (v === void 0 || v === null) continue;
|
|
16926
|
+
if (Array.isArray(v)) {
|
|
16927
|
+
for (const item of v) {
|
|
16928
|
+
if (item !== void 0 && item !== null) url.searchParams.append(k, String(item));
|
|
16929
|
+
}
|
|
16930
|
+
} else {
|
|
16931
|
+
url.searchParams.set(k, String(v));
|
|
16932
|
+
}
|
|
16913
16933
|
}
|
|
16914
16934
|
}
|
|
16915
16935
|
return url.toString();
|
|
@@ -16920,6 +16940,7 @@ var init_client = __esm({
|
|
|
16920
16940
|
"User-Agent": this.config.userAgent,
|
|
16921
16941
|
Accept: "application/json"
|
|
16922
16942
|
});
|
|
16943
|
+
if (this.sessionId) headers.set("X-MCP-Session-Id", this.sessionId);
|
|
16923
16944
|
const init = { method, headers };
|
|
16924
16945
|
if (opts.json !== void 0) {
|
|
16925
16946
|
headers.set("Content-Type", "application/json");
|
|
@@ -17053,6 +17074,7 @@ function pyRepr(v) {
|
|
|
17053
17074
|
if (v === null || v === void 0) return "None";
|
|
17054
17075
|
if (v === true) return "True";
|
|
17055
17076
|
if (v === false) return "False";
|
|
17077
|
+
if (isLosslessNumber(v)) return v.toString();
|
|
17056
17078
|
if (typeof v === "number") return String(v);
|
|
17057
17079
|
if (typeof v === "string") {
|
|
17058
17080
|
const esc2 = v.replace(/\\/g, "\\\\");
|
|
@@ -17079,6 +17101,7 @@ var ToolValidationError, ValueError;
|
|
|
17079
17101
|
var init_errors3 = __esm({
|
|
17080
17102
|
"src/errors.ts"() {
|
|
17081
17103
|
"use strict";
|
|
17104
|
+
init_esm2();
|
|
17082
17105
|
init_client();
|
|
17083
17106
|
ToolValidationError = class extends Error {
|
|
17084
17107
|
constructor(message) {
|
|
@@ -18207,6 +18230,17 @@ var init_schemas_generated = __esm({
|
|
|
18207
18230
|
"minimum": 1,
|
|
18208
18231
|
"maximum": 200,
|
|
18209
18232
|
"default": 50
|
|
18233
|
+
},
|
|
18234
|
+
"name_prefix": {
|
|
18235
|
+
"type": "string",
|
|
18236
|
+
"description": 'Return only keys whose name starts with this prefix \u2014 a cheap scoped lookup (e.g. name_prefix="nav.").'
|
|
18237
|
+
},
|
|
18238
|
+
"key_uuids": {
|
|
18239
|
+
"type": "array",
|
|
18240
|
+
"items": {
|
|
18241
|
+
"type": "string"
|
|
18242
|
+
},
|
|
18243
|
+
"description": "Return only these specific keys, by UUID (repeated query param). Use for a cheap targeted fetch of a known set of keys."
|
|
18210
18244
|
}
|
|
18211
18245
|
},
|
|
18212
18246
|
"additionalProperties": false
|
|
@@ -18289,7 +18323,7 @@ var init_schemas_generated = __esm({
|
|
|
18289
18323
|
}
|
|
18290
18324
|
},
|
|
18291
18325
|
"list_source_duplicates": {
|
|
18292
|
-
"description": "List groups of keys that SHARE an identical source-language value (Source Health duplicates, #1116).
|
|
18326
|
+
"description": "List groups of keys that SHARE an identical source-language value (Source Health duplicates, #1116). PAGINATED: returns an envelope {items, total, offset, limit, has_more} \u2014 read `.items` (each group = {source_value, key_count, key_names[], key_uuids[], status, note}) and page with offset/limit (default 50, max 200) until has_more is false. Duplicates inflate translation cost and drift (the same string translated N ways), so this is the worklist the sonenta-source-health agent repairs. Status is tracked PROJECT-WIDE per source_value: neutral (UNTRIAGED \u2014 the default for a freshly-detected duplicate; this is the batch auto-diagnostic backlog), to_fix (triaged for fixing \u2014 carries a merge_plan to apply), allowed (intentional duplicate \u2014 listed+flagged but excluded from total_issues), resolved (already fixed \u2014 re-scan confirms). Filter by status to focus (e.g. status=neutral for the untriaged backlog). A to_fix group carries a human- or agent-prepared `merge_plan` ({clusters: [{canonical_key_uuid, redundant_key_uuids[]}], survivor_outcome: allowed|differentiate}) \u2014 the consolidation an agent applies (merge each cluster onto its canonical key, then allow or differentiate whatever still shares the text). READ-ONLY.",
|
|
18293
18327
|
"inputSchema": {
|
|
18294
18328
|
"type": "object",
|
|
18295
18329
|
"properties": {
|
|
@@ -18300,15 +18334,29 @@ var init_schemas_generated = __esm({
|
|
|
18300
18334
|
"status": {
|
|
18301
18335
|
"type": "string",
|
|
18302
18336
|
"enum": [
|
|
18303
|
-
"
|
|
18337
|
+
"neutral",
|
|
18304
18338
|
"allowed",
|
|
18339
|
+
"to_fix",
|
|
18305
18340
|
"resolved"
|
|
18306
18341
|
],
|
|
18307
|
-
"description": "Filter to duplicate groups in this triage status. Omit for all."
|
|
18342
|
+
"description": "Filter to duplicate groups in this triage status: neutral (untriaged \u2014 the default), to_fix (triaged, carries a merge_plan), allowed (intentional), resolved (fixed). Omit for all."
|
|
18308
18343
|
},
|
|
18309
18344
|
"version_id": {
|
|
18310
18345
|
"type": "string",
|
|
18311
18346
|
"description": "Optional version UUID; defaults to the production version."
|
|
18347
|
+
},
|
|
18348
|
+
"offset": {
|
|
18349
|
+
"type": "integer",
|
|
18350
|
+
"minimum": 0,
|
|
18351
|
+
"default": 0,
|
|
18352
|
+
"description": "Pagination offset (0-based). Default 0."
|
|
18353
|
+
},
|
|
18354
|
+
"limit": {
|
|
18355
|
+
"type": "integer",
|
|
18356
|
+
"minimum": 1,
|
|
18357
|
+
"maximum": 200,
|
|
18358
|
+
"default": 50,
|
|
18359
|
+
"description": "Max groups per page (1..200). Default 50."
|
|
18312
18360
|
}
|
|
18313
18361
|
},
|
|
18314
18362
|
"additionalProperties": false
|
|
@@ -19395,6 +19443,125 @@ var init_schemas_generated = __esm({
|
|
|
19395
19443
|
}
|
|
19396
19444
|
});
|
|
19397
19445
|
|
|
19446
|
+
// src/tools/schemas.observability.ts
|
|
19447
|
+
var PROJECT_UUID, SESSION_ID, OBSERVABILITY_SCHEMAS, OBSERVABILITY_TOOL_NAMES;
|
|
19448
|
+
var init_schemas_observability = __esm({
|
|
19449
|
+
"src/tools/schemas.observability.ts"() {
|
|
19450
|
+
"use strict";
|
|
19451
|
+
PROJECT_UUID = {
|
|
19452
|
+
type: "string",
|
|
19453
|
+
description: "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise."
|
|
19454
|
+
};
|
|
19455
|
+
SESSION_ID = {
|
|
19456
|
+
type: "string",
|
|
19457
|
+
description: "Agent session id returned by session_start. Optional: defaults to this server's active session, so you normally omit it after calling session_start."
|
|
19458
|
+
};
|
|
19459
|
+
OBSERVABILITY_SCHEMAS = {
|
|
19460
|
+
session_start: {
|
|
19461
|
+
description: "Open an observability session so your work shows up as a live, timestamped thread in the Sonenta dashboard. Call this ONCE at the very start of a task, before touching anything. After it returns, every later MCP call you make is automatically attached to this session's thread (no extra wiring) \u2014 so real mutations (keys created, translations proposed, variants set\u2026) are captured even if you never call annotate. Returns {session_id, status, channel}. Idempotent per (project, session_ref) while a running session with that ref exists. Observability is always free (0 credits).",
|
|
19462
|
+
inputSchema: {
|
|
19463
|
+
type: "object",
|
|
19464
|
+
properties: {
|
|
19465
|
+
project_uuid: PROJECT_UUID,
|
|
19466
|
+
agent: {
|
|
19467
|
+
type: "string",
|
|
19468
|
+
description: "Stable agent label shown in the dashboard thread, e.g. 'sonenta-source-health' or 'sonenta-a11y'. Use your own agent name."
|
|
19469
|
+
},
|
|
19470
|
+
title: {
|
|
19471
|
+
type: "string",
|
|
19472
|
+
description: "Optional one-line human-readable title for this run, e.g. 'Repair placeholder drift'."
|
|
19473
|
+
},
|
|
19474
|
+
session_ref: {
|
|
19475
|
+
type: "string",
|
|
19476
|
+
description: "Optional client idempotency key; reusing it while a session is still running returns that same session."
|
|
19477
|
+
},
|
|
19478
|
+
metadata: {
|
|
19479
|
+
type: "object",
|
|
19480
|
+
description: "Optional opaque object echoed back in the session detail (free-form run context)."
|
|
19481
|
+
}
|
|
19482
|
+
},
|
|
19483
|
+
required: ["agent"]
|
|
19484
|
+
}
|
|
19485
|
+
},
|
|
19486
|
+
annotate: {
|
|
19487
|
+
description: "Append one readable line to the current session's thread \u2014 a human-facing step summary, NOT structured data. Use it to narrate what you are doing at a level a project owner can follow ('Found 12 keys with fr placeholder drift; repairing'). Optional; the thread stays faithful without it because real mutations are auto-captured. Free (0 credits).",
|
|
19488
|
+
inputSchema: {
|
|
19489
|
+
type: "object",
|
|
19490
|
+
properties: {
|
|
19491
|
+
project_uuid: PROJECT_UUID,
|
|
19492
|
+
session_id: SESSION_ID,
|
|
19493
|
+
summary: {
|
|
19494
|
+
type: "string",
|
|
19495
|
+
description: "The readable one-line step summary to append to the thread."
|
|
19496
|
+
},
|
|
19497
|
+
level: {
|
|
19498
|
+
type: "string",
|
|
19499
|
+
enum: ["info", "warning"],
|
|
19500
|
+
default: "info",
|
|
19501
|
+
description: "info for normal progress; warning to flag something the human should notice."
|
|
19502
|
+
},
|
|
19503
|
+
payload: {
|
|
19504
|
+
type: "object",
|
|
19505
|
+
description: "Optional structured detail rendered when the line is expanded in the dashboard."
|
|
19506
|
+
}
|
|
19507
|
+
},
|
|
19508
|
+
required: ["summary"]
|
|
19509
|
+
}
|
|
19510
|
+
},
|
|
19511
|
+
human_needed: {
|
|
19512
|
+
description: "Raise a decision you are waiting on a human for \u2014 it appears as a todo in the dashboard and pauses that branch of work until a person resolves it. Use this the moment you hit a choice that is the founder's to make (never guess a business rule): merge vs keep-separate, an ambiguous source, an irreversible action. Provide clear options when there is a discrete set. Free (0 credits).",
|
|
19513
|
+
inputSchema: {
|
|
19514
|
+
type: "object",
|
|
19515
|
+
properties: {
|
|
19516
|
+
project_uuid: PROJECT_UUID,
|
|
19517
|
+
session_id: SESSION_ID,
|
|
19518
|
+
question: {
|
|
19519
|
+
type: "string",
|
|
19520
|
+
description: `The decision, phrased for a human, e.g. "Merge duplicate 'Save' keys or keep them separate?".`
|
|
19521
|
+
},
|
|
19522
|
+
detail: {
|
|
19523
|
+
type: "string",
|
|
19524
|
+
description: "Optional context that helps the human decide."
|
|
19525
|
+
},
|
|
19526
|
+
deep_link: {
|
|
19527
|
+
type: "string",
|
|
19528
|
+
description: "Optional relative dashboard path to the thing needing attention; defaults to the session thread."
|
|
19529
|
+
},
|
|
19530
|
+
options: {
|
|
19531
|
+
type: "array",
|
|
19532
|
+
items: { type: "string" },
|
|
19533
|
+
description: "Optional suggested choices, e.g. ['merge', 'keep separate']."
|
|
19534
|
+
}
|
|
19535
|
+
},
|
|
19536
|
+
required: ["question"]
|
|
19537
|
+
}
|
|
19538
|
+
},
|
|
19539
|
+
session_end: {
|
|
19540
|
+
description: "Close the current observability session when the task is done (or aborted). Records a closing line, marks the thread ended, and triggers the opt-in end-of-session email to project devs. After this, later MCP calls no longer attach to this session. Idempotent \u2014 ending an already-ended session is a no-op. Free (0 credits).",
|
|
19541
|
+
inputSchema: {
|
|
19542
|
+
type: "object",
|
|
19543
|
+
properties: {
|
|
19544
|
+
project_uuid: PROJECT_UUID,
|
|
19545
|
+
session_id: SESSION_ID,
|
|
19546
|
+
summary: {
|
|
19547
|
+
type: "string",
|
|
19548
|
+
description: "Optional closing line, e.g. 'Repaired 12 keys, 1 decision pending'."
|
|
19549
|
+
},
|
|
19550
|
+
status: {
|
|
19551
|
+
type: "string",
|
|
19552
|
+
enum: ["ended", "aborted"],
|
|
19553
|
+
default: "ended",
|
|
19554
|
+
description: "ended for a normal finish; aborted if you stopped early."
|
|
19555
|
+
}
|
|
19556
|
+
},
|
|
19557
|
+
required: []
|
|
19558
|
+
}
|
|
19559
|
+
}
|
|
19560
|
+
};
|
|
19561
|
+
OBSERVABILITY_TOOL_NAMES = Object.keys(OBSERVABILITY_SCHEMAS);
|
|
19562
|
+
}
|
|
19563
|
+
});
|
|
19564
|
+
|
|
19398
19565
|
// src/tools/registry.ts
|
|
19399
19566
|
var registry_exports = {};
|
|
19400
19567
|
__export(registry_exports, {
|
|
@@ -19407,6 +19574,14 @@ function copyPresent(body, args, keys) {
|
|
|
19407
19574
|
function copyTruthy(target, args, keys) {
|
|
19408
19575
|
for (const k of keys) if (args[k]) target[k] = args[k];
|
|
19409
19576
|
}
|
|
19577
|
+
function sessionId(args, client) {
|
|
19578
|
+
const explicit = args["session_id"];
|
|
19579
|
+
if (explicit) return str(explicit);
|
|
19580
|
+
if (client.sessionId) return client.sessionId;
|
|
19581
|
+
throw new ToolValidationError(
|
|
19582
|
+
"session_id is required (call session_start first, or pass session_id explicitly)"
|
|
19583
|
+
);
|
|
19584
|
+
}
|
|
19410
19585
|
function a11yReportParams(args) {
|
|
19411
19586
|
const params = {};
|
|
19412
19587
|
if (args["version_id"]) params["version_id"] = str(args["version_id"]);
|
|
@@ -19446,6 +19621,7 @@ var init_registry = __esm({
|
|
|
19446
19621
|
init_errors3();
|
|
19447
19622
|
init_helpers2();
|
|
19448
19623
|
init_schemas_generated();
|
|
19624
|
+
init_schemas_observability();
|
|
19449
19625
|
A11Y_SURFACES = ["aria_label", "alt_text", "screen_reader", "plain_language"];
|
|
19450
19626
|
has = (args, k) => k in args;
|
|
19451
19627
|
truthy = (args, k) => Boolean(args[k]);
|
|
@@ -19474,6 +19650,8 @@ var init_registry = __esm({
|
|
|
19474
19650
|
namespace: args["namespace"],
|
|
19475
19651
|
language_code: args["language_code"],
|
|
19476
19652
|
status_filter: args["status_filter"],
|
|
19653
|
+
name_prefix: args["name_prefix"],
|
|
19654
|
+
key_uuids: Array.isArray(args["key_uuids"]) ? args["key_uuids"] : void 0,
|
|
19477
19655
|
include_glossary_hints: truthy(args, "include_glossary_hints") ? "true" : void 0,
|
|
19478
19656
|
cursor: args["cursor"],
|
|
19479
19657
|
limit: args["limit"] ?? 50
|
|
@@ -19893,7 +20071,9 @@ var init_registry = __esm({
|
|
|
19893
20071
|
const p = resolveProjectUuid(args, client);
|
|
19894
20072
|
const params = {
|
|
19895
20073
|
status: args["status"],
|
|
19896
|
-
version_id: args["version_id"]
|
|
20074
|
+
version_id: args["version_id"],
|
|
20075
|
+
offset: args["offset"],
|
|
20076
|
+
limit: args["limit"]
|
|
19897
20077
|
};
|
|
19898
20078
|
return client.get(`/v1/mcp/projects/${p}/source-duplicates`, params);
|
|
19899
20079
|
},
|
|
@@ -19959,9 +20139,48 @@ var init_registry = __esm({
|
|
|
19959
20139
|
let url = `/v1/mcp/projects/${p}/source-duplicates/propose-plan`;
|
|
19960
20140
|
if (args["version_id"]) url += `?version_id=${str(args["version_id"])}`;
|
|
19961
20141
|
return client.post(url, body);
|
|
20142
|
+
},
|
|
20143
|
+
// ---- agent observability (contract v1, task 1611) ----
|
|
20144
|
+
async session_start(args, client) {
|
|
20145
|
+
const p = resolveProjectUuid(args, client);
|
|
20146
|
+
if (!truthy(args, "agent")) throw new ToolValidationError("agent is required");
|
|
20147
|
+
const body = { agent: args["agent"] };
|
|
20148
|
+
copyPresent(body, args, ["title", "session_ref", "metadata"]);
|
|
20149
|
+
const data = await client.post(`/v1/mcp/projects/${p}/agent/sessions`, body);
|
|
20150
|
+
const sid = data?.["session_id"];
|
|
20151
|
+
if (typeof sid === "string" && sid) client.setSession(sid);
|
|
20152
|
+
return data;
|
|
20153
|
+
},
|
|
20154
|
+
async annotate(args, client) {
|
|
20155
|
+
const p = resolveProjectUuid(args, client);
|
|
20156
|
+
const sid = sessionId(args, client);
|
|
20157
|
+
if (!truthy(args, "summary")) throw new ToolValidationError("summary is required");
|
|
20158
|
+
const body = { summary: args["summary"] };
|
|
20159
|
+
copyPresent(body, args, ["level", "payload"]);
|
|
20160
|
+
return client.post(`/v1/mcp/projects/${p}/agent/sessions/${sid}/annotate`, body);
|
|
20161
|
+
},
|
|
20162
|
+
async human_needed(args, client) {
|
|
20163
|
+
const p = resolveProjectUuid(args, client);
|
|
20164
|
+
const sid = sessionId(args, client);
|
|
20165
|
+
if (!truthy(args, "question")) throw new ToolValidationError("question is required");
|
|
20166
|
+
const body = { question: args["question"] };
|
|
20167
|
+
copyPresent(body, args, ["detail", "deep_link", "options"]);
|
|
20168
|
+
return client.post(`/v1/mcp/projects/${p}/agent/sessions/${sid}/human-needed`, body);
|
|
20169
|
+
},
|
|
20170
|
+
async session_end(args, client) {
|
|
20171
|
+
const p = resolveProjectUuid(args, client);
|
|
20172
|
+
const sid = sessionId(args, client);
|
|
20173
|
+
const body = {};
|
|
20174
|
+
copyPresent(body, args, ["summary", "status"]);
|
|
20175
|
+
const data = await client.post(`/v1/mcp/projects/${p}/agent/sessions/${sid}/end`, body);
|
|
20176
|
+
if (client.sessionId === sid) client.clearSession();
|
|
20177
|
+
return data;
|
|
19962
20178
|
}
|
|
19963
20179
|
};
|
|
19964
|
-
TOOLS = Object.entries(
|
|
20180
|
+
TOOLS = Object.entries({
|
|
20181
|
+
...SCHEMAS,
|
|
20182
|
+
...OBSERVABILITY_SCHEMAS
|
|
20183
|
+
}).map(([name, schema]) => {
|
|
19965
20184
|
const handler = HANDLERS[name];
|
|
19966
20185
|
if (!handler) throw new Error(`registry: no handler ported for tool '${name}'`);
|
|
19967
20186
|
return { name, description: schema.description, inputSchema: schema.inputSchema, handler };
|
|
@@ -20051,7 +20270,7 @@ var init_server3 = __esm({
|
|
|
20051
20270
|
init_errors3();
|
|
20052
20271
|
init_helpers2();
|
|
20053
20272
|
init_registry();
|
|
20054
|
-
VERSION = "0.
|
|
20273
|
+
VERSION = "0.37.0";
|
|
20055
20274
|
}
|
|
20056
20275
|
});
|
|
20057
20276
|
|