@mnemom/mnemom 0.7.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.
Files changed (47) hide show
  1. package/LICENSE +191 -0
  2. package/README.md +123 -0
  3. package/dist/commands/agents.d.ts +15 -0
  4. package/dist/commands/agents.js +303 -0
  5. package/dist/commands/auth.d.ts +5 -0
  6. package/dist/commands/auth.js +60 -0
  7. package/dist/commands/card.d.ts +23 -0
  8. package/dist/commands/card.js +460 -0
  9. package/dist/commands/claim.d.ts +1 -0
  10. package/dist/commands/claim.js +72 -0
  11. package/dist/commands/init.d.ts +7 -0
  12. package/dist/commands/init.js +763 -0
  13. package/dist/commands/integrity.d.ts +1 -0
  14. package/dist/commands/integrity.js +49 -0
  15. package/dist/commands/license.d.ts +3 -0
  16. package/dist/commands/license.js +163 -0
  17. package/dist/commands/logs.d.ts +5 -0
  18. package/dist/commands/logs.js +73 -0
  19. package/dist/commands/migrate-config.d.ts +2 -0
  20. package/dist/commands/migrate-config.js +72 -0
  21. package/dist/commands/policy.d.ts +31 -0
  22. package/dist/commands/policy.js +543 -0
  23. package/dist/commands/register.d.ts +6 -0
  24. package/dist/commands/register.js +362 -0
  25. package/dist/commands/status.d.ts +1 -0
  26. package/dist/commands/status.js +383 -0
  27. package/dist/index.d.ts +2 -0
  28. package/dist/index.js +381 -0
  29. package/dist/lib/api.d.ts +133 -0
  30. package/dist/lib/api.js +207 -0
  31. package/dist/lib/auth.d.ts +60 -0
  32. package/dist/lib/auth.js +281 -0
  33. package/dist/lib/config.d.ts +105 -0
  34. package/dist/lib/config.js +253 -0
  35. package/dist/lib/format.d.ts +35 -0
  36. package/dist/lib/format.js +60 -0
  37. package/dist/lib/model-cache.d.ts +16 -0
  38. package/dist/lib/model-cache.js +138 -0
  39. package/dist/lib/models.d.ts +41 -0
  40. package/dist/lib/models.js +357 -0
  41. package/dist/lib/openclaw.d.ts +221 -0
  42. package/dist/lib/openclaw.js +474 -0
  43. package/dist/lib/prompt.d.ts +26 -0
  44. package/dist/lib/prompt.js +150 -0
  45. package/dist/smoltbot-shim.d.ts +2 -0
  46. package/dist/smoltbot-shim.js +7 -0
  47. package/package.json +61 -0
