@zktx.io/sui-mcp 0.6.0 → 0.6.1

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.
Files changed (103) hide show
  1. package/README.md +18 -18
  2. package/dist/adapters/adapterPromptSurfaces.js +0 -20
  3. package/dist/adapters/deepbook/deepbookQuotePolicy.js +0 -4
  4. package/dist/adapters/deepbook/deepbookReviewEvidence.js +0 -9
  5. package/dist/adapters/deepbook/deepbookTransactionMaterialProducer.js +0 -9
  6. package/dist/adapters/intentPlanFactories.js +0 -6
  7. package/dist/core/action/contractNameRegistry.js +0 -53
  8. package/dist/core/action/forbiddenFields.js +0 -4
  9. package/dist/core/action/ptbVisualizationProducer.js +0 -3
  10. package/dist/core/action/receiptPtbGraph.js +0 -17
  11. package/dist/core/action/reviewTimeSimulationEvidence.js +0 -4
  12. package/dist/core/action/signableAdapterContract.js +0 -5
  13. package/dist/core/action/suiChainReceiptMapping.js +0 -18
  14. package/dist/core/action/suiChainReceiptReader.js +1 -21
  15. package/dist/core/action/suiChainReceiptVerifier.js +0 -10
  16. package/dist/core/action/transactionFunding.js +0 -7
  17. package/dist/core/action/types.js +0 -1
  18. package/dist/core/action/walletReviewContractAssembler.js +0 -2
  19. package/dist/core/activity/localDataService.js +0 -6
  20. package/dist/core/activity/sqliteActivityStore.js +0 -8
  21. package/dist/core/activity/sqliteActivityStoreRows.js +0 -2
  22. package/dist/core/activity/sqliteActivityStoreSchema.js +0 -4
  23. package/dist/core/read/deepbookReadHelpers.js +0 -2
  24. package/dist/core/read/deepbookRegistry.js +0 -19
  25. package/dist/core/read/deepbookUsdcChartService.js +0 -2
  26. package/dist/core/read/readCardResult.js +0 -2
  27. package/dist/core/read/readService.js +0 -19
  28. package/dist/core/read/readServiceTypes.js +0 -2
  29. package/dist/core/session/cardSession.js +0 -4
  30. package/dist/core/session/cardSessionStore.js +1 -4
  31. package/dist/core/session/reviewValidity.js +0 -3
  32. package/dist/core/session/sessionRecordStore.js +0 -1
  33. package/dist/core/session/sessionStore.js +0 -15
  34. package/dist/core/session/settingsFileIdentity.js +0 -2
  35. package/dist/core/session/settingsFileProtocol.js +0 -5
  36. package/dist/core/session/settingsFileStore.js +1 -10
  37. package/dist/core/session/settingsInputError.js +0 -2
  38. package/dist/core/session/settingsOperation.js +0 -4
  39. package/dist/core/session/settingsPreparationSql.js +0 -2
  40. package/dist/core/session/settingsWorkflow.js +1 -37
  41. package/dist/core/session/sqliteCardStore.js +0 -2
  42. package/dist/core/session/sqliteSessionStore.js +0 -11
  43. package/dist/core/session/sqliteSettingsWorkflowStore.js +0 -10
  44. package/dist/core/session/sqliteTransactionMaterialStore.js +0 -11
  45. package/dist/core/session/sqliteWalletWorkflowStore.js +0 -29
  46. package/dist/core/session/status.js +0 -2
  47. package/dist/core/session/transactionMaterialStore.js +0 -4
  48. package/dist/core/session/transactionRequest.js +0 -4
  49. package/dist/core/session/walletConnection.js +0 -3
  50. package/dist/core/session/walletWorkflow.js +3 -21
  51. package/dist/core/session/workflowState.js +0 -8
  52. package/dist/core/session/workflowView.js +0 -6
  53. package/dist/core/suiAddress.js +0 -5
  54. package/dist/core/suiEndpoint.js +0 -3
  55. package/dist/mcp/prompts.js +0 -12
  56. package/dist/mcp/schemas.js +0 -3
  57. package/dist/mcp/tools/action/prepareSuiActionReview.js +0 -6
  58. package/dist/mcp/tools/read/serverStatusTools.js +0 -1
  59. package/dist/mcp/tools/session/shared.js +0 -2
  60. package/dist/mcp/tools/session/statusTools.js +0 -2
  61. package/dist/mcp-app/account.html +1 -1
  62. package/dist/mcp-app/chart.html +6 -6
  63. package/dist/mcp-app/connect.html +6 -6
  64. package/dist/mcp-app/receipt.html +298 -298
  65. package/dist/mcp-app/review.html +237 -237
  66. package/dist/mcp-app/settings.html +1 -1
  67. package/dist/mcp-ui/tools.js +3 -4
  68. package/dist/review-server/server.js +0 -2
  69. package/dist/runtime/application.js +1 -1
  70. package/dist/runtime/config.js +0 -2
  71. package/dist/runtime/localSettingsService.js +0 -3
  72. package/dist/runtime/logger.js +0 -2
  73. package/dist/runtime/reviewServerAcquire.js +1 -18
  74. package/dist/runtime/runtimeTermination.js +1 -4
  75. package/dist/runtime/shared/authenticatedFetch.js +0 -6
  76. package/dist/runtime/shared/control.js +0 -2
  77. package/dist/runtime/shared/dataAccess.js +0 -2
  78. package/dist/runtime/shared/mcpHttp.js +0 -5
  79. package/dist/runtime/shared/ownerLease.js +0 -4
  80. package/dist/runtime/shared/server.js +0 -1
  81. package/dist/runtime/shared/stdio.js +2 -5
  82. package/dist/runtime/smokeMainnetRead.js +0 -2
  83. package/dist/runtime/smokeReview.js +0 -4
  84. package/dist/runtime/start.js +0 -2
  85. package/dist/runtime/suiTransactionGraphqlMapping.js +0 -2
  86. package/dist/runtime/suiTransactionGraphqlQueries.js +0 -3
  87. package/dist/runtime/walletConnectConfig.js +0 -2
  88. package/dist/runtime/walletConnectStorage.js +0 -6
  89. package/dist/runtime/walletConnectTransport.js +0 -11
  90. package/dist/runtime/walletSdkChildRuntime.js +0 -5
  91. package/dist/runtime/walletSdkProcess.js +0 -6
  92. package/docs/AGENT_BEHAVIOR.md +1 -5
  93. package/docs/LOCAL_DB_ARCHITECTURE.md +3 -3
  94. package/docs/MCP_SETUP.md +14 -14
  95. package/docs/MCP_TOOLS.md +15 -0
  96. package/docs/SDK_API.md +12 -0
  97. package/docs/WALLET_CONNECTION.md +2 -1
  98. package/package.json +10 -2
  99. package/docs/AGENT_DEVELOPMENT_POLICY.md +0 -819
  100. package/docs/FRONTEND_POLICY.md +0 -611
  101. package/docs/golden-scenarios/BEHAVIOR_MATRIX.md +0 -166
  102. package/docs/golden-scenarios/INTENT_EVIDENCE_GOLDEN_ANSWERS.md +0 -161
  103. package/docs/golden-scenarios/INTENT_EVIDENCE_MATRIX.md +0 -259
