@sofer_agent/cli 0.1.0
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/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +44 -0
- package/dist/bin.js.map +1 -0
- package/dist/chat.d.ts +3 -0
- package/dist/chat.d.ts.map +1 -0
- package/dist/chat.js +43 -0
- package/dist/chat.js.map +1 -0
- package/dist/env.d.ts +10 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +29 -0
- package/dist/env.js.map +1 -0
- package/dist/info.d.ts +3 -0
- package/dist/info.d.ts.map +1 -0
- package/dist/info.js +38 -0
- package/dist/info.js.map +1 -0
- package/dist/init.d.ts +7 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +92 -0
- package/dist/init.js.map +1 -0
- package/dist/secrets.d.ts +4 -0
- package/dist/secrets.d.ts.map +1 -0
- package/dist/secrets.js +13 -0
- package/dist/secrets.js.map +1 -0
- package/package.json +38 -0
- package/src/bin.ts +48 -0
- package/src/chat.ts +46 -0
- package/src/env.ts +28 -0
- package/src/info.ts +46 -0
- package/src/init.ts +114 -0
- package/src/secrets.ts +14 -0
package/dist/bin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
|
package/dist/bin.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { chatCommand } from "./chat.js";
|
|
3
|
+
import { loadDotenv } from "./env.js";
|
|
4
|
+
import { infoCommand } from "./info.js";
|
|
5
|
+
import { initCommand } from "./init.js";
|
|
6
|
+
function printHelp() {
|
|
7
|
+
console.log(`sofer — sovereign AI agent on Sui (memory on Walrus)
|
|
8
|
+
|
|
9
|
+
sofer chat with your agent (default)
|
|
10
|
+
sofer init mint the agent + provision Walrus memory
|
|
11
|
+
sofer info print on-chain agent state
|
|
12
|
+
sofer help show this help
|
|
13
|
+
|
|
14
|
+
Reads config + secrets from .env (or the environment).`);
|
|
15
|
+
}
|
|
16
|
+
async function main() {
|
|
17
|
+
loadDotenv();
|
|
18
|
+
const cmd = process.argv[2] ?? "chat";
|
|
19
|
+
switch (cmd) {
|
|
20
|
+
case "chat":
|
|
21
|
+
await chatCommand();
|
|
22
|
+
break;
|
|
23
|
+
case "init":
|
|
24
|
+
await initCommand();
|
|
25
|
+
break;
|
|
26
|
+
case "info":
|
|
27
|
+
await infoCommand();
|
|
28
|
+
break;
|
|
29
|
+
case "help":
|
|
30
|
+
case "-h":
|
|
31
|
+
case "--help":
|
|
32
|
+
printHelp();
|
|
33
|
+
break;
|
|
34
|
+
default:
|
|
35
|
+
console.error(`unknown command: ${cmd}\n`);
|
|
36
|
+
printHelp();
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
main().catch((e) => {
|
|
41
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
42
|
+
process.exit(1);
|
|
43
|
+
});
|
|
44
|
+
//# sourceMappingURL=bin.js.map
|
package/dist/bin.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,CACT;;;;;;;uDAOmD,CACpD,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,UAAU,EAAE,CAAC;IACb,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC;IACtC,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,MAAM;YACT,MAAM,WAAW,EAAE,CAAC;YACpB,MAAM;QACR,KAAK,MAAM;YACT,MAAM,WAAW,EAAE,CAAC;YACpB,MAAM;QACR,KAAK,MAAM;YACT,MAAM,WAAW,EAAE,CAAC;YACpB,MAAM;QACR,KAAK,MAAM,CAAC;QACZ,KAAK,IAAI,CAAC;QACV,KAAK,QAAQ;YACX,SAAS,EAAE,CAAC;YACZ,MAAM;QACR;YACE,OAAO,CAAC,KAAK,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;YAC3C,SAAS,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;IACjB,OAAO,CAAC,KAAK,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/chat.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../src/chat.ts"],"names":[],"mappings":"AAIA,4CAA4C;AAC5C,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAwCjD"}
|
package/dist/chat.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import readline from "node:readline";
|
|
2
|
+
import { loadConfig, SoferAgent } from "@sofer_agent/core";
|
|
3
|
+
import { requireSecrets } from "./secrets.js";
|
|
4
|
+
/** Interactive chat REPL with the agent. */
|
|
5
|
+
export async function chatCommand() {
|
|
6
|
+
const config = loadConfig();
|
|
7
|
+
const agent = await SoferAgent.create(config, requireSecrets());
|
|
8
|
+
console.log(`\x1b[1m${agent.name}\x1b[0m ready — ${agent.address}`);
|
|
9
|
+
console.log(`model: ${config.brain.model} · type a message, or /exit to quit\n`);
|
|
10
|
+
const rl = readline.createInterface({
|
|
11
|
+
input: process.stdin,
|
|
12
|
+
output: process.stdout,
|
|
13
|
+
prompt: "\x1b[36myou>\x1b[0m ",
|
|
14
|
+
});
|
|
15
|
+
const label = `\x1b[32m${agent.name.toLowerCase()}>\x1b[0m`;
|
|
16
|
+
rl.prompt();
|
|
17
|
+
rl.on("line", async (line) => {
|
|
18
|
+
const text = line.trim();
|
|
19
|
+
if (text === "/exit" || text === "/quit") {
|
|
20
|
+
rl.close();
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (!text) {
|
|
24
|
+
rl.prompt();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const reply = await agent.chat(text);
|
|
29
|
+
console.log(`${label} ${reply}\n`);
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
console.error(`\x1b[31merror:\x1b[0m ${e instanceof Error ? e.message : String(e)}\n`);
|
|
33
|
+
}
|
|
34
|
+
rl.prompt();
|
|
35
|
+
});
|
|
36
|
+
await new Promise((resolve) => {
|
|
37
|
+
rl.on("close", () => {
|
|
38
|
+
console.log("bye.");
|
|
39
|
+
resolve();
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=chat.js.map
|
package/dist/chat.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../src/chat.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,4CAA4C;AAC5C,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC;IAEhE,OAAO,CAAC,GAAG,CAAC,UAAU,KAAK,CAAC,IAAI,mBAAmB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IACpE,OAAO,CAAC,GAAG,CAAC,UAAU,MAAM,CAAC,KAAK,CAAC,KAAK,2CAA2C,CAAC,CAAC;IAErF,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC;QAClC,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,MAAM,EAAE,sBAAsB;KAC/B,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,WAAW,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC;IAC5D,EAAE,CAAC,MAAM,EAAE,CAAC;IAEZ,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACzB,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YACzC,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,OAAO;QACT,CAAC;QACD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,EAAE,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO;QACT,CAAC;QACD,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,IAAI,KAAK,IAAI,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CAAC,yBAAyB,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACzF,CAAC;QACD,EAAE,CAAC,MAAM,EAAE,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAClC,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YAClB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACpB,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/env.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Load `.env` into process.env (Node 22 built-in, no dotenv dep).
|
|
3
|
+
*
|
|
4
|
+
* Resolution order, so `sofer` works from any working directory:
|
|
5
|
+
* 1. `.env` in the current directory (a per-project override), else
|
|
6
|
+
* 2. `.env` at the repo root, found relative to this installed binary
|
|
7
|
+
* (`<repo>/packages/cli/dist/env.js` → `<repo>/.env`).
|
|
8
|
+
*/
|
|
9
|
+
export declare function loadDotenv(): void;
|
|
10
|
+
//# sourceMappingURL=env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAejC"}
|
package/dist/env.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
/**
|
|
5
|
+
* Load `.env` into process.env (Node 22 built-in, no dotenv dep).
|
|
6
|
+
*
|
|
7
|
+
* Resolution order, so `sofer` works from any working directory:
|
|
8
|
+
* 1. `.env` in the current directory (a per-project override), else
|
|
9
|
+
* 2. `.env` at the repo root, found relative to this installed binary
|
|
10
|
+
* (`<repo>/packages/cli/dist/env.js` → `<repo>/.env`).
|
|
11
|
+
*/
|
|
12
|
+
export function loadDotenv() {
|
|
13
|
+
const loader = process.loadEnvFile;
|
|
14
|
+
if (!loader)
|
|
15
|
+
return; // Node < 22
|
|
16
|
+
const cwdEnv = resolve(process.cwd(), ".env");
|
|
17
|
+
const here = dirname(fileURLToPath(import.meta.url)); // <repo>/packages/cli/dist
|
|
18
|
+
const repoEnv = resolve(here, "../../../.env");
|
|
19
|
+
const target = existsSync(cwdEnv) ? cwdEnv : existsSync(repoEnv) ? repoEnv : null;
|
|
20
|
+
if (!target)
|
|
21
|
+
return;
|
|
22
|
+
try {
|
|
23
|
+
loader(target);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
/* ignore malformed env file */
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=env.js.map
|
package/dist/env.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,MAAM,GAAI,OAAgE,CAAC,WAAW,CAAC;IAC7F,IAAI,CAAC,MAAM;QAAE,OAAO,CAAC,YAAY;IAEjC,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,2BAA2B;IACjF,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;IAE/C,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IAClF,IAAI,CAAC,MAAM;QAAE,OAAO;IACpB,IAAI,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,CAAC;IACjB,CAAC;IAAC,MAAM,CAAC;QACP,+BAA+B;IACjC,CAAC;AACH,CAAC"}
|
package/dist/info.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"info.d.ts","sourceRoot":"","sources":["../src/info.ts"],"names":[],"mappings":"AAEA,wCAAwC;AACxC,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CA0CjD"}
|
package/dist/info.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { AgentClient, keypairFromSecret, loadConfig, makeSuiClient, suiBalance } from "@sofer_agent/core";
|
|
2
|
+
/** Print the agent's on-chain state. */
|
|
3
|
+
export async function infoCommand() {
|
|
4
|
+
const config = loadConfig();
|
|
5
|
+
if (!config.packageId) {
|
|
6
|
+
console.log("SOFER_PACKAGE_ID not set.");
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
if (!config.agentObjectId) {
|
|
10
|
+
console.log("No SOFER_AGENT_OBJECT_ID set. Run `sofer init` to mint one.");
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const sui = makeSuiClient(config.network);
|
|
14
|
+
const agents = new AgentClient(sui, config.packageId);
|
|
15
|
+
const a = await agents.getAgent(config.agentObjectId);
|
|
16
|
+
if (!a) {
|
|
17
|
+
console.log("Agent object not found on-chain.");
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
let balance;
|
|
21
|
+
const secret = process.env.SOFER_SUI_SECRET_KEY;
|
|
22
|
+
if (secret) {
|
|
23
|
+
const mist = await suiBalance(sui, keypairFromSecret(secret).toSuiAddress());
|
|
24
|
+
balance = `${(Number(mist) / 1e9).toFixed(4)} SUI`;
|
|
25
|
+
}
|
|
26
|
+
console.log(JSON.stringify({
|
|
27
|
+
network: config.network,
|
|
28
|
+
package: config.packageId,
|
|
29
|
+
agentObjectId: a.id,
|
|
30
|
+
name: a.name,
|
|
31
|
+
persona: a.persona,
|
|
32
|
+
memoryEpoch: a.epoch,
|
|
33
|
+
memoryAccount: a.memoryAccount,
|
|
34
|
+
memoryProvisioned: Boolean(config.memwal.accountId),
|
|
35
|
+
balance,
|
|
36
|
+
}, null, 2));
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=info.js.map
|
package/dist/info.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"info.js","sourceRoot":"","sources":["../src/info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE1G,wCAAwC;AACxC,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;QACzC,OAAO;IACT,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,6DAA6D,CAAC,CAAC;QAC3E,OAAO;IACT,CAAC;IACD,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IACtD,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IACtD,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;QAChD,OAAO;IACT,CAAC;IAED,IAAI,OAA2B,CAAC;IAChC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;IAChD,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE,iBAAiB,CAAC,MAAM,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC;QAC7E,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;IACrD,CAAC;IAED,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CACZ;QACE,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,OAAO,EAAE,MAAM,CAAC,SAAS;QACzB,aAAa,EAAE,CAAC,CAAC,EAAE;QACnB,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,WAAW,EAAE,CAAC,CAAC,KAAK;QACpB,aAAa,EAAE,CAAC,CAAC,aAAa;QAC9B,iBAAiB,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;QACnD,OAAO;KACR,EACD,IAAI,EACJ,CAAC,CACF,CACF,CAAC;AACJ,CAAC"}
|
package/dist/init.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provision a sovereign agent: wallet → fund → mint the Agent object →
|
|
3
|
+
* provision Walrus memory (MemWal account + delegate key) → link them on-chain.
|
|
4
|
+
* Idempotent: re-running on an already-set-up agent is a no-op with guidance.
|
|
5
|
+
*/
|
|
6
|
+
export declare function initCommand(): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAYA;;;;GAIG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAgGjD"}
|
package/dist/init.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { AgentClient, generateKeypair, keypairFromSecret, loadConfig, makeSuiClient, provisionMemwal, requestFaucet, suiBalance, waitForBalance, } from "@sofer_agent/core";
|
|
2
|
+
/**
|
|
3
|
+
* Provision a sovereign agent: wallet → fund → mint the Agent object →
|
|
4
|
+
* provision Walrus memory (MemWal account + delegate key) → link them on-chain.
|
|
5
|
+
* Idempotent: re-running on an already-set-up agent is a no-op with guidance.
|
|
6
|
+
*/
|
|
7
|
+
export async function initCommand() {
|
|
8
|
+
const config = loadConfig();
|
|
9
|
+
if (!config.packageId)
|
|
10
|
+
throw new Error("SOFER_PACKAGE_ID not set");
|
|
11
|
+
const net = config.network === "mainnet" ? "mainnet" : "testnet";
|
|
12
|
+
// Already fully initialized? Don't re-mint / re-provision.
|
|
13
|
+
if (config.agentObjectId && config.memwal.accountId && config.memwal.delegateKey) {
|
|
14
|
+
console.log("Already initialized:");
|
|
15
|
+
console.log(` agent object: ${config.agentObjectId}`);
|
|
16
|
+
console.log(` memory account: ${config.memwal.accountId}`);
|
|
17
|
+
console.log("\nRun `sofer` to chat. To start fresh, unset SOFER_AGENT_OBJECT_ID,");
|
|
18
|
+
console.log("MEMWAL_ACCOUNT_ID, MEMWAL_DELEGATE_KEY (and SOFER_SUI_SECRET_KEY) in .env.");
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
// 1. Wallet (reuse if provided, else generate a fresh one).
|
|
22
|
+
const keypair = process.env.SOFER_SUI_SECRET_KEY
|
|
23
|
+
? keypairFromSecret(process.env.SOFER_SUI_SECRET_KEY)
|
|
24
|
+
: generateKeypair();
|
|
25
|
+
const secret = keypair.getSecretKey();
|
|
26
|
+
const address = keypair.toSuiAddress();
|
|
27
|
+
console.log(`• wallet: ${address}`);
|
|
28
|
+
const sui = makeSuiClient(config.network);
|
|
29
|
+
// 2. Fund (testnet/devnet only).
|
|
30
|
+
if ((await suiBalance(sui, address)) === 0n && config.network !== "mainnet") {
|
|
31
|
+
console.log("• funding from faucet…");
|
|
32
|
+
try {
|
|
33
|
+
await requestFaucet(config.network, address);
|
|
34
|
+
await waitForBalance(sui, address, 1n);
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
console.warn(` faucet failed (${String(e).slice(0, 60)}); fund ${address} at https://faucet.sui.io/ and re-run`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// 3. Mint the on-chain Agent object (reuse if one is already configured).
|
|
41
|
+
const agents = new AgentClient(sui, config.packageId);
|
|
42
|
+
let agentId = config.agentObjectId;
|
|
43
|
+
if (agentId) {
|
|
44
|
+
console.log(`• reusing agent object: ${agentId}`);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
console.log("• minting agent identity object…");
|
|
48
|
+
const minted = await agents.mint(keypair, "Sofer", "a sovereign AI agent on Sui with encrypted memory on Walrus", new TextEncoder().encode("sofer"));
|
|
49
|
+
agentId = minted.agentId;
|
|
50
|
+
console.log(` agent object: ${agentId}`);
|
|
51
|
+
}
|
|
52
|
+
// 4. Provision Walrus memory — unless this wallet already has an account.
|
|
53
|
+
let accountId = config.memwal.accountId;
|
|
54
|
+
let delegateKey = config.memwal.delegateKey;
|
|
55
|
+
if (accountId && delegateKey) {
|
|
56
|
+
console.log(`• reusing memory account: ${accountId}`);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
console.log("• provisioning Walrus memory (MemWal account + delegate key)…");
|
|
60
|
+
try {
|
|
61
|
+
const prov = await provisionMemwal({
|
|
62
|
+
ownerSecret: secret,
|
|
63
|
+
packageId: config.memwal.packageId,
|
|
64
|
+
registryId: config.memwal.registryId,
|
|
65
|
+
network: net,
|
|
66
|
+
label: "sofer-cli",
|
|
67
|
+
});
|
|
68
|
+
accountId = prov.accountId;
|
|
69
|
+
delegateKey = prov.delegateKey;
|
|
70
|
+
console.log(` memory account: ${accountId}`);
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
const msg = String(e);
|
|
74
|
+
if (msg.includes("abort code: 3") || msg.includes("create_account")) {
|
|
75
|
+
throw new Error("This Sui wallet already owns a MemWal account (one per address).\n" +
|
|
76
|
+
" • Reuse it: set MEMWAL_ACCOUNT_ID and MEMWAL_DELEGATE_KEY in .env, then run `sofer`.\n" +
|
|
77
|
+
" • Or start fresh: unset SOFER_SUI_SECRET_KEY in .env and re-run `sofer init` to mint a new wallet.");
|
|
78
|
+
}
|
|
79
|
+
throw e;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// 5. Link the memory account into the agent object on-chain.
|
|
83
|
+
console.log("• linking memory account on-chain…");
|
|
84
|
+
await agents.setMemoryAccount(keypair, agentId, accountId);
|
|
85
|
+
console.log("\n✅ Agent ready. Persist these in your .env (keep them secret):\n");
|
|
86
|
+
console.log(`SOFER_SUI_SECRET_KEY=${secret}`);
|
|
87
|
+
console.log(`SOFER_AGENT_OBJECT_ID=${agentId}`);
|
|
88
|
+
console.log(`MEMWAL_ACCOUNT_ID=${accountId}`);
|
|
89
|
+
console.log(`MEMWAL_DELEGATE_KEY=${delegateKey}`);
|
|
90
|
+
console.log("\nThen run `sofer` to chat.");
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=init.js.map
|
package/dist/init.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.d.ts","sourceRoot":"","sources":["../src/secrets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,0EAA0E;AAC1E,wBAAgB,cAAc,IAAI,YAAY,CAU7C"}
|
package/dist/secrets.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Pull required secrets from the environment, with actionable errors. */
|
|
2
|
+
export function requireSecrets() {
|
|
3
|
+
const suiSecretKey = process.env.SOFER_SUI_SECRET_KEY;
|
|
4
|
+
const anthropicApiKey = process.env.ANTHROPIC_API_KEY;
|
|
5
|
+
if (!suiSecretKey) {
|
|
6
|
+
throw new Error("SOFER_SUI_SECRET_KEY not set — run `sofer init` or add it to .env");
|
|
7
|
+
}
|
|
8
|
+
if (!anthropicApiKey) {
|
|
9
|
+
throw new Error("ANTHROPIC_API_KEY not set — add it to .env");
|
|
10
|
+
}
|
|
11
|
+
return { suiSecretKey, anthropicApiKey };
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../src/secrets.ts"],"names":[],"mappings":"AAEA,0EAA0E;AAC1E,MAAM,UAAU,cAAc;IAC5B,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;IACtD,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IACtD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;IACvF,CAAC;IACD,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,CAAC;AAC3C,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sofer_agent/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"sofer": "./dist/bin.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"src"
|
|
11
|
+
],
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public"
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/anomalyco/sofer"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"sui",
|
|
21
|
+
"ai",
|
|
22
|
+
"agent",
|
|
23
|
+
"walrus",
|
|
24
|
+
"sovereign",
|
|
25
|
+
"cli"
|
|
26
|
+
],
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@sofer_agent/core": "0.1.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/node": "^22.10.2",
|
|
32
|
+
"typescript": "^5.7.2"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsc -b && chmod +x dist/bin.js",
|
|
36
|
+
"typecheck": "tsc --noEmit"
|
|
37
|
+
}
|
|
38
|
+
}
|
package/src/bin.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { chatCommand } from "./chat.js";
|
|
3
|
+
import { loadDotenv } from "./env.js";
|
|
4
|
+
import { infoCommand } from "./info.js";
|
|
5
|
+
import { initCommand } from "./init.js";
|
|
6
|
+
|
|
7
|
+
function printHelp(): void {
|
|
8
|
+
console.log(
|
|
9
|
+
`sofer — sovereign AI agent on Sui (memory on Walrus)
|
|
10
|
+
|
|
11
|
+
sofer chat with your agent (default)
|
|
12
|
+
sofer init mint the agent + provision Walrus memory
|
|
13
|
+
sofer info print on-chain agent state
|
|
14
|
+
sofer help show this help
|
|
15
|
+
|
|
16
|
+
Reads config + secrets from .env (or the environment).`,
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function main(): Promise<void> {
|
|
21
|
+
loadDotenv();
|
|
22
|
+
const cmd = process.argv[2] ?? "chat";
|
|
23
|
+
switch (cmd) {
|
|
24
|
+
case "chat":
|
|
25
|
+
await chatCommand();
|
|
26
|
+
break;
|
|
27
|
+
case "init":
|
|
28
|
+
await initCommand();
|
|
29
|
+
break;
|
|
30
|
+
case "info":
|
|
31
|
+
await infoCommand();
|
|
32
|
+
break;
|
|
33
|
+
case "help":
|
|
34
|
+
case "-h":
|
|
35
|
+
case "--help":
|
|
36
|
+
printHelp();
|
|
37
|
+
break;
|
|
38
|
+
default:
|
|
39
|
+
console.error(`unknown command: ${cmd}\n`);
|
|
40
|
+
printHelp();
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
main().catch((e) => {
|
|
46
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
47
|
+
process.exit(1);
|
|
48
|
+
});
|
package/src/chat.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import readline from "node:readline";
|
|
2
|
+
import { loadConfig, SoferAgent } from "@sofer_agent/core";
|
|
3
|
+
import { requireSecrets } from "./secrets.js";
|
|
4
|
+
|
|
5
|
+
/** Interactive chat REPL with the agent. */
|
|
6
|
+
export async function chatCommand(): Promise<void> {
|
|
7
|
+
const config = loadConfig();
|
|
8
|
+
const agent = await SoferAgent.create(config, requireSecrets());
|
|
9
|
+
|
|
10
|
+
console.log(`\x1b[1m${agent.name}\x1b[0m ready — ${agent.address}`);
|
|
11
|
+
console.log(`model: ${config.brain.model} · type a message, or /exit to quit\n`);
|
|
12
|
+
|
|
13
|
+
const rl = readline.createInterface({
|
|
14
|
+
input: process.stdin,
|
|
15
|
+
output: process.stdout,
|
|
16
|
+
prompt: "\x1b[36myou>\x1b[0m ",
|
|
17
|
+
});
|
|
18
|
+
const label = `\x1b[32m${agent.name.toLowerCase()}>\x1b[0m`;
|
|
19
|
+
rl.prompt();
|
|
20
|
+
|
|
21
|
+
rl.on("line", async (line) => {
|
|
22
|
+
const text = line.trim();
|
|
23
|
+
if (text === "/exit" || text === "/quit") {
|
|
24
|
+
rl.close();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (!text) {
|
|
28
|
+
rl.prompt();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const reply = await agent.chat(text);
|
|
33
|
+
console.log(`${label} ${reply}\n`);
|
|
34
|
+
} catch (e) {
|
|
35
|
+
console.error(`\x1b[31merror:\x1b[0m ${e instanceof Error ? e.message : String(e)}\n`);
|
|
36
|
+
}
|
|
37
|
+
rl.prompt();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
await new Promise<void>((resolve) => {
|
|
41
|
+
rl.on("close", () => {
|
|
42
|
+
console.log("bye.");
|
|
43
|
+
resolve();
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
}
|
package/src/env.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Load `.env` into process.env (Node 22 built-in, no dotenv dep).
|
|
7
|
+
*
|
|
8
|
+
* Resolution order, so `sofer` works from any working directory:
|
|
9
|
+
* 1. `.env` in the current directory (a per-project override), else
|
|
10
|
+
* 2. `.env` at the repo root, found relative to this installed binary
|
|
11
|
+
* (`<repo>/packages/cli/dist/env.js` → `<repo>/.env`).
|
|
12
|
+
*/
|
|
13
|
+
export function loadDotenv(): void {
|
|
14
|
+
const loader = (process as unknown as { loadEnvFile?: (path?: string) => void }).loadEnvFile;
|
|
15
|
+
if (!loader) return; // Node < 22
|
|
16
|
+
|
|
17
|
+
const cwdEnv = resolve(process.cwd(), ".env");
|
|
18
|
+
const here = dirname(fileURLToPath(import.meta.url)); // <repo>/packages/cli/dist
|
|
19
|
+
const repoEnv = resolve(here, "../../../.env");
|
|
20
|
+
|
|
21
|
+
const target = existsSync(cwdEnv) ? cwdEnv : existsSync(repoEnv) ? repoEnv : null;
|
|
22
|
+
if (!target) return;
|
|
23
|
+
try {
|
|
24
|
+
loader(target);
|
|
25
|
+
} catch {
|
|
26
|
+
/* ignore malformed env file */
|
|
27
|
+
}
|
|
28
|
+
}
|
package/src/info.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { AgentClient, keypairFromSecret, loadConfig, makeSuiClient, suiBalance } from "@sofer_agent/core";
|
|
2
|
+
|
|
3
|
+
/** Print the agent's on-chain state. */
|
|
4
|
+
export async function infoCommand(): Promise<void> {
|
|
5
|
+
const config = loadConfig();
|
|
6
|
+
if (!config.packageId) {
|
|
7
|
+
console.log("SOFER_PACKAGE_ID not set.");
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
if (!config.agentObjectId) {
|
|
11
|
+
console.log("No SOFER_AGENT_OBJECT_ID set. Run `sofer init` to mint one.");
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const sui = makeSuiClient(config.network);
|
|
15
|
+
const agents = new AgentClient(sui, config.packageId);
|
|
16
|
+
const a = await agents.getAgent(config.agentObjectId);
|
|
17
|
+
if (!a) {
|
|
18
|
+
console.log("Agent object not found on-chain.");
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let balance: string | undefined;
|
|
23
|
+
const secret = process.env.SOFER_SUI_SECRET_KEY;
|
|
24
|
+
if (secret) {
|
|
25
|
+
const mist = await suiBalance(sui, keypairFromSecret(secret).toSuiAddress());
|
|
26
|
+
balance = `${(Number(mist) / 1e9).toFixed(4)} SUI`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
console.log(
|
|
30
|
+
JSON.stringify(
|
|
31
|
+
{
|
|
32
|
+
network: config.network,
|
|
33
|
+
package: config.packageId,
|
|
34
|
+
agentObjectId: a.id,
|
|
35
|
+
name: a.name,
|
|
36
|
+
persona: a.persona,
|
|
37
|
+
memoryEpoch: a.epoch,
|
|
38
|
+
memoryAccount: a.memoryAccount,
|
|
39
|
+
memoryProvisioned: Boolean(config.memwal.accountId),
|
|
40
|
+
balance,
|
|
41
|
+
},
|
|
42
|
+
null,
|
|
43
|
+
2,
|
|
44
|
+
),
|
|
45
|
+
);
|
|
46
|
+
}
|
package/src/init.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AgentClient,
|
|
3
|
+
generateKeypair,
|
|
4
|
+
keypairFromSecret,
|
|
5
|
+
loadConfig,
|
|
6
|
+
makeSuiClient,
|
|
7
|
+
provisionMemwal,
|
|
8
|
+
requestFaucet,
|
|
9
|
+
suiBalance,
|
|
10
|
+
waitForBalance,
|
|
11
|
+
} from "@sofer_agent/core";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Provision a sovereign agent: wallet → fund → mint the Agent object →
|
|
15
|
+
* provision Walrus memory (MemWal account + delegate key) → link them on-chain.
|
|
16
|
+
* Idempotent: re-running on an already-set-up agent is a no-op with guidance.
|
|
17
|
+
*/
|
|
18
|
+
export async function initCommand(): Promise<void> {
|
|
19
|
+
const config = loadConfig();
|
|
20
|
+
if (!config.packageId) throw new Error("SOFER_PACKAGE_ID not set");
|
|
21
|
+
const net: "testnet" | "mainnet" = config.network === "mainnet" ? "mainnet" : "testnet";
|
|
22
|
+
|
|
23
|
+
// Already fully initialized? Don't re-mint / re-provision.
|
|
24
|
+
if (config.agentObjectId && config.memwal.accountId && config.memwal.delegateKey) {
|
|
25
|
+
console.log("Already initialized:");
|
|
26
|
+
console.log(` agent object: ${config.agentObjectId}`);
|
|
27
|
+
console.log(` memory account: ${config.memwal.accountId}`);
|
|
28
|
+
console.log("\nRun `sofer` to chat. To start fresh, unset SOFER_AGENT_OBJECT_ID,");
|
|
29
|
+
console.log("MEMWAL_ACCOUNT_ID, MEMWAL_DELEGATE_KEY (and SOFER_SUI_SECRET_KEY) in .env.");
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 1. Wallet (reuse if provided, else generate a fresh one).
|
|
34
|
+
const keypair = process.env.SOFER_SUI_SECRET_KEY
|
|
35
|
+
? keypairFromSecret(process.env.SOFER_SUI_SECRET_KEY)
|
|
36
|
+
: generateKeypair();
|
|
37
|
+
const secret = keypair.getSecretKey();
|
|
38
|
+
const address = keypair.toSuiAddress();
|
|
39
|
+
console.log(`• wallet: ${address}`);
|
|
40
|
+
|
|
41
|
+
const sui = makeSuiClient(config.network);
|
|
42
|
+
|
|
43
|
+
// 2. Fund (testnet/devnet only).
|
|
44
|
+
if ((await suiBalance(sui, address)) === 0n && config.network !== "mainnet") {
|
|
45
|
+
console.log("• funding from faucet…");
|
|
46
|
+
try {
|
|
47
|
+
await requestFaucet(config.network, address);
|
|
48
|
+
await waitForBalance(sui, address, 1n);
|
|
49
|
+
} catch (e) {
|
|
50
|
+
console.warn(
|
|
51
|
+
` faucet failed (${String(e).slice(0, 60)}); fund ${address} at https://faucet.sui.io/ and re-run`,
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 3. Mint the on-chain Agent object (reuse if one is already configured).
|
|
57
|
+
const agents = new AgentClient(sui, config.packageId);
|
|
58
|
+
let agentId = config.agentObjectId;
|
|
59
|
+
if (agentId) {
|
|
60
|
+
console.log(`• reusing agent object: ${agentId}`);
|
|
61
|
+
} else {
|
|
62
|
+
console.log("• minting agent identity object…");
|
|
63
|
+
const minted = await agents.mint(
|
|
64
|
+
keypair,
|
|
65
|
+
"Sofer",
|
|
66
|
+
"a sovereign AI agent on Sui with encrypted memory on Walrus",
|
|
67
|
+
new TextEncoder().encode("sofer"),
|
|
68
|
+
);
|
|
69
|
+
agentId = minted.agentId;
|
|
70
|
+
console.log(` agent object: ${agentId}`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 4. Provision Walrus memory — unless this wallet already has an account.
|
|
74
|
+
let accountId = config.memwal.accountId;
|
|
75
|
+
let delegateKey = config.memwal.delegateKey;
|
|
76
|
+
if (accountId && delegateKey) {
|
|
77
|
+
console.log(`• reusing memory account: ${accountId}`);
|
|
78
|
+
} else {
|
|
79
|
+
console.log("• provisioning Walrus memory (MemWal account + delegate key)…");
|
|
80
|
+
try {
|
|
81
|
+
const prov = await provisionMemwal({
|
|
82
|
+
ownerSecret: secret,
|
|
83
|
+
packageId: config.memwal.packageId,
|
|
84
|
+
registryId: config.memwal.registryId,
|
|
85
|
+
network: net,
|
|
86
|
+
label: "sofer-cli",
|
|
87
|
+
});
|
|
88
|
+
accountId = prov.accountId;
|
|
89
|
+
delegateKey = prov.delegateKey;
|
|
90
|
+
console.log(` memory account: ${accountId}`);
|
|
91
|
+
} catch (e) {
|
|
92
|
+
const msg = String(e);
|
|
93
|
+
if (msg.includes("abort code: 3") || msg.includes("create_account")) {
|
|
94
|
+
throw new Error(
|
|
95
|
+
"This Sui wallet already owns a MemWal account (one per address).\n" +
|
|
96
|
+
" • Reuse it: set MEMWAL_ACCOUNT_ID and MEMWAL_DELEGATE_KEY in .env, then run `sofer`.\n" +
|
|
97
|
+
" • Or start fresh: unset SOFER_SUI_SECRET_KEY in .env and re-run `sofer init` to mint a new wallet.",
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
throw e;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// 5. Link the memory account into the agent object on-chain.
|
|
105
|
+
console.log("• linking memory account on-chain…");
|
|
106
|
+
await agents.setMemoryAccount(keypair, agentId, accountId);
|
|
107
|
+
|
|
108
|
+
console.log("\n✅ Agent ready. Persist these in your .env (keep them secret):\n");
|
|
109
|
+
console.log(`SOFER_SUI_SECRET_KEY=${secret}`);
|
|
110
|
+
console.log(`SOFER_AGENT_OBJECT_ID=${agentId}`);
|
|
111
|
+
console.log(`MEMWAL_ACCOUNT_ID=${accountId}`);
|
|
112
|
+
console.log(`MEMWAL_DELEGATE_KEY=${delegateKey}`);
|
|
113
|
+
console.log("\nThen run `sofer` to chat.");
|
|
114
|
+
}
|
package/src/secrets.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AgentSecrets } from "@sofer_agent/core";
|
|
2
|
+
|
|
3
|
+
/** Pull required secrets from the environment, with actionable errors. */
|
|
4
|
+
export function requireSecrets(): AgentSecrets {
|
|
5
|
+
const suiSecretKey = process.env.SOFER_SUI_SECRET_KEY;
|
|
6
|
+
const anthropicApiKey = process.env.ANTHROPIC_API_KEY;
|
|
7
|
+
if (!suiSecretKey) {
|
|
8
|
+
throw new Error("SOFER_SUI_SECRET_KEY not set — run `sofer init` or add it to .env");
|
|
9
|
+
}
|
|
10
|
+
if (!anthropicApiKey) {
|
|
11
|
+
throw new Error("ANTHROPIC_API_KEY not set — add it to .env");
|
|
12
|
+
}
|
|
13
|
+
return { suiSecretKey, anthropicApiKey };
|
|
14
|
+
}
|