Skip to content

Commit ed9efc9

Browse files
authored
Merge pull request #6 from AElfProject/codex/skill-unified-upgrade-20260227
Codex/skill unified upgrade 20260227
2 parents 93ecbe1 + 5d24c91 commit ed9efc9

30 files changed

Lines changed: 1243 additions & 49 deletions

.github/workflows/test.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ jobs:
2424

2525
- run: bun install
2626
- run: bun run deps:check
27+
- name: Typecheck (observe)
28+
continue-on-error: true
29+
run: bun run typecheck
2730
- run: bun run test:coverage:ci
2831
- run: bun run build:openclaw:check
2932

README.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,9 @@ Reference file: [`mcp-config.example.json`](./mcp-config.example.json)
9393
"command": "bun",
9494
"args": ["run", "/ABSOLUTE/PATH/TO/src/mcp/server.ts"],
9595
"env": {
96-
"AELF_PRIVATE_KEY": "your_private_key_here"
96+
"AELF_PRIVATE_KEY": "optional_env_fallback_private_key",
97+
"PORTKEY_WALLET_PASSWORD": "optional_wallet_password",
98+
"PORTKEY_CA_KEYSTORE_PASSWORD": "optional_keystore_password"
9799
}
98100
}
99101
}
@@ -108,8 +110,13 @@ Copy and edit:
108110
cp .env.example .env
109111
```
110112

111-
- `AELF_PRIVATE_KEY`: required for write operations
112-
- `AELF_PRIVATE_KEY` is read from environment only in MCP mode (no private key tool input)
113+
- `AELF_PRIVATE_KEY`: optional env fallback for write operations (highest env priority)
114+
- `PORTKEY_PRIVATE_KEY`: optional secondary env fallback for shared-skill compatibility
115+
- Write tools (`aelf_send_contract_transaction`, `aelf_estimate_transaction_fee`) resolve signer as `explicit -> context -> env`
116+
- `PORTKEY_WALLET_PASSWORD`: optional password cache for EOA wallet context
117+
- `PORTKEY_CA_KEYSTORE_PASSWORD`: optional password cache for CA keystore context
118+
- `PORTKEY_SKILL_WALLET_CONTEXT_PATH`: optional override for active context path (`~/.portkey/skill-wallet/context.v1.json`)
119+
- `signerMode=daemon` is reserved and currently returns `SIGNER_DAEMON_NOT_IMPLEMENTED`
113120
- `AELF_NODE_AELF_RPC_URL`: optional override for AELF node
114121
- `AELF_NODE_TDVV_RPC_URL`: optional override for tDVV node
115122
- `AELF_NODE_REGISTRY_PATH`: optional custom registry path
@@ -153,6 +160,7 @@ bun run test:coverage:ci
153160
## Security
154161

155162
- Never put `AELF_PRIVATE_KEY` in prompts or channel outputs.
163+
- Active wallet context must not contain plaintext private keys.
156164
- Use environment variables for all secrets.
157165

158166
## License

README.zh-CN.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,9 @@ aelf-node-setup claude
9393
"command": "bun",
9494
"args": ["run", "/ABSOLUTE/PATH/TO/src/mcp/server.ts"],
9595
"env": {
96-
"AELF_PRIVATE_KEY": "your_private_key_here"
96+
"AELF_PRIVATE_KEY": "可选_env_回退私钥",
97+
"PORTKEY_WALLET_PASSWORD": "可选钱包密码",
98+
"PORTKEY_CA_KEYSTORE_PASSWORD": "可选keystore密码"
9799
}
98100
}
99101
}
@@ -108,8 +110,13 @@ aelf-node-setup claude
108110
cp .env.example .env
109111
```
110112