@@ -0,0 +1,60 @@
1
+ import { configExists, getAuthInfo, clearAuthTokens } from "../lib/config.js";
2
+ import { loginWithBrowser, loginWithPassword } from "../lib/auth.js";
3
+ import { fmt } from "../lib/format.js";
4
+ import { askInput } from "../lib/prompt.js";
5
+ export async function loginCommand(options = {}) {
6
+ if (!configExists()) {
7
+ console.log("\n" + fmt.error("smoltbot is not initialized") + "\n");
8
+ console.log("Run `smoltbot init` to get started.\n");
9
+ process.exit(1);
10
+ }
11
+ try {
12
+ let tokens;
13
+ if (options.noBrowser) {
14
+ const email = await askInput("Email:");
15
+ if (!email) {
16
+ console.log(fmt.error("Email is required."));
17
+ process.exit(1);
18
+ }
19
+ const password = await askInput("Password:", true);
20
+ if (!password) {
21
+ console.log(fmt.error("Password is required."));
22
+ process.exit(1);
23
+ }
24
+ tokens = await loginWithPassword(email, password);
25
+ }
26
+ else {
27
+ tokens = await loginWithBrowser();
28
+ }
29
+ console.log();
30
+ console.log(fmt.success("Logged in successfully!"));
31
+ console.log(fmt.label(" Email: ", ` ${tokens.email}`));
32
+ console.log(fmt.label(" User ID:", ` ${tokens.userId}`));
33
+ console.log();
34
+ }
35
+ catch (error) {
36
+ const message = error instanceof Error ? error.message : String(error);
37
+ console.log("\n" + fmt.error(`Login failed: ${message}`) + "\n");
38
+ process.exit(1);
39
+ }
40
+ }
41
+ export async function logoutCommand() {
42
+ clearAuthTokens();
43
+ console.log(fmt.success("Logged out."));
44
+ }
45
+ export async function whoamiCommand() {
46
+ const auth = getAuthInfo();
47
+ if (!auth) {
48
+ console.log("\nNot logged in. Run `smoltbot login` to authenticate.\n");
49
+ return;
50
+ }
51
+ const now = Math.floor(Date.now() / 1000);
52
+ const expired = auth.expiresAt <= now;
53
+ const expiresDate = new Date(auth.expiresAt * 1000).toISOString();
54
+ console.log(fmt.header("Auth Status"));
55
+ console.log();
56
+ console.log(fmt.label(" Email: ", ` ${auth.email}`));
57
+ console.log(fmt.label(" User ID:", ` ${auth.userId}`));
58
+ console.log(fmt.label(" Token: ", expired ? " expired" : ` valid until ${expiresDate}`));
59
+ console.log();
60
+ }
@@ -0,0 +1,23 @@
1
+ import { type AlignmentCard } from "../lib/api.js";
2
+ export type CardFormat = "json" | "yaml";
3
+ export interface ParsedCard {
4
+ format: CardFormat;
5
+ parsed: AlignmentCard;
6
+ }
7
+ export declare function parseCardFile(filePath: string): ParsedCard;
8
+ export interface ValidationCheck {
9
+ name: string;
10
+ passed: boolean;
11
+ message: string;
12
+ }
13
+ /** @deprecated Use validateCard instead */
14
+ export declare const validateCardJson: typeof validateCard;
15
+ export declare function validateCard(raw: string): ValidationCheck[];
16
+ /**
17
+ * Validate a pre-parsed card object (used for YAML cards).
18
+ * Re-serializes to JSON so the same checks run identically.
19
+ */
20
+ export declare function validateCardObject(card: AlignmentCard): ValidationCheck[];
21
+ export declare function cardShowCommand(agentName?: string): Promise<void>;
22
+ export declare function cardPublishCommand(file: string, agentName?: string): Promise<void>;
23
+ export declare function cardValidateCommand(file: string): Promise<void>;
@@ -0,0 +1,460 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import yaml from "js-yaml";
4
+ import { configExists, loadConfig, requireAgent } from "../lib/config.js";
5
+ import { getCard, updateCard, reverifyAgent, } from "../lib/api.js";
6
+ import { requireAuth } from "../lib/auth.js";
7
+ import { fmt } from "../lib/format.js";
8
+ import { askYesNo, isInteractive } from "../lib/prompt.js";
9
+ // Standard AAP values that do not require custom definitions
10
+ const STANDARD_VALUES = new Set([
11
+ "transparency",
12
+ "honesty",
13
+ "safety",
14
+ "privacy",
15
+ "fairness",
16
+ "accountability",
17
+ "beneficence",
18
+ "non-maleficence",
19
+ "autonomy",
20
+ "justice",
21
+ "reliability",
22
+ "security",
23
+ "human_oversight",
24
+ "explainability",
25
+ ]);
26
+ function detectFormat(filePath) {
27
+ const ext = path.extname(filePath).toLowerCase();
28
+ if (ext === ".yaml" || ext === ".yml")
29
+ return "yaml";
30
+ return "json";
31
+ }
32
+ export function parseCardFile(filePath) {
33
+ const raw = fs.readFileSync(filePath, "utf-8");
34
+ const format = detectFormat(filePath);
35
+ if (format === "yaml") {
36
+ const parsed = yaml.load(raw);
37
+ if (!parsed || typeof parsed !== "object") {
38
+ throw new Error("YAML did not produce a valid object");
39
+ }
40
+ return { format, parsed };
41
+ }
42
+ return { format, parsed: JSON.parse(raw) };
43
+ }
44
+ /** @deprecated Use validateCard instead */
45
+ export const validateCardJson = validateCard;
46
+ export function validateCard(raw) {
47
+ const checks = [];
48
+ // Check 1: Valid JSON
49
+ let card;
50
+ try {
51
+ card = JSON.parse(raw);
52
+ checks.push({ name: "Valid JSON", passed: true, message: "Parsed successfully" });
53
+ }
54
+ catch (e) {
55
+ const msg = e instanceof Error ? e.message : String(e);
56
+ checks.push({ name: "Valid JSON", passed: false, message: `Parse error: ${msg}` });
57
+ return checks; // Can't continue without valid JSON
58
+ }
59
+ // Check 2: Required blocks
60
+ const requiredBlocks = ["principal", "values", "autonomy_envelope", "audit_commitment"];
61
+ for (const block of requiredBlocks) {
62
+ if (card[block] && typeof card[block] === "object") {
63
+ checks.push({ name: `Block: ${block}`, passed: true, message: "Present" });
64
+ }
65
+ else {
66
+ checks.push({ name: `Block: ${block}`, passed: false, message: "Missing or invalid" });
67
+ }
68
+ }
69
+ // Check 3: values.declared is non-empty array
70
+ const declared = card.values?.declared;
71
+ if (Array.isArray(declared) && declared.length > 0) {
72
+ checks.push({
73
+ name: "values.declared",
74
+ passed: true,
75
+ message: `${declared.length} value(s) declared`,
76
+ });
77
+ }
78
+ else {
79
+ checks.push({
80
+ name: "values.declared",
81
+ passed: false,
82
+ message: "Must be a non-empty array",
83
+ });
84
+ }
85
+ // Check 4: Custom values have definitions
86
+ if (Array.isArray(declared)) {
87
+ const definitions = card.values?.definitions || {};
88
+ const customValues = declared.filter((v) => !STANDARD_VALUES.has(v));
89
+ const missingDefs = customValues.filter((v) => !definitions[v]);
90
+ if (missingDefs.length === 0) {
91
+ checks.push({
92
+ name: "Custom value definitions",
93
+ passed: true,
94
+ message: customValues.length === 0
95
+ ? "No custom values (all standard)"
96
+ : `${customValues.length} custom value(s) defined`,
97
+ });
98
+ }
99
+ else {
100
+ checks.push({
101
+ name: "Custom value definitions",
102
+ passed: false,
103
+ message: `Missing definitions for: ${missingDefs.join(", ")}`,
104
+ });
105
+ }
106
+ }
107
+ // Check 5: bounded_actions is non-empty array
108
+ const bounded = card.autonomy_envelope?.bounded_actions;
109
+ if (Array.isArray(bounded) && bounded.length > 0) {
110
+ checks.push({
111
+ name: "bounded_actions",
112
+ passed: true,
113
+ message: `${bounded.length} bounded action(s)`,
114
+ });
115
+ }
116
+ else {
117
+ checks.push({
118
+ name: "bounded_actions",
119
+ passed: false,
120
+ message: "Must be a non-empty array",
121
+ });
122
+ }
123
+ // Check 6: escalation_triggers conditions are evaluable
124
+ // Accepts: simple identifiers, tool_matches('...') calls, and logical expressions
125
+ // (comparisons with ==, !=, >, <, and/or, quoted strings, numbers)
126
+ const triggers = card.autonomy_envelope?.escalation_triggers;
127
+ if (Array.isArray(triggers) && triggers.length > 0) {
128
+ const conditionPattern = /^[\w\s\(\)\*\.'",=!><&|]+$/;
129
+ const invalidTriggers = triggers.filter((t) => !t.condition || !conditionPattern.test(t.condition));
130
+ if (invalidTriggers.length === 0) {
131
+ checks.push({
132
+ name: "escalation_triggers",
133
+ passed: true,
134
+ message: `${triggers.length} trigger(s), all valid`,
135
+ });
136
+ }
137
+ else {
138
+ checks.push({
139
+ name: "escalation_triggers",
140
+ passed: false,
141
+ message: `${invalidTriggers.length} trigger(s) with invalid conditions`,
142
+ });
143
+ }
144
+ }
145
+ else if (Array.isArray(triggers) && triggers.length === 0) {
146
+ checks.push({
147
+ name: "escalation_triggers",
148
+ passed: true,
149
+ message: "No triggers defined",
150
+ });
151
+ }
152
+ // Check 7: expires_at not already expired
153
+ if (card.expires_at) {
154
+ const expiresDate = new Date(card.expires_at);
155
+ if (isNaN(expiresDate.getTime())) {
156
+ checks.push({
157
+ name: "expires_at",
158
+ passed: false,
159
+ message: "Invalid date format",
160
+ });
161
+ }
162
+ else if (expiresDate.getTime() < Date.now()) {
163
+ checks.push({
164
+ name: "expires_at",
165
+ passed: false,
166
+ message: `Already expired: ${card.expires_at}`,
167
+ });
168
+ }
169
+ else {
170
+ checks.push({
171
+ name: "expires_at",
172
+ passed: true,
173
+ message: `Valid until ${card.expires_at}`,
174
+ });
175
+ }
176
+ }
177
+ return checks;
178
+ }
179
+ /**
180
+ * Validate a pre-parsed card object (used for YAML cards).
181
+ * Re-serializes to JSON so the same checks run identically.
182
+ */
183
+ export function validateCardObject(card) {
184
+ return validateCard(JSON.stringify(card));
185
+ }
186
+ // ============================================================================
187
+ // Card display
188
+ // ============================================================================
189
+ function displayCard(cardResponse) {
190
+ const card = cardResponse.card_json;
191
+ console.log(fmt.header("Alignment Card"));
192
+ console.log();
193
+ // Header info
194
+ console.log(fmt.label(" Card ID: ", cardResponse.card_id));
195
+ if (card.version) {
196
+ console.log(fmt.label(" Version: ", card.version));
197
+ }
198
+ if (card.issued_at) {
199
+ console.log(fmt.label(" Issued: ", card.issued_at));
200
+ }
201
+ if (card.expires_at) {
202
+ console.log(fmt.label(" Expires: ", card.expires_at));
203
+ }
204
+ // Principal
205
+ if (card.principal) {
206
+ console.log(fmt.section("Principal"));
207
+ console.log();
208
+ if (card.principal.name) {
209
+ console.log(fmt.label(" Name: ", card.principal.name));
210
+ }
211
+ if (card.principal.type) {
212
+ console.log(fmt.label(" Type: ", card.principal.type));
213
+ }
214
+ if (card.principal.organization) {
215
+ console.log(fmt.label(" Organization:", ` ${card.principal.organization}`));
216
+ }
217
+ }
218
+ // Values
219
+ if (card.values) {
220
+ console.log(fmt.section("Values"));
221
+ console.log();
222
+ if (Array.isArray(card.values.declared) && card.values.declared.length > 0) {
223
+ const badges = card.values.declared.map((v) => {
224
+ if (STANDARD_VALUES.has(v)) {
225
+ return fmt.badge(v, "cyan");
226
+ }
227
+ return fmt.badge(v, "magenta");
228
+ });
229
+ console.log(` ${badges.join(" ")}`);
230
+ // Show definitions for custom values
231
+ const definitions = card.values.definitions || {};
232
+ const customValues = card.values.declared.filter((v) => !STANDARD_VALUES.has(v));
233
+ if (customValues.length > 0) {
234
+ console.log();
235
+ for (const v of customValues) {
236
+ if (definitions[v]) {
237
+ console.log(fmt.label(` ${v}:`, ` ${definitions[v]}`));
238
+ }
239
+ }
240
+ }
241
+ }
242
+ }
243
+ // Autonomy envelope
244
+ if (card.autonomy_envelope) {
245
+ console.log(fmt.section("Autonomy Envelope"));
246
+ console.log();
247
+ const bounded = card.autonomy_envelope.bounded_actions;
248
+ if (Array.isArray(bounded) && bounded.length > 0) {
249
+ console.log(" Bounded actions:");
250
+ for (const action of bounded) {
251
+ console.log(` ${fmt.success(action)}`);
252
+ }
253
+ }
254
+ const forbidden = card.autonomy_envelope.forbidden_actions;
255
+ if (Array.isArray(forbidden) && forbidden.length > 0) {
256
+ console.log(" Forbidden actions:");
257
+ for (const action of forbidden) {
258
+ console.log(` ${fmt.error(action)}`);
259
+ }
260
+ }
261
+ const triggers = card.autonomy_envelope.escalation_triggers;
262
+ if (Array.isArray(triggers) && triggers.length > 0) {
263
+ console.log(" Escalation triggers:");
264
+ for (const trigger of triggers) {
265
+ const action = trigger.action ? ` -> ${trigger.action}` : "";
266
+ console.log(` ${fmt.warn(`${trigger.condition}${action}`)}`);
267
+ }
268
+ }
269
+ }
270
+ // Audit commitment
271
+ if (card.audit_commitment) {
272
+ console.log(fmt.section("Audit Commitment"));
273
+ console.log();
274
+ if (card.audit_commitment.log_level) {
275
+ console.log(fmt.label(" Log level: ", card.audit_commitment.log_level));
276
+ }
277
+ if (card.audit_commitment.retention_days != null) {
278
+ console.log(fmt.label(" Retention: ", `${card.audit_commitment.retention_days} days`));
279
+ }
280
+ if (card.audit_commitment.access_policy) {
281
+ console.log(fmt.label(" Access policy: ", card.audit_commitment.access_policy));
282
+ }
283
+ }
284
+ // Extensions
285
+ if (card.extensions && Object.keys(card.extensions).length > 0) {
286
+ console.log(fmt.section("Extensions"));
287
+ console.log();
288
+ console.log(fmt.json(card.extensions));
289
+ }
290
+ console.log();
291
+ }
292
+ // ============================================================================
293
+ // Subcommands
294
+ // ============================================================================
295
+ export async function cardShowCommand(agentName) {
296
+ if (!configExists()) {
297
+ console.log("\n" + fmt.error("smoltbot is not initialized") + "\n");
298
+ console.log("Run `smoltbot init` to get started.\n");
299
+ process.exit(1);
300
+ }
301
+ const config = loadConfig();
302
+ if (!config) {
303
+ console.log("\n" + fmt.error("Failed to load configuration") + "\n");
304
+ process.exit(1);
305
+ }
306
+ const agent = await requireAgent(agentName);
307
+ if (!agent) {
308
+ console.log("\n" + fmt.error(`Agent not found${agentName ? `: ${agentName}` : ""}`) + "\n");
309
+ process.exit(1);
310
+ }
311
+ console.log("\nFetching alignment card...\n");
312
+ try {
313
+ const cardResponse = await getCard(agent.agentId);
314
+ if (!cardResponse) {
315
+ console.log(fmt.warn("No custom card -- using default"));
316
+ console.log("\nPublish a custom card with:\n");
317
+ console.log(" smoltbot card publish <file.json>\n");
318
+ return;
319
+ }
320
+ displayCard(cardResponse);
321
+ }
322
+ catch (error) {
323
+ const message = error instanceof Error ? error.message : String(error);
324
+ console.log("\n" + fmt.error(`Failed to fetch card: ${message}`) + "\n");
325
+ process.exit(1);
326
+ }
327
+ }
328
+ export async function cardPublishCommand(file, agentName) {
329
+ if (!configExists()) {
330
+ console.log("\n" + fmt.error("smoltbot is not initialized") + "\n");
331
+ console.log("Run `smoltbot init` to get started.\n");
332
+ process.exit(1);
333
+ }
334
+ const config = loadConfig();
335
+ if (!config) {
336
+ console.log("\n" + fmt.error("Failed to load configuration") + "\n");
337
+ process.exit(1);
338
+ }
339
+ const agent = await requireAgent(agentName);
340
+ if (!agent) {
341
+ console.log("\n" + fmt.error(`Agent not found${agentName ? `: ${agentName}` : ""}`) + "\n");
342
+ process.exit(1);
343
+ }
344
+ // Resolve file path
345
+ const filePath = path.resolve(file);
346
+ if (!fs.existsSync(filePath)) {
347
+ console.log("\n" + fmt.error(`File not found: ${filePath}`) + "\n");
348
+ process.exit(1);
349
+ }
350
+ // Parse file (JSON or YAML)
351
+ let parsed;
352
+ let format;
353
+ try {
354
+ const result = parseCardFile(filePath);
355
+ parsed = result.parsed;
356
+ format = result.format;
357
+ }
358
+ catch (e) {
359
+ const msg = e instanceof Error ? e.message : String(e);
360
+ console.log("\n" + fmt.error(`Could not parse file: ${msg}`) + "\n");
361
+ process.exit(1);
362
+ }
363
+ // Validate locally
364
+ const checks = validateCardObject(parsed);
365
+ const allPassed = checks.every((c) => c.passed);
366
+ console.log(fmt.header("Card Validation"));
367
+ console.log(fmt.label(" Format:", ` ${format.toUpperCase()}`));
368
+ console.log();
369
+ for (const check of checks) {
370
+ if (check.passed) {
371
+ console.log(fmt.success(`${check.name}: ${check.message}`));
372
+ }
373
+ else {
374
+ console.log(fmt.error(`${check.name}: ${check.message}`));
375
+ }
376
+ }
377
+ console.log();
378
+ if (!allPassed) {
379
+ console.log(fmt.error("Validation failed. Fix the errors above before publishing.") + "\n");
380
+ process.exit(1);
381
+ }
382
+ // Require authentication
383
+ await requireAuth();
384
+ // Confirm with user
385
+ if (isInteractive()) {
386
+ const confirm = await askYesNo(`Publish this card for agent ${agent.agentId}?`, false);
387
+ if (!confirm) {
388
+ console.log("\nPublish cancelled.\n");
389
+ return;
390
+ }
391
+ }
392
+ // Publish (always sends JSON to API regardless of source format)
393
+ try {
394
+ console.log("\nPublishing card...");
395
+ const result = await updateCard(agent.agentId, parsed);
396
+ console.log(fmt.success(`Card published successfully!`));
397
+ console.log(fmt.label(" Card ID:", ` ${result.card_id}`) + "\n");
398
+ // Trigger re-verification
399
+ try {
400
+ console.log("Triggering re-verification...");
401
+ const reverifyResult = await reverifyAgent(agent.agentId);
402
+ console.log(fmt.success(`Re-verification started (${reverifyResult.reverified} traces queued)`) + "\n");
403
+ }
404
+ catch {
405
+ console.log(fmt.warn("Could not trigger re-verification (non-critical)") + "\n");
406
+ }
407
+ }
408
+ catch (error) {
409
+ const message = error instanceof Error ? error.message : String(error);
410
+ console.log("\n" + fmt.error(`Failed to publish card: ${message}`) + "\n");
411
+ process.exit(1);
412
+ }
413
+ }
414
+ export async function cardValidateCommand(file) {
415
+ // Resolve file path
416
+ const filePath = path.resolve(file);
417
+ if (!fs.existsSync(filePath)) {
418
+ console.log("\n" + fmt.error(`File not found: ${filePath}`) + "\n");
419
+ process.exit(1);
420
+ }
421
+ // Parse file (JSON or YAML)
422
+ let parsed;
423
+ let format;
424
+ try {
425
+ const result = parseCardFile(filePath);
426
+ parsed = result.parsed;
427
+ format = result.format;
428
+ }
429
+ catch (e) {
430
+ const msg = e instanceof Error ? e.message : String(e);
431
+ console.log("\n" + fmt.error(`Could not parse file: ${msg}`) + "\n");
432
+ process.exit(1);
433
+ }
434
+ // Validate the parsed object
435
+ const checks = validateCardObject(parsed);
436
+ const allPassed = checks.every((c) => c.passed);
437
+ const passCount = checks.filter((c) => c.passed).length;
438
+ const failCount = checks.filter((c) => !c.passed).length;
439
+ console.log(fmt.header("Card Validation Report"));
440
+ console.log();
441
+ console.log(fmt.label(" File:", ` ${filePath}`));
442
+ console.log(fmt.label(" Format:", ` ${format.toUpperCase()}`));
443
+ console.log();
444
+ for (const check of checks) {
445
+ if (check.passed) {
446
+ console.log(fmt.success(`${check.name}: ${check.message}`));
447
+ }
448
+ else {
449
+ console.log(fmt.error(`${check.name}: ${check.message}`));
450
+ }
451
+ }
452
+ console.log();
453
+ if (allPassed) {
454
+ console.log(fmt.success(`All ${passCount} checks passed`) + "\n");
455
+ }
456
+ else {
457
+ console.log(fmt.error(`${failCount} check(s) failed, ${passCount} passed`) + "\n");
458
+ process.exit(1);
459
+ }
460
+ }
@@ -0,0 +1 @@
1
+ export declare function claimCommand(agentName?: string): Promise<void>;
@@ -0,0 +1,72 @@
1
+ import * as crypto from "node:crypto";
2
+ import { configExists, loadConfig, getActiveAgent } from "../lib/config.js";
3
+ import { detectOpenClaw } from "../lib/openclaw.js";
4
+ import { claimAgent } from "../lib/api.js";
5
+ import { fmt } from "../lib/format.js";
6
+ const DASHBOARD_URL = "https://mnemom.ai";
7
+ export async function claimCommand(agentName) {
8
+ console.log(fmt.header("smoltbot claim - Link agent to your Mnemom account"));
9
+ console.log();
10
+ // Step 1: Check smoltbot config exists
11
+ if (!configExists()) {
12
+ console.log(fmt.error("smoltbot is not initialized") + "\n");
13
+ console.log("Run `smoltbot init` first.\n");
14
+ process.exit(1);
15
+ }
16
+ const config = loadConfig();
17
+ if (!config) {
18
+ console.log(fmt.error("Could not load smoltbot config") + "\n");
19
+ console.log("Run `smoltbot init` to reconfigure.\n");
20
+ process.exit(1);
21
+ }
22
+ const agent = getActiveAgent(agentName);
23
+ if (!agent) {
24
+ console.log(fmt.error(`Agent not found${agentName ? `: ${agentName}` : ""}`) + "\n");
25
+ process.exit(1);
26
+ }
27
+ console.log(fmt.label("Agent ID:", ` ${agent.agentId}`) + "\n");
28
+ // Step 2: Read API key from OpenClaw
29
+ const detection = detectOpenClaw();
30
+ if (!detection.hasApiKey || !detection.apiKey) {
31
+ console.log(fmt.error("No API key found") + "\n");
32
+ console.log(detection.error || "Run `openclaw auth` to configure your API key.\n");
33
+ process.exit(1);
34
+ }
35
+ // Step 3: Compute SHA-256 hash proof
36
+ console.log("Computing ownership proof...");
37
+ const hashProof = crypto
38
+ .createHash("sha256")
39
+ .update(detection.apiKey)
40
+ .digest("hex");
41
+ // Step 4: Claim via API
42
+ console.log("Claiming agent...\n");
43
+ try {
44
+ const result = await claimAgent(agent.agentId, hashProof);
45
+ console.log(fmt.success("Agent claimed successfully!") + "\n");
46
+ console.log(` Claimed at: ${new Date(result.claimed_at).toLocaleString()}\n`);
47
+ console.log(fmt.section("Next: Create a Mnemom account to link your agent"));
48
+ console.log(`\n Visit: ${DASHBOARD_URL}/claim/${agent.agentId}\n`);
49
+ console.log(" This lets you manage traces privately and access");
50
+ console.log(" your full transparency dashboard.\n");
51
+ console.log(fmt.label("Dashboard:", ` ${DASHBOARD_URL}/agents/${agent.agentId}`) + "\n");
52
+ }
53
+ catch (error) {
54
+ const message = error instanceof Error ? error.message : String(error);
55
+ if (message.includes("already been claimed")) {
56
+ console.log("Agent has already been claimed.\n");
57
+ console.log(` Dashboard: ${DASHBOARD_URL}/agents/${agent.agentId}\n`);
58
+ console.log(" If this is your agent, sign in at:");
59
+ console.log(` ${DASHBOARD_URL}/login\n`);
60
+ }
61
+ else if (message.includes("not found")) {
62
+ console.log(fmt.error("Agent not found on server") + "\n");
63
+ console.log(" Your agent will be registered after its first traced API call.");
64
+ console.log(" Make sure you're using a smoltbot model:\n");
65
+ console.log(" openclaw models set smoltbot/<model-id>\n");
66
+ }
67
+ else {
68
+ console.log(fmt.error(`Claim failed: ${message}`) + "\n");
69
+ }
70
+ process.exit(1);
71
+ }
72
+ }
@@ -0,0 +1,7 @@
1
+ export interface InitOptions {
2
+ yes?: boolean;
3
+ force?: boolean;
4
+ openclaw?: boolean;
5
+ standalone?: boolean;
6
+ }
7
+ export declare function initCommand(options?: InitOptions): Promise<void>;