Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 136 additions & 0 deletions reference/codemods/wraith-sdk-v0-to-v1.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
"use strict";

/**
* jscodeshift transform: Wraith SDK v0.x → v1.x
*
* Handles all public symbol renames from the v1 API-stability sweep (issue #6).
*
* Transforms applied:
* - Import renames: ChainEnum → Chain, WraithClientConfig → WraithConfig,
* CreateAgentOptions → AgentConfig
* - Method call renames: agent.sendMessage() → agent.chat()
* agent.payments() → agent.scanPayments()
* agent.balance() → agent.getBalance()
* agent.conversations() → agent.getConversations()
* agent.messages() → agent.getMessages()
* - Method call renames + await removal: wraith.getAgent() → wraith.agent()
*
* Usage:
* npx jscodeshift \
* --transform reference/codemods/wraith-sdk-v0-to-v1.cjs \
* --extensions ts,tsx,js,jsx \
* src/
*
* The transform is idempotent — running it twice produces the same result.
*
* Limitations:
* - Dynamic property access (`agent["sendMessage"]`) is not transformed.
* - If your variable holding a WraithAgent is not named `agent`, the method
* renames still apply because this transform rewrites ALL calls matching
* the old method name on ANY object. Review the diff carefully.
* - The `await wraith.getAgent()` removal only strips `await` when the call
* is directly awaited (i.e., `await wraith.getAgent(id)`). If you stored
* the promise and awaited it separately, update that manually.
*/

const IMPORT_RENAMES = {
ChainEnum: "Chain",
WraithClientConfig: "WraithConfig",
CreateAgentOptions: "AgentConfig",
};

/** Method renames applied to any object. */
const METHOD_RENAMES = {
sendMessage: "chat",
payments: "scanPayments",
balance: "getBalance",
conversations: "getConversations",
messages: "getMessages",
};

/** Methods that should also have `await` stripped from the call expression. */
const SYNC_METHODS = new Set(["getAgent"]);
const SYNC_METHOD_RENAMES = {
getAgent: "agent",
};

/**
* @param {import("jscodeshift").FileInfo} file
* @param {import("jscodeshift").API} api
* @returns {string}
*/
module.exports = function transform(file, api) {
const j = api.jscodeshift;
const root = j(file.source);
let changed = false;

// ─── 1. Rename imported specifiers ───────────────────────────────────────
root
.find(j.ImportDeclaration, { source: { value: "@wraith-protocol/sdk" } })
.forEach((importDecl) => {
importDecl.node.specifiers.forEach((specifier) => {
if (
specifier.type === "ImportSpecifier" &&
IMPORT_RENAMES[specifier.imported.name]
) {
const oldName = specifier.imported.name;
const newName = IMPORT_RENAMES[oldName];

// Rename the imported binding in all usages throughout the file.
root
.find(j.Identifier, { name: oldName })
.forEach((identPath) => {
// Skip the import declaration itself — we handle it below.
if (
identPath.parent.node.type === "ImportSpecifier" &&
identPath.parent.node.imported === identPath.node
) {
return;
}
identPath.node.name = newName;
changed = true;
});

// Rename the import specifier and its local alias if they match.
if (specifier.local.name === oldName) {
specifier.local.name = newName;
}
specifier.imported.name = newName;
changed = true;
}
});
});

// ─── 2. Rename method calls ───────────────────────────────────────────────
root.find(j.CallExpression).forEach((callPath) => {
const callee = callPath.node.callee;

if (callee.type !== "MemberExpression") return;
if (callee.computed) return; // skip obj["method"]() — dynamic access
if (callee.property.type !== "Identifier") return;

const methodName = callee.property.name;

// Ordinary method renames (no await removal).
if (METHOD_RENAMES[methodName]) {
callee.property.name = METHOD_RENAMES[methodName];
changed = true;
return;
}

// Methods that become synchronous: rename + strip surrounding await.
if (SYNC_METHODS.has(methodName)) {
callee.property.name = SYNC_METHOD_RENAMES[methodName];
changed = true;

// Strip `await` if this call is the direct operand of an AwaitExpression.
const parent = callPath.parent;
if (parent && parent.node.type === "AwaitExpression") {
// Replace the AwaitExpression with the unwrapped CallExpression.
j(parent).replaceWith(callPath.node);
}
}
});

return changed ? root.toSource({ quote: "double" }) : file.source;
};
125 changes: 125 additions & 0 deletions reference/codemods/wraith-v1-codemod.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
---
title: "Codemod: Wraith SDK v0 → v1"
description: "jscodeshift transform that automates all Wraith SDK v1 renames"
---