111-
- `AELF_PRIVATE_KEY`:写操作必填
112-
- MCP 模式仅从环境变量读取 `AELF_PRIVATE_KEY`(不接受 tool 入参传私钥)
113+
- `AELF_PRIVATE_KEY`:写操作的 env 回退私钥(可选,env 优先级最高)
114+
- `PORTKEY_PRIVATE_KEY`:共享 skill 兼容的次级 env 回退私钥(可选)
115+
- 写操作工具(`aelf_send_contract_transaction``aelf_estimate_transaction_fee`)按 `explicit -> context -> env` 解析 signer
116+
- `PORTKEY_WALLET_PASSWORD`:EOA wallet context 的密码缓存(可选)
117+
- `PORTKEY_CA_KEYSTORE_PASSWORD`:CA keystore context 的密码缓存(可选)
118+
- `PORTKEY_SKILL_WALLET_CONTEXT_PATH`:active context 路径覆盖(默认 `~/.portkey/skill-wallet/context.v1.json`
119+
- `signerMode=daemon` 仅预埋接口,本轮返回 `SIGNER_DAEMON_NOT_IMPLEMENTED`
113120
- `AELF_NODE_AELF_RPC_URL`:可选,覆盖 AELF 节点
114121
- `AELF_NODE_TDVV_RPC_URL`:可选,覆盖 tDVV 节点
115122
- `AELF_NODE_REGISTRY_PATH`:可选,自定义节点注册表路径
@@ -153,6 +160,7 @@ bun run test:coverage:ci
153160
## 安全
154161

155162
- 不要在对话输出中暴露 `AELF_PRIVATE_KEY`
163+
- Active wallet context 不存明文私钥。
156164
- 所有密钥均通过环境变量管理。
157165

158166
## License

SKILL.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,25 @@ description: "AElf node querying and contract execution skill for agents."
1212
- Chain reads: status, block, transaction result, metadata
1313
- Contract operations: view call and transaction sending
1414
- Node registry import/list with REST-first and SDK fallback strategy
15+
- Shared signer resolution for write operations: `explicit -> context -> env`
1516
- Supports SDK, CLI, MCP, and OpenClaw integration from one codebase.
1617

1718
## Safe usage rules
1819
- Never print private keys, mnemonics, or tokens in channel outputs.
1920
- For write operations, require explicit user confirmation and validate parameters before sending transactions.
2021
- Prefer `simulate` or read-only queries first when available.
22+
- Active wallet context contains identity metadata only; never persist plaintext private keys.
2123

2224
## Command recipes
2325
- Start MCP server: `bun run mcp`
2426
- Run CLI entry: `bun run cli`
2527
- Generate OpenClaw config: `bun run build:openclaw`
2628
- Verify OpenClaw config: `bun run build:openclaw:check`
2729
- Run CI coverage gate: `bun run test:coverage:ci`
30+
- For write calls, pass optional `signerContext` with `signerMode=auto`.
2831

2932
## Limits / Non-goals
3033
- This skill focuses on domain operations and adapters; it is not a full wallet custody system.
3134
- Do not hardcode environment secrets in source code or docs.
3235
- Avoid bypassing validation for external service calls.
36+
- `signerMode=daemon` is reserved and returns `SIGNER_DAEMON_NOT_IMPLEMENTED` in this release.

bun.lock

Lines changed: 6 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

index.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ export { importNode, listNodes } from './src/core/node-registry.js';
1414

1515
export { resolveNode, listAvailableNodes } from './lib/node-router.js';
1616
export { clearSdkCaches, clearSdkCacheForRpc } from './lib/sdk-client.js';
17+
export { resolvePrivateKeyContext, SignerContextError } from './lib/signer-context.js';
18+
export {
19+
readWalletContext,
20+
writeWalletContext,
21+
getActiveWalletProfile,
22+
setActiveWalletProfile,
23+
} from './lib/wallet-context.js';
1724
export type {
1825
SkillResponse,
1926
SkillError,
@@ -27,4 +34,13 @@ export type {
2734
EstimateTransactionFeeInput,
2835
ImportNodeInput,
2936
NodeProfile,
37+
SignerMode,
38+
SignerProvider,
39+
SignerContextInput,
3040
} from './lib/types.js';
41+
export type {
42+
WalletType,
43+
WalletSource,
44+
ActiveWalletProfile,
45+
WalletContextFile,
46+
} from './lib/wallet-context.js';

lib/aelf-sdk.d.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
declare module 'aelf-sdk' {
22
export interface AelfWallet {
33
address: string;
4+
privateKey: string;
5+
mnemonic?: string;
46
[key: string]: unknown;
57
}
68

@@ -36,6 +38,8 @@ declare module 'aelf-sdk' {
3638
export interface AelfWalletApi {
3739
createNewWallet(): AelfWallet;
3840
getWalletByPrivateKey(privateKey: string): AelfWallet;
41+
AESEncrypt(privateKey: string, password: string): string;
42+
AESDecrypt(encrypted: string, password: string): string;
3943
}
4044

4145
export interface AelfStaticApi {
@@ -53,3 +57,18 @@ declare module 'aelf-sdk' {
5357

5458
export default AElf;
5559
}
60+
61+
declare module "aelf-sdk/src/util/keyStore.js" {
62+
export function getKeystore(
63+
account: { privateKey: string; mnemonic?: string; address?: string; nickName?: string },
64+
password: string,
65+
option?: Record<string, unknown>,
66+
): unknown;
67+
export function unlockKeystore(keystore: unknown, password: string): {
68+
privateKey: string;
69+
mnemonic?: string;
70+
address?: string;
71+
nickName?: string;
72+
};
73+
export function checkPassword(keystore: unknown, password: string): boolean;
74+
}

lib/errors.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,17 @@ export function normalizeError(input: unknown, fallbackCode = 'UNKNOWN_ERROR'):
4444
}
4545

4646
if (input instanceof Error) {
47+
const maybeCode =
48+
typeof (input as { code?: unknown }).code === 'string'
49+
? String((input as { code?: unknown }).code)
50+
: '';
51+
const maybeDetails = (input as { details?: unknown }).details;
52+
const maybeRaw = (input as { raw?: unknown }).raw;
4753
return {
48-
code: fallbackCode,
54+
code: maybeCode || fallbackCode,
4955
message: input.message,
50-
raw: { name: input.name, stack: input.stack },
56+
details: maybeDetails !== undefined ? stringifyRaw(maybeDetails) : '',
57+
raw: maybeRaw !== undefined ? maybeRaw : { name: input.name, stack: input.stack },
5158
};
5259
}
5360

0 commit comments

Comments
 (0)