@agent-wire/terminal 1.7.0 → 1.7.2
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 +44 -1
- package/dist/api.d.ts +78 -16
- package/dist/api.js +42 -5
- package/dist/api.js.map +1 -1
- package/dist/cli.js +104 -10
- package/dist/cli.js.map +1 -1
- package/dist/identity.d.ts +1 -0
- package/dist/identity.js +6 -0
- package/dist/identity.js.map +1 -1
- package/dist/local-pull.js +19 -0
- package/dist/local-pull.js.map +1 -1
- package/dist/mcp-server.d.ts +10 -0
- package/dist/mcp-server.js +209 -40
- package/dist/mcp-server.js.map +1 -1
- package/dist/sync/index.d.ts +1 -1
- package/dist/sync/index.js.map +1 -1
- package/dist/sync/push.d.ts +41 -3
- package/dist/sync/push.js +51 -2
- package/dist/sync/push.js.map +1 -1
- package/dist/sync/types.d.ts +1 -0
- package/package.json +1 -1
package/dist/mcp-server.js
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
// their replacements live in slots.ts. The legacy functions in
|
|
19
19
|
// identity.ts remain for backward compat with wait-cli.ts during the
|
|
20
20
|
// migration window.
|
|
21
|
-
loadDeviceRecord, saveDeviceRecord, loadAuthPending, saveAuthPending, deleteAuthPending, getStableDeviceFingerprint, hasAnyLocalIdentityForEmail, acquireIdentityLock, releaseIdentityLock, } from './identity.js';
|
|
21
|
+
loadDeviceRecord, saveDeviceRecord, deleteDeviceRecord, loadAuthPending, saveAuthPending, deleteAuthPending, getStableDeviceFingerprint, hasAnyLocalIdentityForEmail, acquireIdentityLock, releaseIdentityLock, } from './identity.js';
|
|
22
22
|
import { acquireLock, releaseLock, isWorkerRunning } from './lockfile.js';
|
|
23
23
|
import { walkDirectory, computeDiff, pushFiles, pullFiles, parseManifest, serializeManifest, updateManifest, paginateAll, } from './sync/index.js';
|
|
24
24
|
import { WIRE_HELP_POINTER } from './help-pointer.js';
|
|
@@ -81,7 +81,7 @@ function normalizeApiRootPath(path) {
|
|
|
81
81
|
}
|
|
82
82
|
async function fetchSurfaceConfigItems(api) {
|
|
83
83
|
const queries = ['surface_config', 'dispatcher_bound_surface_config', 'lookup_surface'];
|
|
84
|
-
const responses = await Promise.all(queries.map((text) => api.query({ text, domain: 'all', limit: 100 })));
|
|
84
|
+
const responses = await Promise.all(queries.map((text) => api.query({ text, domain: 'all', limit: 100, sort: 'recency' })));
|
|
85
85
|
return responses.flatMap(extractQueryItems);
|
|
86
86
|
}
|
|
87
87
|
async function refreshSubstrateSurfaces(api) {
|
|
@@ -147,6 +147,46 @@ function parseToolRefreshPollIntervalMs(items) {
|
|
|
147
147
|
}
|
|
148
148
|
return { pollIntervalMs: Math.round(value), source: 'economic_parameter', handle: latest.handle_path };
|
|
149
149
|
}
|
|
150
|
+
function toolsAvailableMsg(verificationStatus) {
|
|
151
|
+
return verificationStatus === 'confirmed'
|
|
152
|
+
? 'All tools available.'
|
|
153
|
+
: 'Pending verification: wire_identify, wire_query, wire_graph, wire_inspect, wire_status, wire_corpora, wire_legal, wire_pulse, wire_opportunities, wire_roster available now. Credit-affecting tools (wire_contribute, wire_rate, wire_flag, wire_correct, wire_messages, wire_market, wire_games, wire_supersede) require operator approval — check your operator\'s email.';
|
|
154
|
+
}
|
|
155
|
+
function looksLikeDeviceAuthFailure(error) {
|
|
156
|
+
if (!error)
|
|
157
|
+
return false;
|
|
158
|
+
return /\b(401|410)\b|revoked|device authorization|device secret|unauthorized/i.test(error.message);
|
|
159
|
+
}
|
|
160
|
+
function buildResumeResponse(params) {
|
|
161
|
+
const resumedStatus = typeof params.verificationStatus === 'string'
|
|
162
|
+
? params.verificationStatus
|
|
163
|
+
: 'unknown';
|
|
164
|
+
const resumeResponse = {
|
|
165
|
+
status: 'resumed',
|
|
166
|
+
identity: `${params.requestedName} (pseudo-ID: ${params.pseudoId})`,
|
|
167
|
+
operator: params.operatorEmail,
|
|
168
|
+
verification_status: resumedStatus,
|
|
169
|
+
help: WIRE_HELP_POINTER,
|
|
170
|
+
tools_available: toolsAvailableMsg(resumedStatus),
|
|
171
|
+
};
|
|
172
|
+
if (params.sinceLastSession && typeof params.sinceLastSession === 'object') {
|
|
173
|
+
const sls = params.sinceLastSession;
|
|
174
|
+
const parts = [];
|
|
175
|
+
if (sls.new_messages > 0)
|
|
176
|
+
parts.push(`${sls.new_messages} new message${sls.new_messages !== 1 ? 's' : ''}`);
|
|
177
|
+
if (sls.new_tasks > 0)
|
|
178
|
+
parts.push(`${sls.new_tasks} new task${sls.new_tasks !== 1 ? 's' : ''}`);
|
|
179
|
+
if (sls.new_contributions > 0)
|
|
180
|
+
parts.push(`${sls.new_contributions} new contribution${sls.new_contributions !== 1 ? 's' : ''}`);
|
|
181
|
+
if (sls.credits_earned > 0)
|
|
182
|
+
parts.push(`${sls.credits_earned} credits earned`);
|
|
183
|
+
if (parts.length > 0) {
|
|
184
|
+
resumeResponse.while_you_were_away = `While you were away: ${parts.join(', ')}.`;
|
|
185
|
+
}
|
|
186
|
+
resumeResponse.since_last_session = sls;
|
|
187
|
+
}
|
|
188
|
+
return resumeResponse;
|
|
189
|
+
}
|
|
150
190
|
export const __mcpSurfaceTestInternals = {
|
|
151
191
|
normalizeSurfaceName,
|
|
152
192
|
surfaceToolName,
|
|
@@ -156,6 +196,8 @@ export const __mcpSurfaceTestInternals = {
|
|
|
156
196
|
SURFACE_REFRESH_TTL_MS,
|
|
157
197
|
fingerprintSubstrateSurfaces,
|
|
158
198
|
parseToolRefreshPollIntervalMs,
|
|
199
|
+
buildResumeResponse,
|
|
200
|
+
looksLikeDeviceAuthFailure,
|
|
159
201
|
};
|
|
160
202
|
export async function startMcpServer(options) {
|
|
161
203
|
const loadedConfig = loadConfig();
|
|
@@ -466,6 +508,7 @@ export async function startMcpServer(options) {
|
|
|
466
508
|
text: 'refresh_mcp_tools_poll_interval economic_parameter',
|
|
467
509
|
domain: 'all',
|
|
468
510
|
limit: 25,
|
|
511
|
+
sort: 'recency',
|
|
469
512
|
});
|
|
470
513
|
const policy = parseToolRefreshPollIntervalMs(extractQueryItems(result));
|
|
471
514
|
if (policy.source === 'default') {
|
|
@@ -556,10 +599,6 @@ export async function startMcpServer(options) {
|
|
|
556
599
|
create_new: z.boolean().optional().describe('Set true to explicitly create a new agent identity. Without this, unrecognized names return the roster instead of auto-creating.'),
|
|
557
600
|
agent_message: z.string().optional().describe('Context message included in any emails sent to the operator during this flow.'),
|
|
558
601
|
}, async (params) => {
|
|
559
|
-
// ── Helper: tools_available message based on verification status ──
|
|
560
|
-
const toolsAvailableMsg = (verificationStatus) => verificationStatus === 'confirmed'
|
|
561
|
-
? 'All tools available.'
|
|
562
|
-
: 'Pending verification: wire_identify, wire_query, wire_graph, wire_inspect, wire_status, wire_corpora, wire_legal, wire_pulse, wire_opportunities, wire_roster available now. Credit-affecting tools (wire_contribute, wire_rate, wire_flag, wire_correct, wire_messages, wire_market, wire_games, wire_supersede) require operator approval — check your operator\'s email.';
|
|
563
602
|
const nameKey = params.name.trim().toLowerCase();
|
|
564
603
|
// ── Mission #1.5-rev2: first-call-wins pin guard ──────────
|
|
565
604
|
// If this MCP process is already pinned and the request is for
|
|
@@ -882,20 +921,134 @@ export async function startMcpServer(options) {
|
|
|
882
921
|
}, null, 2) }],
|
|
883
922
|
};
|
|
884
923
|
}
|
|
885
|
-
// ── 5. Have device secret —
|
|
924
|
+
// ── 5. Have device secret — resume/register without requiring roster ─
|
|
886
925
|
if (deviceRecord) {
|
|
926
|
+
let resumeError = null;
|
|
927
|
+
if (!params.create_new) {
|
|
928
|
+
const nonce = randomUUID();
|
|
929
|
+
let resumed = null;
|
|
930
|
+
try {
|
|
931
|
+
resumed = await bootApi.resumeAgent(params.name, deviceRecord.deviceSecret, nonce);
|
|
932
|
+
}
|
|
933
|
+
catch (err) {
|
|
934
|
+
resumeError = err;
|
|
935
|
+
}
|
|
936
|
+
if (resumed) {
|
|
937
|
+
establishPin(params.name, {
|
|
938
|
+
apiToken: resumed.api_token,
|
|
939
|
+
agentId: resumed.agent_id,
|
|
940
|
+
pseudoId: resumed.pseudo_id,
|
|
941
|
+
operatorEmail: params.operator_email,
|
|
942
|
+
verificationStatus: resumed.verification_status,
|
|
943
|
+
}, 'device-resume');
|
|
944
|
+
await discoverSurfacesAtPin('device-resume');
|
|
945
|
+
await ensureNodeAndMaybeStartWorker();
|
|
946
|
+
const canonicalName = resumed.name || params.name;
|
|
947
|
+
shaperContext = {
|
|
948
|
+
agentName: canonicalName,
|
|
949
|
+
agentHandle: null,
|
|
950
|
+
verificationStatus: normalizeVerificationStatus(resumed.verification_status),
|
|
951
|
+
firstIdentifyInSession: false,
|
|
952
|
+
lastSessionAt: null,
|
|
953
|
+
lastAccessedContributionId: null,
|
|
954
|
+
};
|
|
955
|
+
console.error(`[wire-mcp] Resumed via device secret: ${canonicalName} (${resumed.pseudo_id})`);
|
|
956
|
+
return {
|
|
957
|
+
content: [{ type: 'text', text: JSON.stringify(buildResumeResponse({
|
|
958
|
+
requestedName: params.name,
|
|
959
|
+
pseudoId: resumed.pseudo_id,
|
|
960
|
+
operatorEmail: params.operator_email,
|
|
961
|
+
verificationStatus: resumed.verification_status,
|
|
962
|
+
sinceLastSession: resumed.since_last_session,
|
|
963
|
+
}), null, 2) }],
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
console.error(`[wire-mcp] Direct agent resume failed for ${params.name}: ${resumeError?.message ?? 'unknown error'}`);
|
|
967
|
+
}
|
|
887
968
|
const harness = process.env.MCP_CLIENT_NAME || undefined;
|
|
888
969
|
let roster;
|
|
889
970
|
try {
|
|
890
971
|
roster = await bootApi.getRosterWithDeviceSecret(deviceRecord.deviceSecret, harness, params.name);
|
|
891
972
|
}
|
|
892
973
|
catch (err) {
|
|
893
|
-
|
|
894
|
-
|
|
974
|
+
const rosterError = err;
|
|
975
|
+
console.error(`[wire-mcp] Roster fetch failed: ${rosterError.message}`);
|
|
976
|
+
if (params.create_new) {
|
|
977
|
+
const sessionMetadata = {
|
|
978
|
+
hostname: hostname(),
|
|
979
|
+
pid: process.pid,
|
|
980
|
+
client: process.env.MCP_CLIENT_NAME || 'unknown',
|
|
981
|
+
session_started: new Date().toISOString(),
|
|
982
|
+
};
|
|
983
|
+
let result;
|
|
984
|
+
try {
|
|
985
|
+
result = await bootApi.registerAgent({
|
|
986
|
+
name: params.name,
|
|
987
|
+
operator_email: params.operator_email,
|
|
988
|
+
domains: ['all'],
|
|
989
|
+
session_metadata: sessionMetadata,
|
|
990
|
+
agent_message: params.agent_message,
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
catch (registerErr) {
|
|
994
|
+
return {
|
|
995
|
+
content: [{ type: 'text', text: JSON.stringify({
|
|
996
|
+
status: 'error',
|
|
997
|
+
error: `Roster unavailable (${rosterError.message}) and direct agent registration failed: ${registerErr.message}`,
|
|
998
|
+
}, null, 2) }],
|
|
999
|
+
isError: true,
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
if (!result.api_token || !result.pseudo_id || !result.agent_id) {
|
|
1003
|
+
return {
|
|
1004
|
+
content: [{ type: 'text', text: JSON.stringify({
|
|
1005
|
+
status: 'error', error: 'Registration response missing critical fields.',
|
|
1006
|
+
}, null, 2) }],
|
|
1007
|
+
isError: true,
|
|
1008
|
+
};
|
|
1009
|
+
}
|
|
1010
|
+
establishPin(params.name, {
|
|
1011
|
+
apiToken: result.api_token,
|
|
1012
|
+
agentId: result.agent_id,
|
|
1013
|
+
pseudoId: result.pseudo_id,
|
|
1014
|
+
operatorEmail: params.operator_email,
|
|
1015
|
+
verificationStatus: result.verification_status,
|
|
1016
|
+
}, 'direct-create-new');
|
|
1017
|
+
await discoverSurfacesAtPin('direct-create-new');
|
|
1018
|
+
await ensureNodeAndMaybeStartWorker();
|
|
1019
|
+
shaperContext = {
|
|
1020
|
+
agentName: params.name,
|
|
1021
|
+
agentHandle: null,
|
|
1022
|
+
verificationStatus: normalizeVerificationStatus(result.verification_status),
|
|
1023
|
+
firstIdentifyInSession: true,
|
|
1024
|
+
lastSessionAt: null,
|
|
1025
|
+
lastAccessedContributionId: null,
|
|
1026
|
+
};
|
|
1027
|
+
return { content: [{ type: 'text', text: JSON.stringify({
|
|
1028
|
+
status: 'registered',
|
|
1029
|
+
identity: `${params.name} (pseudo-ID: ${result.pseudo_id})`,
|
|
1030
|
+
verification_status: result.verification_status,
|
|
1031
|
+
roster_warning: `Roster lookup failed (${rosterError.message}); registered directly via /register.`,
|
|
1032
|
+
help: WIRE_HELP_POINTER,
|
|
1033
|
+
tools_available: toolsAvailableMsg(result.verification_status),
|
|
1034
|
+
}, null, 2) }] };
|
|
1035
|
+
}
|
|
1036
|
+
if (looksLikeDeviceAuthFailure(resumeError) && looksLikeDeviceAuthFailure(rosterError)) {
|
|
1037
|
+
deleteDeviceRecord(params.operator_email);
|
|
1038
|
+
return {
|
|
1039
|
+
content: [{ type: 'text', text: JSON.stringify({
|
|
1040
|
+
status: 'reauthorization_required',
|
|
1041
|
+
error: `Device authorization appears revoked: direct resume failed (${resumeError?.message ?? 'unknown error'}); roster lookup failed (${rosterError.message}).`,
|
|
1042
|
+
next_step: 'Call wire_identify again without device_code to request a fresh email authorization code.',
|
|
1043
|
+
}, null, 2) }],
|
|
1044
|
+
isError: true,
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
895
1047
|
return {
|
|
896
1048
|
content: [{ type: 'text', text: JSON.stringify({
|
|
897
|
-
status: '
|
|
898
|
-
error: `Failed to
|
|
1049
|
+
status: 'identity_resolution_failed',
|
|
1050
|
+
error: `Failed to resume "${params.name}" directly, and roster lookup is unavailable: ${rosterError.message}`,
|
|
1051
|
+
hint: 'Check the agent name, or retry with create_new:true to register a new identity. Device authorization itself may still be valid.',
|
|
899
1052
|
}, null, 2) }],
|
|
900
1053
|
isError: true,
|
|
901
1054
|
};
|
|
@@ -939,33 +1092,14 @@ export async function startMcpServer(options) {
|
|
|
939
1092
|
};
|
|
940
1093
|
const resumedStatus = resumed.verification_status ?? 'unknown';
|
|
941
1094
|
console.error(`[wire-mcp] Resumed via roster: ${canonicalName} (${resumed.pseudo_id})`);
|
|
942
|
-
const resumeResponse = {
|
|
943
|
-
status: 'resumed',
|
|
944
|
-
identity: `${params.name} (pseudo-ID: ${resumed.pseudo_id})`,
|
|
945
|
-
operator: params.operator_email,
|
|
946
|
-
verification_status: resumed.verification_status ?? 'unknown',
|
|
947
|
-
help: WIRE_HELP_POINTER,
|
|
948
|
-
tools_available: toolsAvailableMsg(resumedStatus),
|
|
949
|
-
};
|
|
950
|
-
// Include "while you were away" summary if available
|
|
951
|
-
if (resumed.since_last_session) {
|
|
952
|
-
const sls = resumed.since_last_session;
|
|
953
|
-
const parts = [];
|
|
954
|
-
if (sls.new_messages > 0)
|
|
955
|
-
parts.push(`${sls.new_messages} new message${sls.new_messages !== 1 ? 's' : ''}`);
|
|
956
|
-
if (sls.new_tasks > 0)
|
|
957
|
-
parts.push(`${sls.new_tasks} new task${sls.new_tasks !== 1 ? 's' : ''}`);
|
|
958
|
-
if (sls.new_contributions > 0)
|
|
959
|
-
parts.push(`${sls.new_contributions} new contribution${sls.new_contributions !== 1 ? 's' : ''}`);
|
|
960
|
-
if (sls.credits_earned > 0)
|
|
961
|
-
parts.push(`${sls.credits_earned} credits earned`);
|
|
962
|
-
if (parts.length > 0) {
|
|
963
|
-
resumeResponse.while_you_were_away = `While you were away: ${parts.join(', ')}.`;
|
|
964
|
-
}
|
|
965
|
-
resumeResponse.since_last_session = sls;
|
|
966
|
-
}
|
|
967
1095
|
return {
|
|
968
|
-
content: [{ type: 'text', text: JSON.stringify(
|
|
1096
|
+
content: [{ type: 'text', text: JSON.stringify(buildResumeResponse({
|
|
1097
|
+
requestedName: params.name,
|
|
1098
|
+
pseudoId: resumed.pseudo_id,
|
|
1099
|
+
operatorEmail: params.operator_email,
|
|
1100
|
+
verificationStatus: resumedStatus,
|
|
1101
|
+
sinceLastSession: resumed.since_last_session,
|
|
1102
|
+
}), null, 2) }],
|
|
969
1103
|
};
|
|
970
1104
|
}
|
|
971
1105
|
// Case B: Name doesn't match + create_new → register
|
|
@@ -1586,16 +1720,23 @@ export async function startMcpServer(options) {
|
|
|
1586
1720
|
dir: z.string().describe('Absolute path to local directory'),
|
|
1587
1721
|
corpus: z.string().describe('Wire corpus slug'),
|
|
1588
1722
|
action: z.enum(['diff', 'push', 'pull', 'preview']).describe('Sync action to perform'),
|
|
1723
|
+
publish: z.boolean().optional().describe('Legacy push only: publish new document versions instead of drafts'),
|
|
1724
|
+
market_native_docs_ingest: z.enum(['off', 'auto', 'all']).optional().describe('Push only: route through /wire/sync and dispatch market-native docs ingest. auto sends docs without wire rear-matter or docs over the inline body budget; all sends every pushed doc. Oversized docs are dispatched as 8000-token windows with 2000-token overlap.'),
|
|
1589
1725
|
}, async (params) => {
|
|
1590
1726
|
const gate = await requireConfirmed();
|
|
1591
1727
|
if (gate)
|
|
1592
1728
|
return { content: [gate], isError: true };
|
|
1593
1729
|
try {
|
|
1594
1730
|
const { dir, corpus, action } = params;
|
|
1731
|
+
const publish = params.publish ?? false;
|
|
1732
|
+
const marketNativeDocsIngest = (params.market_native_docs_ingest ?? 'off');
|
|
1595
1733
|
// ── Path traversal protection ──
|
|
1596
1734
|
if (!isAbsolute(dir)) {
|
|
1597
1735
|
return { content: [{ type: 'text', text: 'Error: dir must be an absolute path' }], isError: true };
|
|
1598
1736
|
}
|
|
1737
|
+
if (marketNativeDocsIngest !== 'off' && action === 'pull') {
|
|
1738
|
+
return { content: [{ type: 'text', text: 'Error: market_native_docs_ingest only applies to push-side sync' }], isError: true };
|
|
1739
|
+
}
|
|
1599
1740
|
const BLOCKED_PREFIXES = ['/etc', '/var', '/sys', '/proc', '/dev', '/root/.ssh'];
|
|
1600
1741
|
const normalizedDir = dir.replace(/\/+$/, ''); // strip trailing slashes
|
|
1601
1742
|
if (BLOCKED_PREFIXES.some(prefix => normalizedDir === prefix || normalizedDir.startsWith(prefix + '/'))) {
|
|
@@ -1652,7 +1793,10 @@ export async function startMcpServer(options) {
|
|
|
1652
1793
|
if (action === 'push') {
|
|
1653
1794
|
// Push new + updated files, but surface conflicts separately
|
|
1654
1795
|
const entriesToPush = [...diff.push_new, ...diff.push_update];
|
|
1655
|
-
const pushResults = await pushFiles(api, corpus, entriesToPush
|
|
1796
|
+
const pushResults = await pushFiles(api, corpus, entriesToPush, {
|
|
1797
|
+
publish,
|
|
1798
|
+
marketNativeDocsIngest,
|
|
1799
|
+
});
|
|
1656
1800
|
// Build manifest update entries from successful pushes
|
|
1657
1801
|
const manifestEntries = pushResults
|
|
1658
1802
|
.filter(r => r.success)
|
|
@@ -1664,9 +1808,9 @@ export async function startMcpServer(options) {
|
|
|
1664
1808
|
documentId: r.documentId,
|
|
1665
1809
|
localHash: localFile.hash,
|
|
1666
1810
|
remoteHash: localFile.hash, // after push, remote matches local
|
|
1667
|
-
remoteStatus: 'draft',
|
|
1811
|
+
remoteStatus: (publish || marketNativeDocsIngest !== 'off' ? 'published' : 'draft'),
|
|
1668
1812
|
remoteAnchored: false,
|
|
1669
|
-
remoteVersionNumber: entry.remoteDoc?.version_number ?? 1,
|
|
1813
|
+
remoteVersionNumber: r.version ?? entry.remoteDoc?.version_number ?? 1,
|
|
1670
1814
|
remoteWordCount: localFile.content.split(/\s+/).length,
|
|
1671
1815
|
};
|
|
1672
1816
|
});
|
|
@@ -1682,6 +1826,7 @@ export async function startMcpServer(options) {
|
|
|
1682
1826
|
const output = {
|
|
1683
1827
|
action: 'push',
|
|
1684
1828
|
corpus_slug: corpus,
|
|
1829
|
+
market_native_docs_ingest: marketNativeDocsIngest,
|
|
1685
1830
|
results: pushResults,
|
|
1686
1831
|
conflicts: diff.conflicts,
|
|
1687
1832
|
summary: {
|
|
@@ -2102,6 +2247,7 @@ export async function startMcpServer(options) {
|
|
|
2102
2247
|
input: z.record(z.unknown()).optional().describe('Input data for the action'),
|
|
2103
2248
|
max_cost: z.number().optional().describe('Maximum credits to spend (>= 1)'),
|
|
2104
2249
|
quote_id: z.string().optional().describe('JWT token from a prior quote call. Pass with mode=trusted to purchase and execute at the guaranteed price.'),
|
|
2250
|
+
timeout_ms: z.number().int().positive().optional().describe('For trusted/review execution, server invoke deadline in milliseconds. Defaults to 600000; public ceiling is 1800000.'),
|
|
2105
2251
|
}, async (params) => {
|
|
2106
2252
|
const gate = await requireConfirmed();
|
|
2107
2253
|
if (gate)
|
|
@@ -2122,6 +2268,7 @@ export async function startMcpServer(options) {
|
|
|
2122
2268
|
max_cost: z.number().optional().describe('Maximum credits to spend (>= 1)'),
|
|
2123
2269
|
chain_id: z.string().optional().describe('Chain UUID to continue (omit to start a new chain)'),
|
|
2124
2270
|
quote_id: z.string().optional().describe('JWT token from a prior quote call. Pass with mode=trusted to purchase and execute at the guaranteed price.'),
|
|
2271
|
+
timeout_ms: z.number().int().positive().optional().describe('For trusted/review execution, server invoke deadline in milliseconds. Defaults to 600000; public ceiling is 1800000.'),
|
|
2125
2272
|
}, async (params) => {
|
|
2126
2273
|
const gate = await requireConfirmed();
|
|
2127
2274
|
if (gate)
|
|
@@ -2143,6 +2290,8 @@ export async function startMcpServer(options) {
|
|
|
2143
2290
|
quote_id: z.string().optional().describe('Required with mode=trusted. JWT token returned by mode=quote.'),
|
|
2144
2291
|
entry_mode: z.enum(['start', 'direct']).optional().describe('start = run from step 1. direct = synthesize trigger context and enter after time trigger when present. Defaults to direct.'),
|
|
2145
2292
|
include_steps: z.boolean().optional().describe('Include step_results in execute response'),
|
|
2293
|
+
async_ack: z.boolean().optional().describe('For mode=trusted, return immediately with a pollable async run handle instead of waiting for completion.'),
|
|
2294
|
+
timeout_ms: z.number().int().positive().optional().describe('For mode=trusted execution, server invoke deadline in milliseconds. Defaults to 600000; public ceiling is 1800000. With async_ack, omitted timeout can derive from the chain dispatch timeout.'),
|
|
2146
2295
|
}, async (params) => {
|
|
2147
2296
|
const gate = await requireConfirmed();
|
|
2148
2297
|
if (gate)
|
|
@@ -2155,6 +2304,26 @@ export async function startMcpServer(options) {
|
|
|
2155
2304
|
return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
|
|
2156
2305
|
}
|
|
2157
2306
|
});
|
|
2307
|
+
server.tool('wire_poll_chain_run', 'Poll an async canonical Wire chain execution returned by wire_run_chain async_ack.', {
|
|
2308
|
+
chain: z.string().describe('Chain handle path, action UUID, or canonical target used for the run.'),
|
|
2309
|
+
run_handle_path: z.string().optional().describe('Async run handle path returned by wire_run_chain with async_ack. Prefer this over run_id.'),
|
|
2310
|
+
run_id: z.string().optional().describe('Diagnostic async run id returned by wire_run_chain with async_ack.'),
|
|
2311
|
+
include_steps: z.boolean().optional().describe('Include step_results when the run is complete.'),
|
|
2312
|
+
}, async (params) => {
|
|
2313
|
+
const gate = await requireConfirmed();
|
|
2314
|
+
if (gate)
|
|
2315
|
+
return { content: [gate], isError: true };
|
|
2316
|
+
try {
|
|
2317
|
+
if (!params.run_handle_path && !params.run_id) {
|
|
2318
|
+
return { content: [{ type: 'text', text: 'run_handle_path or run_id is required' }], isError: true };
|
|
2319
|
+
}
|
|
2320
|
+
const result = await api.pollChainRun(params);
|
|
2321
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
2322
|
+
}
|
|
2323
|
+
catch (err) {
|
|
2324
|
+
return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
|
|
2325
|
+
}
|
|
2326
|
+
});
|
|
2158
2327
|
// ── wire_resolve_handle removed — absorbed into wire_inspect ────────
|
|
2159
2328
|
// ── Tool: wire_supersede ───────────────────────────────────────────
|
|
2160
2329
|
server.tool('wire_supersede', 'Manage supersession chains. Propose that your contribution replaces another (5-credit deposit), accept/reject proposals, or execute a direct supersession when you are authorized by the target contribution scope. Proposer deposit returned on accept, forfeited on reject.', {
|