A single [jscodeshift](https://github.com/facebook/jscodeshift) transform that automates every rename from the [v1 migration guide](/reference/migrating-to-v1).

The transform is located at `reference/codemods/wraith-sdk-v0-to-v1.cjs` in this repository. It is safe to run multiple times — running it on already-migrated code is a no-op.

## What It Transforms

| Old (v0.x) | New (v1.x) | Transform type |
|---|---|---|
| `import { ChainEnum }` | `import { Chain }` | Import rename + usages |
| `import { WraithClientConfig }` | `import { WraithConfig }` | Import rename + usages |
| `import { CreateAgentOptions }` | `import { AgentConfig }` | Import rename + usages |
| `agent.sendMessage(` | `agent.chat(` | Method call rename |
| `await wraith.getAgent(id)` | `wraith.agent(id)` | Method rename + `await` removal |
| `agent.payments(` | `agent.scanPayments(` | Method call rename |
| `agent.balance(` | `agent.getBalance(` | Method call rename |
| `agent.conversations(` | `agent.getConversations(` | Method call rename |
| `agent.messages(` | `agent.getMessages(` | Method call rename |

## Install

```bash
npm install --save-dev jscodeshift
```

## Run

Apply all transforms to your source directory:

```bash
npx jscodeshift \
--transform reference/codemods/wraith-sdk-v0-to-v1.cjs \
--extensions ts,tsx,js,jsx \
src/
```

Add `--dry` to preview changes without writing:

```bash
npx jscodeshift \
--transform reference/codemods/wraith-sdk-v0-to-v1.cjs \
--extensions ts,tsx,js,jsx \
--dry \
src/
```

## Example Input / Output

### Import renames

```typescript no-check
// Input
import { ChainEnum, WraithClientConfig, CreateAgentOptions } from "@wraith-protocol/sdk";

const config: WraithClientConfig = { apiKey: process.env.WRAITH_KEY };
const opts: CreateAgentOptions = {
name: "alice",
chain: ChainEnum.Stellar,
wallet: walletAddress,
signature: sig,
};
```

```typescript no-check
// Output
import { Chain, WraithConfig, AgentConfig } from "@wraith-protocol/sdk";

const config: WraithConfig = { apiKey: process.env.WRAITH_KEY };
const opts: AgentConfig = {
name: "alice",
chain: Chain.Stellar,
wallet: walletAddress,
signature: sig,
};
```

### Method renames

```typescript no-check
// Input
const agent = await wraith.getAgent("agent-uuid-here");
const res = await agent.sendMessage("what's my balance?");
const payments = await agent.payments();
const balance = await agent.balance();
const convs = await agent.conversations();
const msgs = await agent.messages(convId);
```

```typescript no-check
// Output
const agent = wraith.agent("agent-uuid-here");
const res = await agent.chat("what's my balance?");
const payments = await agent.scanPayments();
const balance = await agent.getBalance();
const convs = await agent.getConversations();
const msgs = await agent.getMessages(convId);
```

## Limitations

The transform does not cover:

- **Dynamic property access** — `agent["sendMessage"]()` is not transformed. Update these manually.
- **Destructured method references** — `const { sendMessage } = agent` is not transformed. Update these manually.
- **Non-direct awaits** — if you stored the `getAgent` promise before awaiting it, the `await` is not removed:
```typescript no-check
// NOT transformed — update manually
const p = wraith.getAgent(id);
const agent = await p;
```
- **Stellar SDK v13 changes** — `SorobanRpc` → `rpc`, `signAuthEntries` parameter rename, `Memo` validation, and `SentTransaction` constructor are not covered. See the [migration guide](/reference/migrating-to-v1) for those.

## Verifying the Output

After running the codemod, run TypeScript to catch any remaining issues:

```bash
npx tsc --noEmit
```

TypeScript will flag any `ChainEnum`, `WraithClientConfig`, or `CreateAgentOptions` references that the codemod missed (e.g., in string-typed JSDoc or dynamic access).
Loading
Loading