@@ -4,8 +4,6 @@ import { SqliteCardRecordStore } from "./sqliteCardStore.js";
4
4
  import { SettingsConflict, settingsDownload, storedSettingsDownloadSchema, settingsDraftSchema, settingsResultSchema, retainedBackupRejection } from "./settingsOperation.js";
5
5
  import { isSettingsDownloadFile, settingsBackupPath, SETTINGS_FILE_CLEANUP_SQL } from "./settingsFileIdentity.js";
6
6
  import { SETTINGS_REUSABLE_UPLOAD_SQL, SETTINGS_RESET_PREPARATION_SQL } from "./settingsPreparationSql.js";
7
- /** Settings transitions share the activity owner's SQLite connection and card CAS.
8
- * Network and filesystem work must remain outside these transactions. */
9
7
  export class SqliteSettingsWorkflowStore {
10
8
  db;
11
9
  ownerId;
@@ -118,7 +116,6 @@ export class SqliteSettingsWorkflowStore {
118
116
  const control = this.control();
119
117
  return this.fileIOAvailable(control) && (control.active_operation_id === null || control.active_operation_id === operationId);
120
118
  }
121
- // Read-only eligibility check shared by preparation and final admission.
122
119
  requireFinalSlot(replaceId) {
123
120
  const control = this.control();
124
121
  if (!this.fileIOAvailable(control) || control.active_operation_id !== (replaceId ?? null)) {
@@ -145,8 +142,6 @@ export class SqliteSettingsWorkflowStore {
145
142
  return next;
146
143
  });
147
144
  }
148
- // Pure admission checks let deadline reconciliation commit an expected refusal
149
- // without claiming a final slot or consuming input. Admission uses the same rule.
150
145
  requireAdmission(expected, input, currentFingerprint, replaceOperationId, now = this.now()) {
151
146
  const result = this.requireInput(expected, input.operationId, now), operation = result.operation;
152
147
  if (operation.phase !== "prepared" || !operation.draft || operation.preparationId !== input.preparationId ||
@@ -212,8 +207,6 @@ export class SqliteSettingsWorkflowStore {
212
207
  if (!isDeepStrictEqual(this.get(expected.operationId), expected) || expected.draft?.kind !== "download_backup") {
213
208
  throw new SettingsConflict("The download state changed before it could be saved.");
214
209
  }
215
- // A terminal result is immutable serialized evidence. Updating delivery
216
- // state must not reserialize it, even with semantically identical keys.
217
210
  this.db.prepare("UPDATE settings_operations SET preparation_json=? WHERE operation_id=?")
218
211
  .run(JSON.stringify({ download }), expected.operationId);
219
212
  if (!this.cards.replace(card, { ...card, state: { ...card.state, revision: card.state.revision + 1 } })) {
@@ -259,7 +252,6 @@ export class SqliteSettingsWorkflowStore {
259
252
  }
260
253
  continueDownload(expected, input) {
261
254
  return this.transaction(() => {
262
- // Validate the caller's scope before any target reads or expiry writes.
263
255
  this.downloadContext(expected, input.operationId, input.fileId);
264
256
  this.expireDownloads(input.operationId);
265
257
  const { card, operation, file, download } = this.downloadContext(expected, input.operationId, input.fileId);
@@ -454,8 +446,6 @@ export class SqliteSettingsWorkflowStore {
454
446
  }
455
447
  }
456
448
  }
457
- // The input is already a strict typed action. Sort object keys recursively so
458
- // JSON-RPC ids and object insertion order never change business idempotency.
459
449
  export function settingsIdentity(value) {
460
450
  const canonical = (input) => Array.isArray(input) ? input.map(canonical) : input !== null && typeof input === "object"
461
451
  ? Object.fromEntries(Object.entries(input).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, item]) => [key, canonical(item)])) : input;
@@ -1,13 +1,4 @@
1
1
  import { buildTransactionMaterialRecord, sameHandle, toMaterialHandle } from "./transactionMaterialStore.js";
2
- /**
3
- * SQLite-backed transaction material store. Holds the same synchronous contract as
4
- * InMemoryLocalTransactionMaterialStore so producers and the wallet handoff path are
5
- * unchanged, but persists records (including the unsigned transaction BLOB) to the
6
- * shared local database so any review-server process can read them. Validation,
7
- * handle identity, and expiry semantics are shared via transactionMaterialStore.ts,
8
- * so the two backends never drift. The unsigned bytes are protected at rest by the
9
- * data directory (0700) and database file (0600) permissions set in SqliteActivityStore.
10
- */
11
2
  export class SqliteTransactionMaterialStore {
12
3
  db;
13
4
  constructor(db) {
@@ -44,8 +35,6 @@ export class SqliteTransactionMaterialStore {
44
35
  this.db.prepare(`DELETE FROM live_transaction_materials WHERE review_session_id = ?`).run(reviewSessionId);
45
36
  }
46
37
  }
47
- // Each read rebuilds a fresh record (new Uint8Array from the BLOB, parsed
48
- // diagnostics) so a caller mutating the result never touches the stored row.
49
38
  function recordFromRow(row) {
50
39
  return {
51
40
  materialId: row.material_id,
@@ -34,8 +34,6 @@ const preparationInterruptionReasons = {
34
34
  wallet_service_restarted: "The wallet service was restarted. Update this review before requesting approval.",
35
35
  wallet_service_lost: "The wallet service stopped. Restore the wallet connection and update this review before requesting approval."
36
36
  };
37
- /** Purpose-specific mutations on the activity owner's connection. Each method
38
- * commits card, request and public history together; no network work runs here. */
39
37
  export class SqliteWalletWorkflowStore {
40
38
  db;
41
39
  ownerId;
@@ -103,8 +101,6 @@ export class SqliteWalletWorkflowStore {
103
101
  return recovery;
104
102
  }
105
103
  recordWalletFailure(input) {
106
- // Retried by the workflow until revocation is durably recorded. The SDK
107
- // run is already fenced, so a failed write cannot preserve usable authority.
108
104
  this.invalidateWalletRun("wallet_service_lost", new Date(input.observedAt), input.runId);
109
105
  }
110
106
  publishWalletState() { this.publishAvailableWallets(); }
@@ -115,8 +111,6 @@ export class SqliteWalletWorkflowStore {
115
111
  continue;
116
112
  const observed = snapshot.sessions.find((item) => item.topic === record.topic);
117
113
  if (record.connection.status !== "connected") {
118
- // Startup can transfer management ownership; ordinary observations
119
- // update the current run's facts without restoring terminal authority.
120
114
  if ((ready || record.ownerId === this.ownerId && record.runId === snapshot.runId) &&
121
115
  observed?.status === "present" && !record.sdkPending &&
122
116
  !this.pendingDisconnect(record.connection.connectionId, record.ownerId)) {
@@ -208,8 +202,6 @@ export class SqliteWalletWorkflowStore {
208
202
  return { confirmed: true, connections, unrecorded, pendingConnectionIds };
209
203
  }
210
204
  readConnectionFacts(now) {
211
- // A deferred read transaction reuses an outer admission transaction when
212
- // present. It never repairs callbacks, advances deadlines or reserves I/O.
213
205
  return this.db.transaction(() => {
214
206
  const records = this.connections(), snapshot = this.readSdkSnapshot(), account = this.readActiveAccount();
215
207
  return { evaluatedAt: now.toISOString(), activeAccount: account?.address, activeAccountConnectionId: account?.walletId,
@@ -239,9 +231,6 @@ export class SqliteWalletWorkflowStore {
239
231
  if (!card || card.ownerId !== this.ownerId || card.operationId !== id || card.acceptedInput?.action !== source.action ||
240
232
  card.acceptedInput.walletRunId !== source.runId)
241
233
  return;
242
- // A connection may progress from pairing to one admitted disconnect.
243
- // That later operation owns sdk_pending even if its result is already
244
- // visible and the original pairing's failed cleanup write arrives late.
245
234
  const disconnect = this.db.prepare(`SELECT id FROM live_read_cards WHERE owner_id=? AND scope='connect' AND operation_id=?
246
235
  AND json_extract(accepted_input_json,'$.action')='disconnect'`).get(this.ownerId, id);
247
236
  if (source.action === "connect" && disconnect && disconnect.id !== source.cardId)
@@ -314,8 +303,6 @@ export class SqliteWalletWorkflowStore {
314
303
  if (card.state.kind === "review" && !session)
315
304
  throw new WorkflowConflict("The saved review is unavailable.");
316
305
  const connection = card.state.kind === "connect" && card.operationId ? this.connection(card.operationId)?.connection : undefined;
317
- // Wallet-dependent commands already passed the workflow availability guard.
318
- // This store checks DB eligibility; it does not measure SDK health.
319
306
  const connectionFacts = this.readConnectionFacts(now), targetAccount = session?.account ?? connectionFacts.activeAccount;
320
307
  const facts = { ...connectionFacts, ownerId: this.ownerId, record: card, session, request,
321
308
  authority: request ? this.authority(request.attemptId) : undefined, connection,
@@ -380,8 +367,6 @@ export class SqliteWalletWorkflowStore {
380
367
  WHERE operation_id=@id`).run({ terminal: terminal ? 1 : 0, id: operationId });
381
368
  }
382
369
  publishConnection(connectionId, status) {
383
- // Connection updates are not completion of every operation referencing it.
384
- // In particular, session_update(connected) must not finish a pending disconnect.
385
370
  const outcome = this.connection(connectionId)?.connection;
386
371
  this.db.prepare(`UPDATE live_read_cards SET revision=revision+1,
387
372
  result_json=CASE WHEN state='running' AND json_extract(accepted_input_json,'$.action')='disconnect'
@@ -447,8 +432,6 @@ export class SqliteWalletWorkflowStore {
447
432
  this.db.prepare("INSERT INTO live_wallet_connections (id,owner_id,status,revision,topic,sdk_pending,connection_json,run_id) VALUES (?,?,?,?,?,?,?,?)")
448
433
  .run(connection.connectionId, this.ownerId, connection.status, 0, null, 1, JSON.stringify(connection), this.runId ?? null);
449
434
  this.consume(card, input, connection.connectionId);
450
- // Every other live input observes the admitted connection before the SDK
451
- // responds, so an older selection cannot bypass the one-connection rule.
452
435
  this.publishAvailableWallets();
453
436
  return this.connection(connection.connectionId);
454
437
  }).immediate();
@@ -494,7 +477,6 @@ export class SqliteWalletWorkflowStore {
494
477
  owner_id=excluded.owner_id, status=excluded.status, revision=excluded.revision, topic=excluded.topic,
495
478
  sdk_pending=0, connection_json=excluded.connection_json,run_id=excluded.run_id`).run(id, this.ownerId, next.status, next.revision, session.topic, 0, JSON.stringify(next), this.runId ?? null);
496
479
  this.publishConnection(id, next.status);
497
- // Restoring the SDK session never restores a cleared read-account context.
498
480
  return this.connection(id);
499
481
  }
500
482
  useAccount(expected, input, connectionId, account) {
@@ -532,7 +514,6 @@ export class SqliteWalletWorkflowStore {
532
514
  finishDisconnect(cardId, connectionId, succeeded, now) {
533
515
  this.db.transaction(() => {
534
516
  const pending = this.pendingDisconnect(connectionId);
535
- // A session deletion event may have already completed this operation.
536
517
  if (pending?.state.cardId !== cardId)
537
518
  return;
538
519
  this.updateConnection(connectionId, succeeded ? { status: "disconnected" } : {
@@ -587,8 +568,6 @@ export class SqliteWalletWorkflowStore {
587
568
  const artifacts = new SqlitePrivateReviewArtifactStore(this.db).get(material.reviewSessionId);
588
569
  const stored = this.materialStore.getTransactionMaterial(material.transactionMaterial, now);
589
570
  if (!current || !materialStillMatches(material, current, sessions.revision(current.id), artifacts, stored, now)) {
590
- // Expected expiry commits its normal cleanup, but no request authority.
591
- // A changed candidate is a conflict and must not invalidate newer data.
592
571
  const evaluated = this.evaluateState({ purpose: "review", reviewSessionId: material.reviewSessionId,
593
572
  readTarget: this.reviewReadTarget(material.reviewSessionId, card), expectedCard: card, candidate: { session: material.review, rowRevision: material.rowRevision,
594
573
  artifacts: material.artifacts, material }, walletAvailability: { status: "available", walletRunId } }, now);
@@ -709,8 +688,6 @@ export class SqliteWalletWorkflowStore {
709
688
  if (old.requestStatus === "awaiting_signature" && next !== old.requestStatus)
710
689
  this.publishAvailableWallets();
711
690
  if (["stopped", "request_failed", "outcome_unknown", "completed"].includes(next)) {
712
- // A historical attempt may finish while a newer review is preparing.
713
- // Clean only the material still owned by this admitted revision.
714
691
  for (const table of ["live_transaction_materials", "live_private_review_artifacts"]) {
715
692
  this.db.prepare(`DELETE FROM ${table} WHERE review_session_id=? AND EXISTS
716
693
  (SELECT 1 FROM live_review_sessions WHERE id=? AND review_revision=? AND preparation_id IS NULL)`)
@@ -741,8 +718,6 @@ export class SqliteWalletWorkflowStore {
741
718
  this.db.transaction(() => {
742
719
  const now = this.clock();
743
720
  this.advanceRequestDeadlines(now, id);
744
- // Observation may have finished, or its window may have closed, while
745
- // submit was pending. A late response cannot reopen either outcome.
746
721
  if (this.request(id)?.requestStatus === "submitting")
747
722
  this.transitionRequest(id, "awaiting_chain_result", now);
748
723
  }).immediate();
@@ -757,8 +732,6 @@ export class SqliteWalletWorkflowStore {
757
732
  return request;
758
733
  if (request.requestStatus === "awaiting_signature")
759
734
  return this.transitionRequest(id, cause === "wallet_service_lost" ? "request_failed" : "stopped", now, { reason: interruptionReasons[cause] });
760
- // Once submitted, connection changes cannot revoke a transaction or the
761
- // independent lookup of its digest. Only explicit user stopping ends observation.
762
735
  if (cause === "user_stop" && authority.observation_stopped === 0 &&
763
736
  ["submitting", "awaiting_chain_result", "outcome_unknown"].includes(request.requestStatus)) {
764
737
  this.db.prepare("UPDATE live_request_authority SET observation_stopped=1 WHERE attempt_id=?").run(id);
@@ -778,8 +751,6 @@ export class SqliteWalletWorkflowStore {
778
751
  .all(connectionId, this.ownerId, runId ?? null, runId ?? null);
779
752
  for (const row of rows) {
780
753
  const state = row.review_state_json ? JSON.parse(row.review_state_json) : undefined;
781
- // Later session observations cannot rewrite why an already interrupted
782
- // preparation ended. A new admitted preparation clears this error.
783
754
  if (!row.preparation_id && row.preparation_error && !state?.transactionReviewData)
784
755
  continue;
785
756
  if (state) {
@@ -32,8 +32,6 @@ export function isInteractionPendingReviewStatus(status) {
32
32
  return executionStatusCategory(status) !== "final";
33
33
  }
34
34
  export function isReviewInteractionPending({ hasReviewInput, request, progress }) {
35
- // Historical preparation state is not proof that a live input remains.
36
- // Consumed input, in turn, does not end its admitted request or observation.
37
35
  return hasReviewInput || progress.status !== "idle" || !!request && isRequestWaiting(request.requestStatus);
38
36
  }
39
37
  export function executionPollingHint() {
@@ -115,9 +115,6 @@ export class LocalTransactionMaterialStoreError extends Error {
115
115
  super(message);
116
116
  }
117
117
  }
118
- // Validate the store input and build the stored record (with cloned bytes). Shared
119
- // by every LocalTransactionMaterialStore implementation so validation never drifts
120
- // between the in-memory and SQLite backends.
121
118
  export function buildTransactionMaterialRecord(input, now = new Date()) {
122
119
  const account = parseSuiAddress(input.account);
123
120
  if (!account) {
@@ -158,7 +155,6 @@ export function buildTransactionMaterialRecord(input, now = new Date()) {
158
155
  : { redactedDiagnostics: structuredClone(input.redactedDiagnostics) })
159
156
  };
160
157
  }
161
- // Project the public (redacted) handle out of a stored record.
162
158
  export function toMaterialHandle(record) {
163
159
  return {
164
160
  materialId: record.materialId,
@@ -6,14 +6,10 @@ export const TRANSACTION_REQUEST_STATUSES = [
6
6
  "request_failed", "outcome_unknown", "completed"
7
7
  ];
8
8
  export const transactionRequestStatusSchema = z.enum(TRANSACTION_REQUEST_STATUSES);
9
- // The submission was admitted durably before external I/O. A failed follow-up
10
- // write must not remove its initial observation window or replacement guard.
11
9
  export const INITIAL_CHAIN_OBSERVATION_STATUSES = ["submitting", "awaiting_chain_result"];
12
10
  export function isInitialChainObservation(status) {
13
11
  return INITIAL_CHAIN_OBSERVATION_STATUSES.some((value) => value === status);
14
12
  }
15
- // This is the existing signing surface's local wait, independent of protocol
16
- // request expiry, card input expiry and the chain observation window.
17
13
  export const SIGNATURE_WAIT_MS = 90_000;
18
14
  export const CHAIN_RECEIPT_LOOKUP_MAX_AGE_MS = 10 * 60 * 1000;
19
15
  export const transactionExecutionSummarySchema = z.object({
@@ -46,7 +46,6 @@ export function workflowProgress(waiting, requiresWallet, availability) {
46
46
  export const walletConnectionStatusSchema = z.enum([
47
47
  "awaiting_approval", "connected", "rejected", "failed", "expired", "stopped", "disconnected"
48
48
  ]);
49
- // Recorded recovery facts, not proof of a currently usable wallet connection.
50
49
  export const walletRecoveryImpactSchema = z.object({
51
50
  runId: z.string().uuid(),
52
51
  connections: z.array(z.object({ connectionId: z.string().min(1), revision: z.number().int().nonnegative(),
@@ -104,8 +103,6 @@ export function walletConnectionSelection(connections, at, presence, stored) {
104
103
  export class WalletUserRejectedError extends Error {
105
104
  constructor() { super("The wallet request was rejected by the user."); }
106
105
  }
107
- // Shared recorded connection facts only. Each operation checks its own expiry,
108
- // account, method and revision requirements at its decision boundary.
109
106
  export function isOwnedConnectedWallet(record, ownerId, disconnectPending) {
110
107
  return !!record && record.ownerId === ownerId && record.connection.status === "connected" && !disconnectPending;
111
108
  }
@@ -19,8 +19,6 @@ export class WalletWorkflow {
19
19
  observing = new Map();
20
20
  preparing = new Set();
21
21
  pendingWrites = new Map();
22
- // Child exit ends child I/O, not verification or submit work already running
23
- // in this parent. The owning signature continuation alone ends that work.
24
22
  parentSignatureWork = new Set();
25
23
  eventListener;
26
24
  settingsRecovery;
@@ -47,7 +45,7 @@ export class WalletWorkflow {
47
45
  report(stage) { try {
48
46
  this.options.logger.error("Wallet operation failed", { stage });
49
47
  }
50
- catch { /* SQLite owns outcomes. */ } }
48
+ catch { } }
51
49
  async start() {
52
50
  this.assertCurrent();
53
51
  if (this.started)
@@ -130,7 +128,6 @@ export class WalletWorkflow {
130
128
  this.retainWrite(completion);
131
129
  }
132
130
  retainWrite(completion) {
133
- // An old data generation cannot add repair work to the replacement data.
134
131
  try {
135
132
  this.assertCurrent();
136
133
  }
@@ -173,8 +170,6 @@ export class WalletWorkflow {
173
170
  failure = error;
174
171
  }
175
172
  }
176
- // A completed callback's pending flag is housekeeping, not authority to
177
- // read recorded facts. Retain failed repairs for the next applicable read.
178
173
  if (failure && walletDependent)
179
174
  throw failure;
180
175
  if (walletDependent)
@@ -210,14 +205,10 @@ export class WalletWorkflow {
210
205
  walletObservation: state.walletObservation, manageableConnectionIds: state.manageableConnectionIds,
211
206
  connectionReconciliationRequired: state.connectionReconciliationRequired, assetReadAccount: state.assetReadAccount ?? { status: "address_required" } };
212
207
  }
213
- // Diagnostic facts are collected without maintenance. Reconciliation and
214
- // admission own durable transitions and cannot use this snapshot as authority.
215
208
  currentConnectionContext() {
216
209
  this.assertCurrent();
217
210
  const facts = this.options.records.readConnectionFacts(this.now()), availability = this.walletAvailability();
218
211
  const { selection: _selection, ...eligibility } = workflowConnectionEligibility({ ...facts, walletAvailability: availability });
219
- // The shared projection gates qualification on published availability;
220
- // a memory snapshot alone does not prove its journal/result has committed.
221
212
  return { connections: facts.connections, walletAvailability: availability, walletObservation: facts.walletObservation,
222
213
  connectionConflict: eligibility.connectionConflict, manageableConnectionIds: eligibility.manageableConnectionIds,
223
214
  connectionReconciliationRequired: eligibility.connectionReconciliationRequired,
@@ -231,7 +222,6 @@ export class WalletWorkflow {
231
222
  const pending = this.options.records.pendingDisconnect(record.connection.connectionId);
232
223
  if (!pending)
233
224
  continue;
234
- // Disabled transports also return undefined; that is not session absence.
235
225
  const absent = available && !!record.topic && this.observed(record.topic)?.status === "absent";
236
226
  this.options.records.recoverDisconnect(pending.state.cardId, record.connection.connectionId, record.connection.revision, absent);
237
227
  }
@@ -263,8 +253,6 @@ export class WalletWorkflow {
263
253
  if (explicitResult) {
264
254
  await this.observing.get(state.request.attemptId);
265
255
  this.assertCurrent();
266
- // An awaited receipt may have committed new facts. Return one freshly
267
- // evaluated snapshot; ordinary status reads do not await external I/O.
268
256
  state = await this.evaluateReview(id, undefined, false, state.request.attemptId);
269
257
  }
270
258
  }
@@ -447,8 +435,6 @@ export class WalletWorkflow {
447
435
  catch (error) {
448
436
  displayFailure = error;
449
437
  }
450
- // The approval remains pending even if setup/QR recording fails or the
451
- // wallet dependency is disabled. Settle only after that promise ends.
452
438
  const session = await result.approval;
453
439
  if (displayFailure)
454
440
  throw displayFailure;
@@ -552,8 +538,6 @@ export class WalletWorkflow {
552
538
  return;
553
539
  }
554
540
  catch (error) {
555
- // SDK verification can itself depend on a remote source. An exception is
556
- // not proof of a mismatched transaction or signer.
557
541
  if (!this.stopped)
558
542
  this.options.records.transitionRequest(request.attemptId, "request_failed", this.now(), {
559
543
  reason: this.walletAvailability().status !== "available" ? "Wallet operations became unavailable before submission. The returned signature will not be submitted."
@@ -564,7 +548,7 @@ export class WalletWorkflow {
564
548
  try {
565
549
  await this.options.submitTransaction(bytes, response.signature);
566
550
  }
567
- catch { /* A lost submit response is not proof of failure. Observe the same digest. */ }
551
+ catch { }
568
552
  finally {
569
553
  this.completeCallback({ kind: "request", id: request.attemptId, field: "submit_pending" });
570
554
  }
@@ -585,8 +569,6 @@ export class WalletWorkflow {
585
569
  const current = this.options.records.request(id);
586
570
  if (!current || !(isInitialChainObservation(current.requestStatus) || explicit && current.requestStatus === "outcome_unknown"))
587
571
  return;
588
- // Starting another lookup needs its own previous callback to be settled.
589
- // Stored terminal facts above never depend on this write succeeding.
590
572
  for (const [key, write] of this.pendingWrites)
591
573
  if (write.kind === "request" && write.id === id && write.field === "lookup_pending") {
592
574
  this.settlePendingWrite(key, write);
@@ -607,7 +589,7 @@ export class WalletWorkflow {
607
589
  if (receipt.status === "found")
608
590
  details = projectReadCardResult("receipt", { digest: request.transactionDigest }, receipt);
609
591
  }
610
- catch { /* Keep verified chain facts if the additional display read is unavailable. */ }
592
+ catch { }
611
593
  }
612
594
  this.assertCurrent();
613
595
  this.options.records.transitionRequest(id, "completed", this.now(), { execution: {
@@ -2,8 +2,6 @@ import { walletConnectionSelection } from "./walletConnection.js";
2
2
  import { isInitialChainObservation } from "./transactionRequest.js";
3
3
  export const workflowActions = ["connect", "disconnect", "use_account", "stop_connection", "prepare_review",
4
4
  "request_signature", "cancel", "stop_waiting", "read_result"];
5
- // Read context may change; an existing review's account binding may not.
6
- // Both evaluated choices and admission consume this relation with current facts.
7
5
  export function reviewPreparationAccount(boundAccount, activeAccount, selectedAccount = activeAccount) {
8
6
  if (!activeAccount)
9
7
  return { allowed: false, message: "No account from a connected wallet is selected for this review." };
@@ -23,18 +21,12 @@ export function workflowConnectionEligibility(facts) {
23
21
  : usableConnectionId ? selection.assetReadAccount : { status: "address_required" };
24
22
  return { selection, usableConnectionId, assetReadAccount, connectionConflict: selection.conflict,
25
23
  manageableConnectionIds: available ? selection.manageableConnectionIds : [],
26
- // A pending memory snapshot is not a published SDK observation. Startup
27
- // and state-sync failures retain their own result and neutral diagnosis.
28
24
  connectionReconciliationRequired: available && dependent ? selection.connectionReconciliationRequired : undefined };
29
25
  }
30
- // Shared domain eligibility. The DB supplies current facts at its decision
31
- // boundary. Returned choices are advisory; admission still binds concrete input.
32
26
  export function workflowEligibility(facts) {
33
27
  const { record, session, request, authority, walletAvailability } = facts;
34
28
  const at = Date.parse(facts.evaluatedAt);
35
29
  const cardRemaining = record?.ownerId === facts.ownerId ? Math.max(0, Date.parse(record.state.expiresAt) - at) : 0;
36
- // A later-created input card cannot extend its review session. Admitted
37
- // requests and management cards retain their separate observation authority.
38
30
  const remaining = record?.scope === "review" && session && !request
39
31
  ? Math.min(cardRemaining, Math.max(0, Date.parse(session.expiresAt) - at)) : cardRemaining;
40
32
  const inputAvailable = remaining > 0 && record?.state.state === "ready" && record.acceptedInput === undefined;
@@ -9,7 +9,6 @@ import { reviewProgress, EXECUTION_POLLING_INTERVAL_SECONDS } from "./status.js"
9
9
  import { walletRunIdSchema, walletRecoverySchema, walletObservationSchema } from "./walletRuntime.js";
10
10
  export const CONNECT_BOUNDARY = "A wallet connection provides account context; it is not a transaction approval or proof of address ownership.";
11
11
  export const REVIEW_BOUNDARY = "Review evidence is not a safety guarantee. Only an explicit card action and wallet approval may authorize this exact transaction.";
12
- // A projection of an admitted card operation, not a new wallet connection state.
13
12
  export const connectionViewSchema = walletConnectionSchema.extend({ pendingAction: z.literal("disconnect").optional() });
14
13
  export { assetReadAccountSchema } from "./walletConnection.js";
15
14
  export const pendingConnectionStatusSchema = z.enum(["input_required", "awaiting_approval", "disconnect_pending"]);
@@ -80,8 +79,6 @@ export const workflowViewSchema = z.object({
80
79
  context.addIssue({ code: "custom", path: ["assetReadAccount"], message: "The default address must belong to the usable connection and stored selection." });
81
80
  }
82
81
  });
83
- // Automatic preparation uses the same current selection and typed admission as
84
- // a deliberate retry. A failed computation is not a reason to compute in a loop.
85
82
  function automaticReviewAction(input) {
86
83
  const { record, session, request } = input;
87
84
  if (!session || record?.scope !== "review" || request || session.preparationError ||
@@ -98,7 +95,6 @@ function automaticReviewAction(input) {
98
95
  return { action: "prepare_review", walletRunId: input.walletAvailability.walletRunId, connectionId: candidates[0].connectionId,
99
96
  account, reviewRevision: session.reviewRevision };
100
97
  }
101
- // Method support filters wallet choices; it does not authorize a signature.
102
98
  export function reviewWalletChoices(selection, account, requireSigningMethod = false) {
103
99
  return selection.connections.filter((item) => item.connectionId === selection.usableConnectionId && item.accounts.includes(account) &&
104
100
  (!requireSigningMethod || item.methods.includes("sui_signTransaction")));
@@ -112,8 +108,6 @@ function nextStateRead(input) {
112
108
  .filter((value) => value !== undefined && value > 0);
113
109
  return delays.length ? Math.min(...delays) : undefined;
114
110
  }
115
- // These projections do not read clocks, storage, or admission rules. The
116
- // evaluated facts and choices were collected together by the database owner.
117
111
  export function projectConnectionView(input) {
118
112
  const { walletAvailability } = input;
119
113
  const stored = input.record?.state.data;
@@ -1,13 +1,8 @@
1
1
  import { isValidSuiAddress, isValidTransactionDigest, normalizeSuiAddress } from "@mysten/sui/utils";
2
2
  import { z } from "zod";
3
- // Use the string-only schema at MCP/HTTP output boundaries because zod transforms
4
- // cannot be represented in MCP JSON Schema. Use the normalized schema for values
5
- // before storing them as local session state.
6
3
  export const suiAddressStringSchema = z
7
4
  .string()
8
5
  .refine(isValidSuiAddress, "Expected a 32-byte Sui address");
9
- // Shared Sui transaction digest schema (pinned SDK source of truth). Used at
10
- // MCP/HTTP boundaries and by the signable-adapter commitment fields.
11
6
  export const suiTransactionDigestSchema = z
12
7
  .string()
13
8
  .refine(isValidTransactionDigest, "Expected a Sui transaction digest");
@@ -35,9 +35,6 @@ export function parseGrpcUrl(value) {
35
35
  }
36
36
  return `${parsed.protocol}//${authority}`;
37
37
  }
38
- // GraphQL endpoints commonly include a path such as /graphql and may omit an
39
- // explicit port. gRPC endpoints stay stricter because the pinned gRPC client
40
- // runtime expects only scheme, host, and explicit port.
41
38
  export function parseGraphqlUrl(value) {
42
39
  let parsed;
43
40
  if (value.length > MAX_SUI_GRAPHQL_URL_LENGTH) {
@@ -24,9 +24,6 @@ export const MCP_PROMPTS = [
24
24
  ].join("\n")
25
25
  }
26
26
  ];
27
- // Platform-owned boundary language appended to every adapter prompt surface.
28
- // Adapters contribute copy about their own action only; they cannot weaken
29
- // or omit these lines.
30
27
  const PLATFORM_PROMPT_BOUNDARY_LINES = [
31
28
  "Present the internal Review card and summarize the returned review checks.",
32
29
  "This MCP response never contains signing data, transaction bytes, or signing readiness; only an explicit UI action and wallet approval authorize the backend request; request status is separate from server-verified chain execution facts."
@@ -76,18 +73,9 @@ export function registerMcpPrompts(server, surfaces = []) {
76
73
  ]
77
74
  }));
78
75
  }
79
- // Adapter prompt surfaces: action-first names (`swap-deep`) with one
80
- // free-text intent argument so clients can pass the whole request in one
81
- // line (Claude Code: /mcp__sui-mcp__swap-deep 10 sui to usdc;
82
- // Claude Desktop shows a single input field). The model parses the
83
- // intent; this server never does.
84
76
  for (const surface of surfaces) {
85
77
  registerSurfacePrompt(server, promptNameFor(surface), surface, surface.description);
86
78
  }
87
- // Bare action prompts are always registered. One protocol: straight to it.
88
- // Several protocols: an optional `protocol` argument (completion suggests
89
- // the slugs) and explicit instructions to ask the user - the venue is the
90
- // user's choice, never the server's.
91
79
  for (const [action, group] of actionGroups(surfaces)) {
92
80
  registerBareActionPrompt(server, action, group);
93
81
  }
@@ -1,7 +1,4 @@
1
1
  import { z } from "zod";
2
- // No-parameter tools. The `.optional()` is load-bearing: it lets the tool be called with
3
- // no arguments at all (undefined args validate). A bare `{}`/`z.object({})` would instead
4
- // REQUIRE an (empty) object and reject an argument-less call, so this is not a no-op.
5
2
  export const noParamsInputSchema = z.object({}).optional();
6
3
  export function successOutputSchema(dataShape) {
7
4
  return {
@@ -32,12 +32,6 @@ export function registerActionTools(server, deps) {
32
32
  if (!supportsCards(server))
33
33
  return errorToolResult({ kind: "ui_unavailable", details: { reason: "An internal review card is required." } });
34
34
  const now = new Date();
35
- // A swap review is account-bound: its evidence (balances, transaction
36
- // material, digest, simulation) is computed for a specific sender, and
37
- // no transaction can be built without that account. Refuse here when no
38
- // wallet account is connected instead of creating a hollow proposal that
39
- // can never be computed or signed. Connect first via
40
- // session.create_wallet_connection.
41
35
  let activeAccount;
42
36
  try {
43
37
  activeAccount = await deps.activityStore.getActiveAccount();
@@ -5,7 +5,6 @@ import { MCP_PROMPTS } from "../../prompts.js";
5
5
  import { MCP_RESOURCES } from "../../resources.js";
6
6
  import { EVIDENCE_POLICY, FAIL_CLOSED_TOOLS, IMPLEMENTED_TOOLS, PACKAGE_NAME, SERVER_LIMITATIONS, SERVER_NAME, SERVER_NETWORK, SERVER_RUNTIME, SERVER_TRANSPORT, SERVER_VERSION } from "../../serverInfo.js";
7
7
  import { TOOL_NAMES } from "../../toolNames.js";
8
- // Executable swap adapters precede protocol-notes-only entries.
9
8
  export const SUPPORTED_PROTOCOLS = [
10
9
  { id: "deepbook-v3", status: "mainnet", support: "read_and_local_review" },
11
10
  { id: "deepbook-margin", status: "mainnet", support: "protocol_notes_only" }
@@ -27,8 +27,6 @@ export function latest(items) {
27
27
  const sorted = [...items].sort((left, right) => right.lastActivityAt.localeCompare(left.lastActivityAt));
28
28
  return { limit: INTERACTION_STATUS_LIMIT, items: sorted.slice(0, INTERACTION_STATUS_LIMIT), truncated: sorted.length > INTERACTION_STATUS_LIMIT };
29
29
  }
30
- // Runtime workflows own reconciliation/observation. A server without a wallet
31
- // workflow can still expose ordinary preparation facts, with explicit absence.
32
30
  export async function readCurrentReview(deps, id, explicitResult = false) {
33
31
  if (deps.workflow)
34
32
  return deps.workflow.readReview(id, explicitResult);
@@ -34,8 +34,6 @@ export function registerSessionStatusTools(server, deps) {
34
34
  return activityStoreToolError(error, deps.logger);
35
35
  }
36
36
  try {
37
- // Connection reconciliation can invalidate reviews and interrupt requests.
38
- // Complete that maintenance before projecting its dependent review facts.
39
37
  const context = deps.workflow?.reconcileConnectionContext() ?? { connections: [], manageableConnectionIds: [],
40
38
  assetReadAccount: { status: "address_required" }, walletAvailability: walletUnavailable("initialization_failed") };
41
39
  const connections = deps.workflow?.pendingConnections() ?? [];