@sofer_agent/cli 0.3.0 → 0.3.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.
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +71 -70
- package/dist/init.js.map +1 -1
- package/package.json +2 -1
- package/src/init.ts +90 -92
package/dist/init.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AA2BA;;;;;GAKG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAkLjD"}
|
package/dist/init.js
CHANGED
|
@@ -1,22 +1,5 @@
|
|
|
1
|
+
import { cancel, intro, isCancel, note, outro, password, select, spinner, } from "@clack/prompts";
|
|
1
2
|
import { AgentClient, agentPaths, generateKeypair, keypairFromSecret, loadConfig, makeSuiClient, provisionMemwal, requestFaucet, shortAgentId, suiBalance, waitForBalance, writePersistedConfig, writeSecret, } from "@sofer_agent/core";
|
|
2
|
-
/** Simple spinner that logs to stdout. */
|
|
3
|
-
function spin(label, fn) {
|
|
4
|
-
process.stdout.write(`${label}… `);
|
|
5
|
-
return fn().then((result) => {
|
|
6
|
-
console.log("done");
|
|
7
|
-
return result;
|
|
8
|
-
}, (err) => {
|
|
9
|
-
console.log("failed");
|
|
10
|
-
throw err;
|
|
11
|
-
});
|
|
12
|
-
}
|
|
13
|
-
async function ask(question) {
|
|
14
|
-
const rl = await import("node:readline/promises");
|
|
15
|
-
const iface = rl.createInterface({ input: process.stdin, output: process.stdout });
|
|
16
|
-
const answer = await iface.question(question);
|
|
17
|
-
iface.close();
|
|
18
|
-
return answer.trim();
|
|
19
|
-
}
|
|
20
3
|
/**
|
|
21
4
|
* Interactive init wizard — mint the agent + provision Walrus memory.
|
|
22
5
|
* Stores config to ~/.sofer/config.json and secrets to ~/.sofer/{sui,brain}.key
|
|
@@ -32,37 +15,52 @@ export async function initCommand() {
|
|
|
32
15
|
console.log(` sui key: ${agentPaths.suiKey}`);
|
|
33
16
|
console.log(` brain key: ${agentPaths.brainKey}`);
|
|
34
17
|
console.log(` agent: ${existing.agentObjectId}`);
|
|
35
|
-
console.log(`
|
|
36
|
-
console.log(`\nRun \`sofer\` to chat. To start fresh, delete
|
|
18
|
+
console.log(` memory: ${existing.memwal.accountId}`);
|
|
19
|
+
console.log(`\nRun \`sofer\` to chat. To start fresh, delete ${agentPaths.root}/.`);
|
|
37
20
|
return;
|
|
38
21
|
}
|
|
39
|
-
|
|
40
|
-
console.log("║ sofer init — agent setup ║");
|
|
41
|
-
console.log("╚══════════════════════════════════════════╝\n");
|
|
22
|
+
intro("sofer init");
|
|
42
23
|
// ── 1. Network ─────────────────────────────────────────────────────────
|
|
43
|
-
const network = (await
|
|
24
|
+
const network = (await select({
|
|
25
|
+
message: "Which network?",
|
|
26
|
+
options: [
|
|
27
|
+
{ value: "testnet", label: "Sui Testnet" },
|
|
28
|
+
{ value: "mainnet", label: "Sui Mainnet" },
|
|
29
|
+
],
|
|
30
|
+
initialValue: "testnet",
|
|
31
|
+
}));
|
|
32
|
+
if (isCancel(network)) {
|
|
33
|
+
cancel("Aborted.");
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
44
36
|
const net = network === "mainnet" ? "mainnet" : "testnet";
|
|
45
|
-
console.log(` → ${net}\n`);
|
|
46
37
|
// ── 2. Anthropic API key ───────────────────────────────────────────────
|
|
47
|
-
const apiKey = await
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
38
|
+
const apiKey = (await password({
|
|
39
|
+
message: "Anthropic API key (stored in ~/.sofer/brain.key, never in .env)",
|
|
40
|
+
mask: "*",
|
|
41
|
+
}));
|
|
42
|
+
if (isCancel(apiKey) || !apiKey) {
|
|
43
|
+
cancel("API key is required.");
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
51
46
|
// ── 3. Sui wallet ─────────────────────────────────────────────────────
|
|
52
47
|
const existingSecret = process.env.SOFER_SUI_SECRET_KEY;
|
|
48
|
+
const sGen = spinner();
|
|
53
49
|
let secret;
|
|
54
50
|
let address;
|
|
55
51
|
if (existingSecret) {
|
|
52
|
+
sGen.start("Loading wallet from SOFER_SUI_SECRET_KEY");
|
|
56
53
|
const kp = keypairFromSecret(existingSecret);
|
|
57
54
|
secret = existingSecret;
|
|
58
55
|
address = kp.toSuiAddress();
|
|
59
|
-
|
|
56
|
+
sGen.stop(`wallet: ${address} (from env)`);
|
|
60
57
|
}
|
|
61
58
|
else {
|
|
59
|
+
sGen.start("Generating new Sui wallet");
|
|
62
60
|
const kp = generateKeypair();
|
|
63
61
|
secret = kp.getSecretKey();
|
|
64
62
|
address = kp.toSuiAddress();
|
|
65
|
-
|
|
63
|
+
sGen.stop(`wallet: ${address} (new)`);
|
|
66
64
|
}
|
|
67
65
|
const config = loadConfig();
|
|
68
66
|
const sui = makeSuiClient(config.network);
|
|
@@ -70,82 +68,87 @@ export async function initCommand() {
|
|
|
70
68
|
if (net !== "mainnet") {
|
|
71
69
|
const bal = await suiBalance(sui, address);
|
|
72
70
|
if (bal === 0n) {
|
|
73
|
-
|
|
71
|
+
const sFund = spinner();
|
|
72
|
+
sFund.start("Requesting testnet faucet");
|
|
74
73
|
try {
|
|
75
74
|
await requestFaucet(config.network, address);
|
|
76
75
|
await waitForBalance(sui, address, 1n);
|
|
77
|
-
|
|
76
|
+
sFund.stop("funded");
|
|
78
77
|
}
|
|
79
78
|
catch (e) {
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
sFund.stop(`faucet failed: ${String(e).slice(0, 80)}`);
|
|
80
|
+
note(`Fund ${address} at https://faucet.sui.io/ and re-run.`, "manual funding needed");
|
|
82
81
|
}
|
|
83
82
|
}
|
|
84
83
|
else {
|
|
85
|
-
|
|
84
|
+
note(`${(Number(bal) / 1e9).toFixed(4)} SUI on ${address}`, "wallet balance");
|
|
86
85
|
}
|
|
87
86
|
}
|
|
88
87
|
const agents = new AgentClient(sui, config.packageId);
|
|
89
88
|
// ── 5. Mint agent ─────────────────────────────────────────────────────
|
|
90
|
-
let agentId =
|
|
89
|
+
let agentId = existing.agentObjectId;
|
|
91
90
|
if (!agentId) {
|
|
92
|
-
|
|
91
|
+
const sMint = spinner();
|
|
92
|
+
sMint.start("Minting agent identity object on-chain");
|
|
93
93
|
try {
|
|
94
94
|
const keypair = keypairFromSecret(secret);
|
|
95
|
-
const minted = await
|
|
95
|
+
const minted = await agents.mint(keypair, "Sofer", "a sovereign AI agent on Sui with encrypted memory on Walrus", new TextEncoder().encode("sofer"));
|
|
96
96
|
agentId = minted.agentId;
|
|
97
|
-
|
|
97
|
+
sMint.stop(`agent: ${agentId}`);
|
|
98
98
|
}
|
|
99
99
|
catch (e) {
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
sMint.stop(`mint failed: ${String(e).slice(0, 120)}`);
|
|
101
|
+
cancel("Mint failed. Is the wallet funded?");
|
|
102
102
|
return;
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
else {
|
|
106
|
-
|
|
106
|
+
note(agentId, "reusing agent");
|
|
107
107
|
}
|
|
108
108
|
// ── 6. Provision MemWal memory ────────────────────────────────────────
|
|
109
|
-
let accountId =
|
|
110
|
-
let delegateKey =
|
|
109
|
+
let accountId = existing.memwal.accountId;
|
|
110
|
+
let delegateKey = existing.memwal.delegateKey;
|
|
111
111
|
if (!accountId || !delegateKey) {
|
|
112
|
-
|
|
112
|
+
const sMem = spinner();
|
|
113
|
+
sMem.start("Provisioning Walrus memory (MemWal)");
|
|
113
114
|
try {
|
|
114
|
-
const prov = await
|
|
115
|
+
const prov = await provisionMemwal({
|
|
115
116
|
ownerSecret: secret,
|
|
116
117
|
packageId: config.memwal.packageId,
|
|
117
118
|
registryId: config.memwal.registryId,
|
|
118
119
|
network: net,
|
|
119
120
|
label: "sofer-cli",
|
|
120
|
-
})
|
|
121
|
+
});
|
|
121
122
|
accountId = prov.accountId;
|
|
122
123
|
delegateKey = prov.delegateKey;
|
|
123
|
-
|
|
124
|
+
sMem.stop(`account: ${accountId}`);
|
|
124
125
|
}
|
|
125
126
|
catch (e) {
|
|
127
|
+
sMem.stop(`provision failed: ${String(e).slice(0, 120)}`);
|
|
126
128
|
const msg = String(e);
|
|
127
129
|
if (msg.includes("abort code: 3") || msg.includes("create_account")) {
|
|
128
|
-
|
|
129
|
-
"Delete ~/.sofer/ and re-run `sofer init`, or set the env vars manually.");
|
|
130
|
+
cancel("This wallet already owns a MemWal account.\nDelete ~/.sofer/ and re-run, or set env vars manually.");
|
|
130
131
|
}
|
|
131
|
-
|
|
132
|
+
return;
|
|
132
133
|
}
|
|
133
134
|
}
|
|
134
135
|
else {
|
|
135
|
-
|
|
136
|
+
note(accountId, "reusing memory account");
|
|
136
137
|
}
|
|
137
138
|
// ── 7. Link memory to agent on-chain ───────────────────────────────────
|
|
138
|
-
|
|
139
|
+
const sLink = spinner();
|
|
140
|
+
sLink.start("Linking memory account to agent on-chain");
|
|
139
141
|
try {
|
|
140
142
|
const keypair = keypairFromSecret(secret);
|
|
141
|
-
await
|
|
142
|
-
|
|
143
|
+
await agents.setMemoryAccount(keypair, agentId, accountId);
|
|
144
|
+
sLink.stop("linked");
|
|
143
145
|
}
|
|
144
146
|
catch (e) {
|
|
145
|
-
|
|
147
|
+
sLink.stop(`link failed (may already be linked): ${String(e).slice(0, 80)}`);
|
|
146
148
|
}
|
|
147
149
|
// ── 8. Persist config + secrets to ~/.sofer/ ───────────────────────────
|
|
148
|
-
|
|
150
|
+
const sSave = spinner();
|
|
151
|
+
sSave.start("Saving to ~/.sofer/");
|
|
149
152
|
writeSecret(agentPaths.suiKey, secret);
|
|
150
153
|
writeSecret(agentPaths.brainKey, apiKey);
|
|
151
154
|
const persisted = {
|
|
@@ -159,18 +162,16 @@ export async function initCommand() {
|
|
|
159
162
|
},
|
|
160
163
|
};
|
|
161
164
|
writePersistedConfig(persisted);
|
|
162
|
-
|
|
163
|
-
console.log(` config: ${agentPaths.config}`);
|
|
164
|
-
console.log(` keys: ${agentPaths.suiKey} / ${agentPaths.brainKey}`);
|
|
165
|
-
console.log(` agent: ${agentDir.dir}\n`);
|
|
165
|
+
sSave.stop(`config: ${agentPaths.config}`);
|
|
166
166
|
// ── 9. Summary ────────────────────────────────────────────────────────
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
167
|
+
const lines = [
|
|
168
|
+
`agent ${agentId.slice(0, 30)}…`,
|
|
169
|
+
`address ${address.slice(0, 10)}…`,
|
|
170
|
+
`network ${net}`,
|
|
171
|
+
`memory ${accountId.slice(0, 10)}…`,
|
|
172
|
+
"",
|
|
173
|
+
"Run `sofer` to chat with your agent.",
|
|
174
|
+
];
|
|
175
|
+
outro(lines.join("\n"));
|
|
175
176
|
}
|
|
176
177
|
//# sourceMappingURL=init.js.map
|
package/dist/init.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sofer_agent/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"sofer": "./dist/bin.js"
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"cli"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
+
"@clack/prompts": "^1.5.1",
|
|
28
29
|
"@sofer_agent/core": "0.3.0"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|
package/src/init.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cancel,
|
|
3
|
+
intro,
|
|
4
|
+
isCancel,
|
|
5
|
+
note,
|
|
6
|
+
outro,
|
|
7
|
+
password,
|
|
8
|
+
select,
|
|
9
|
+
spinner,
|
|
10
|
+
} from "@clack/prompts";
|
|
1
11
|
import {
|
|
2
12
|
type PersistedConfig,
|
|
3
|
-
type SoferConfig,
|
|
4
13
|
AgentClient,
|
|
5
14
|
agentPaths,
|
|
6
15
|
generateKeypair,
|
|
@@ -16,29 +25,6 @@ import {
|
|
|
16
25
|
writeSecret,
|
|
17
26
|
} from "@sofer_agent/core";
|
|
18
27
|
|
|
19
|
-
/** Simple spinner that logs to stdout. */
|
|
20
|
-
function spin<T>(label: string, fn: () => Promise<T>): Promise<T> {
|
|
21
|
-
process.stdout.write(`${label}… `);
|
|
22
|
-
return fn().then(
|
|
23
|
-
(result) => {
|
|
24
|
-
console.log("done");
|
|
25
|
-
return result;
|
|
26
|
-
},
|
|
27
|
-
(err) => {
|
|
28
|
-
console.log("failed");
|
|
29
|
-
throw err;
|
|
30
|
-
},
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async function ask(question: string): Promise<string> {
|
|
35
|
-
const rl = await import("node:readline/promises");
|
|
36
|
-
const iface = rl.createInterface({ input: process.stdin, output: process.stdout });
|
|
37
|
-
const answer = await iface.question(question);
|
|
38
|
-
iface.close();
|
|
39
|
-
return answer.trim();
|
|
40
|
-
}
|
|
41
|
-
|
|
42
28
|
/**
|
|
43
29
|
* Interactive init wizard — mint the agent + provision Walrus memory.
|
|
44
30
|
* Stores config to ~/.sofer/config.json and secrets to ~/.sofer/{sui,brain}.key
|
|
@@ -54,39 +40,55 @@ export async function initCommand(): Promise<void> {
|
|
|
54
40
|
console.log(` sui key: ${agentPaths.suiKey}`);
|
|
55
41
|
console.log(` brain key: ${agentPaths.brainKey}`);
|
|
56
42
|
console.log(` agent: ${existing.agentObjectId}`);
|
|
57
|
-
console.log(`
|
|
58
|
-
console.log(`\nRun \`sofer\` to chat. To start fresh, delete
|
|
43
|
+
console.log(` memory: ${existing.memwal.accountId}`);
|
|
44
|
+
console.log(`\nRun \`sofer\` to chat. To start fresh, delete ${agentPaths.root}/.`);
|
|
59
45
|
return;
|
|
60
46
|
}
|
|
61
47
|
|
|
62
|
-
|
|
63
|
-
console.log("║ sofer init — agent setup ║");
|
|
64
|
-
console.log("╚══════════════════════════════════════════╝\n");
|
|
48
|
+
intro("sofer init");
|
|
65
49
|
|
|
66
50
|
// ── 1. Network ─────────────────────────────────────────────────────────
|
|
67
|
-
const network = (await
|
|
51
|
+
const network = (await select({
|
|
52
|
+
message: "Which network?",
|
|
53
|
+
options: [
|
|
54
|
+
{ value: "testnet", label: "Sui Testnet" },
|
|
55
|
+
{ value: "mainnet", label: "Sui Mainnet" },
|
|
56
|
+
],
|
|
57
|
+
initialValue: "testnet",
|
|
58
|
+
})) as string | symbol;
|
|
59
|
+
if (isCancel(network)) {
|
|
60
|
+
cancel("Aborted.");
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
68
63
|
const net = network === "mainnet" ? "mainnet" : "testnet";
|
|
69
|
-
console.log(` → ${net}\n`);
|
|
70
64
|
|
|
71
65
|
// ── 2. Anthropic API key ───────────────────────────────────────────────
|
|
72
|
-
const apiKey = await
|
|
73
|
-
|
|
74
|
-
|
|
66
|
+
const apiKey = (await password({
|
|
67
|
+
message: "Anthropic API key (stored in ~/.sofer/brain.key, never in .env)",
|
|
68
|
+
mask: "*",
|
|
69
|
+
})) as string | symbol;
|
|
70
|
+
if (isCancel(apiKey) || !apiKey) {
|
|
71
|
+
cancel("API key is required.");
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
75
74
|
|
|
76
75
|
// ── 3. Sui wallet ─────────────────────────────────────────────────────
|
|
77
76
|
const existingSecret = process.env.SOFER_SUI_SECRET_KEY;
|
|
77
|
+
const sGen = spinner();
|
|
78
78
|
let secret: string;
|
|
79
79
|
let address: string;
|
|
80
80
|
if (existingSecret) {
|
|
81
|
+
sGen.start("Loading wallet from SOFER_SUI_SECRET_KEY");
|
|
81
82
|
const kp = keypairFromSecret(existingSecret);
|
|
82
83
|
secret = existingSecret;
|
|
83
84
|
address = kp.toSuiAddress();
|
|
84
|
-
|
|
85
|
+
sGen.stop(`wallet: ${address} (from env)`);
|
|
85
86
|
} else {
|
|
87
|
+
sGen.start("Generating new Sui wallet");
|
|
86
88
|
const kp = generateKeypair();
|
|
87
89
|
secret = kp.getSecretKey();
|
|
88
90
|
address = kp.toSuiAddress();
|
|
89
|
-
|
|
91
|
+
sGen.stop(`wallet: ${address} (new)`);
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
const config = loadConfig();
|
|
@@ -96,95 +98,94 @@ export async function initCommand(): Promise<void> {
|
|
|
96
98
|
if (net !== "mainnet") {
|
|
97
99
|
const bal = await suiBalance(sui, address);
|
|
98
100
|
if (bal === 0n) {
|
|
99
|
-
|
|
101
|
+
const sFund = spinner();
|
|
102
|
+
sFund.start("Requesting testnet faucet");
|
|
100
103
|
try {
|
|
101
104
|
await requestFaucet(config.network, address);
|
|
102
105
|
await waitForBalance(sui, address, 1n);
|
|
103
|
-
|
|
106
|
+
sFund.stop("funded");
|
|
104
107
|
} catch (e) {
|
|
105
|
-
|
|
106
|
-
|
|
108
|
+
sFund.stop(`faucet failed: ${String(e).slice(0, 80)}`);
|
|
109
|
+
note(`Fund ${address} at https://faucet.sui.io/ and re-run.`, "manual funding needed");
|
|
107
110
|
}
|
|
108
111
|
} else {
|
|
109
|
-
|
|
112
|
+
note(`${(Number(bal) / 1e9).toFixed(4)} SUI on ${address}`, "wallet balance");
|
|
110
113
|
}
|
|
111
114
|
}
|
|
112
115
|
|
|
113
116
|
const agents = new AgentClient(sui, config.packageId);
|
|
114
117
|
|
|
115
118
|
// ── 5. Mint agent ─────────────────────────────────────────────────────
|
|
116
|
-
let agentId =
|
|
119
|
+
let agentId = existing.agentObjectId;
|
|
117
120
|
if (!agentId) {
|
|
118
|
-
|
|
121
|
+
const sMint = spinner();
|
|
122
|
+
sMint.start("Minting agent identity object on-chain");
|
|
119
123
|
try {
|
|
120
124
|
const keypair = keypairFromSecret(secret);
|
|
121
|
-
const minted = await
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
new TextEncoder().encode("sofer"),
|
|
127
|
-
),
|
|
125
|
+
const minted = await agents.mint(
|
|
126
|
+
keypair,
|
|
127
|
+
"Sofer",
|
|
128
|
+
"a sovereign AI agent on Sui with encrypted memory on Walrus",
|
|
129
|
+
new TextEncoder().encode("sofer"),
|
|
128
130
|
);
|
|
129
131
|
agentId = minted.agentId;
|
|
130
|
-
|
|
132
|
+
sMint.stop(`agent: ${agentId}`);
|
|
131
133
|
} catch (e) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
+
sMint.stop(`mint failed: ${String(e).slice(0, 120)}`);
|
|
135
|
+
cancel("Mint failed. Is the wallet funded?");
|
|
134
136
|
return;
|
|
135
137
|
}
|
|
136
138
|
} else {
|
|
137
|
-
|
|
139
|
+
note(agentId, "reusing agent");
|
|
138
140
|
}
|
|
139
141
|
|
|
140
142
|
// ── 6. Provision MemWal memory ────────────────────────────────────────
|
|
141
|
-
let accountId =
|
|
142
|
-
let delegateKey =
|
|
143
|
+
let accountId = existing.memwal.accountId;
|
|
144
|
+
let delegateKey = existing.memwal.delegateKey;
|
|
143
145
|
if (!accountId || !delegateKey) {
|
|
144
|
-
|
|
146
|
+
const sMem = spinner();
|
|
147
|
+
sMem.start("Provisioning Walrus memory (MemWal)");
|
|
145
148
|
try {
|
|
146
|
-
const prov = await
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}),
|
|
154
|
-
);
|
|
149
|
+
const prov = await provisionMemwal({
|
|
150
|
+
ownerSecret: secret,
|
|
151
|
+
packageId: config.memwal.packageId,
|
|
152
|
+
registryId: config.memwal.registryId,
|
|
153
|
+
network: net,
|
|
154
|
+
label: "sofer-cli",
|
|
155
|
+
});
|
|
155
156
|
accountId = prov.accountId;
|
|
156
157
|
delegateKey = prov.delegateKey;
|
|
157
|
-
|
|
158
|
+
sMem.stop(`account: ${accountId}`);
|
|
158
159
|
} catch (e) {
|
|
160
|
+
sMem.stop(`provision failed: ${String(e).slice(0, 120)}`);
|
|
159
161
|
const msg = String(e);
|
|
160
162
|
if (msg.includes("abort code: 3") || msg.includes("create_account")) {
|
|
161
|
-
|
|
162
|
-
"This wallet already owns a MemWal account
|
|
163
|
-
"Delete ~/.sofer/ and re-run `sofer init`, or set the env vars manually.",
|
|
163
|
+
cancel(
|
|
164
|
+
"This wallet already owns a MemWal account.\nDelete ~/.sofer/ and re-run, or set env vars manually.",
|
|
164
165
|
);
|
|
165
166
|
}
|
|
166
|
-
|
|
167
|
+
return;
|
|
167
168
|
}
|
|
168
169
|
} else {
|
|
169
|
-
|
|
170
|
+
note(accountId, "reusing memory account");
|
|
170
171
|
}
|
|
171
172
|
|
|
172
173
|
// ── 7. Link memory to agent on-chain ───────────────────────────────────
|
|
173
|
-
|
|
174
|
+
const sLink = spinner();
|
|
175
|
+
sLink.start("Linking memory account to agent on-chain");
|
|
174
176
|
try {
|
|
175
177
|
const keypair = keypairFromSecret(secret);
|
|
176
|
-
await
|
|
177
|
-
|
|
178
|
+
await agents.setMemoryAccount(keypair, agentId!, accountId!);
|
|
179
|
+
sLink.stop("linked");
|
|
178
180
|
} catch (e) {
|
|
179
|
-
|
|
181
|
+
sLink.stop(`link failed (may already be linked): ${String(e).slice(0, 80)}`);
|
|
180
182
|
}
|
|
181
183
|
|
|
182
184
|
// ── 8. Persist config + secrets to ~/.sofer/ ───────────────────────────
|
|
183
|
-
|
|
184
|
-
|
|
185
|
+
const sSave = spinner();
|
|
186
|
+
sSave.start("Saving to ~/.sofer/");
|
|
185
187
|
writeSecret(agentPaths.suiKey, secret);
|
|
186
188
|
writeSecret(agentPaths.brainKey, apiKey);
|
|
187
|
-
|
|
188
189
|
const persisted: PersistedConfig = {
|
|
189
190
|
network: net,
|
|
190
191
|
agentObjectId: agentId!,
|
|
@@ -196,19 +197,16 @@ export async function initCommand(): Promise<void> {
|
|
|
196
197
|
},
|
|
197
198
|
};
|
|
198
199
|
writePersistedConfig(persisted);
|
|
199
|
-
|
|
200
|
-
const agentDir = agentPaths.agent(shortAgentId(address));
|
|
201
|
-
console.log(` config: ${agentPaths.config}`);
|
|
202
|
-
console.log(` keys: ${agentPaths.suiKey} / ${agentPaths.brainKey}`);
|
|
203
|
-
console.log(` agent: ${agentDir.dir}\n`);
|
|
200
|
+
sSave.stop(`config: ${agentPaths.config}`);
|
|
204
201
|
|
|
205
202
|
// ── 9. Summary ────────────────────────────────────────────────────────
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
203
|
+
const lines = [
|
|
204
|
+
`agent ${agentId!.slice(0, 30)}…`,
|
|
205
|
+
`address ${address.slice(0, 10)}…`,
|
|
206
|
+
`network ${net}`,
|
|
207
|
+
`memory ${accountId!.slice(0, 10)}…`,
|
|
208
|
+
"",
|
|
209
|
+
"Run `sofer` to chat with your agent.",
|
|
210
|
+
];
|
|
211
|
+
outro(lines.join("\n"));
|
|
214
212
|
}
|