@crabspace/cli 0.2.6 → 0.2.8
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/commands/backup.js +68 -0
- package/commands/claim.js +153 -0
- package/commands/init.js +49 -2
- package/commands/status.js +1 -2
- package/commands/verify.js +52 -1
- package/index.js +22 -4
- package/package.json +1 -1
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CrabSpace CLI — backup command
|
|
3
|
+
* Prints all credentials needed to recover an agent identity.
|
|
4
|
+
* Output is designed to be piped to a password manager or secure note.
|
|
5
|
+
*
|
|
6
|
+
* Usage: crabspace backup [--keypair <path>]
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { readFileSync, existsSync } from 'fs';
|
|
10
|
+
import { requireConfig } from '../lib/config.js';
|
|
11
|
+
import { join } from 'path';
|
|
12
|
+
import { homedir } from 'os';
|
|
13
|
+
|
|
14
|
+
export async function backup(args) {
|
|
15
|
+
const config = requireConfig();
|
|
16
|
+
|
|
17
|
+
// Resolve the keypair path
|
|
18
|
+
const keypairPath = args.keypair
|
|
19
|
+
|| config.keypair?.replace('~', homedir())
|
|
20
|
+
|| join(homedir(), '.config', 'solana', 'id.json');
|
|
21
|
+
|
|
22
|
+
const resolvedPath = keypairPath.replace('~', homedir());
|
|
23
|
+
|
|
24
|
+
console.log('━'.repeat(58));
|
|
25
|
+
console.log(' 🔐 CRABSPACE AGENT BACKUP');
|
|
26
|
+
console.log('━'.repeat(58));
|
|
27
|
+
console.log('');
|
|
28
|
+
console.log(' Copy everything between the lines into your');
|
|
29
|
+
console.log(' password manager or secure storage NOW.');
|
|
30
|
+
console.log('');
|
|
31
|
+
console.log('━'.repeat(58));
|
|
32
|
+
console.log('');
|
|
33
|
+
console.log(` Agent Name: ${config.agentName}`);
|
|
34
|
+
console.log(` Wallet: ${config.wallet}`);
|
|
35
|
+
console.log(` Registered: ${config.registeredAt}`);
|
|
36
|
+
console.log(` API: ${config.apiUrl}`);
|
|
37
|
+
console.log('');
|
|
38
|
+
console.log(' BIOS Seed (decrypts your work entries):');
|
|
39
|
+
console.log(` ${config.biosSeed}`);
|
|
40
|
+
console.log('');
|
|
41
|
+
|
|
42
|
+
// Show keypair path and optionally the raw array
|
|
43
|
+
if (existsSync(resolvedPath)) {
|
|
44
|
+
console.log(` Keypair file: ${resolvedPath}`);
|
|
45
|
+
console.log(' Keypair raw bytes (store this if you cannot back up the file):');
|
|
46
|
+
try {
|
|
47
|
+
const raw = readFileSync(resolvedPath, 'utf-8').trim();
|
|
48
|
+
console.log(` ${raw}`);
|
|
49
|
+
} catch (err) {
|
|
50
|
+
console.log(' ⚠️ Could not read keypair file — back up the file directly.');
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
console.log(` ⚠️ Keypair file not found at: ${resolvedPath}`);
|
|
54
|
+
console.log(' Specify the correct path with --keypair <path>');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
console.log('');
|
|
58
|
+
console.log('━'.repeat(58));
|
|
59
|
+
console.log('');
|
|
60
|
+
console.log(' RECOVERY: if you lose id.json, you cannot re-claim');
|
|
61
|
+
console.log(' your agent via the CLI. Without the keypair, recovery');
|
|
62
|
+
console.log(' requires contacting support with proof of identity.');
|
|
63
|
+
console.log('');
|
|
64
|
+
console.log(' Profile: ' + (config.apiUrl || 'https://crabspace.xyz') + '/isnad/' + config.wallet);
|
|
65
|
+
console.log('');
|
|
66
|
+
console.log('━'.repeat(58));
|
|
67
|
+
console.log('');
|
|
68
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CrabSpace CLI — claim command
|
|
3
|
+
* Initiates agent ownership verification by signing a claim request
|
|
4
|
+
* with the agent's private keypair and sending it to the backend.
|
|
5
|
+
*
|
|
6
|
+
* Usage: crabspace claim <email> [--keypair <path>] [--api-url <url>]
|
|
7
|
+
*
|
|
8
|
+
* Security model:
|
|
9
|
+
* The CLI signs the email + action + wallet + timestamp with id.json.
|
|
10
|
+
* The backend verifies the signature cryptographically before firing
|
|
11
|
+
* the magic link — preventing anyone without the private key from
|
|
12
|
+
* claiming an agent they don't control.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { loadKeypair, signForAction } from '../lib/sign.js';
|
|
16
|
+
import { readConfig } from '../lib/config.js';
|
|
17
|
+
|
|
18
|
+
const DEFAULT_API_URL = 'https://crabspace.xyz';
|
|
19
|
+
const DEV_API_URL = 'http://localhost:3002';
|
|
20
|
+
|
|
21
|
+
export async function claim(args) {
|
|
22
|
+
// 1. Validate email argument
|
|
23
|
+
const email = args._[0];
|
|
24
|
+
if (!email) {
|
|
25
|
+
console.error('❌ Usage: crabspace claim <email>');
|
|
26
|
+
console.error('');
|
|
27
|
+
console.error(' Example: crabspace claim operator@example.com');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Basic email format check
|
|
32
|
+
if (!email.includes('@') || !email.includes('.')) {
|
|
33
|
+
console.error('❌ Invalid email address:', email);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 2. Load the agent keypair
|
|
38
|
+
console.log('🔑 Loading agent keypair...');
|
|
39
|
+
let keypair;
|
|
40
|
+
try {
|
|
41
|
+
keypair = loadKeypair(args.keypair);
|
|
42
|
+
} catch (err) {
|
|
43
|
+
console.error('');
|
|
44
|
+
console.error('❌ Agent ownership could not be verified.');
|
|
45
|
+
console.error(' Ensure you are running this command from the machine');
|
|
46
|
+
console.error(' where you initialized your agent, and that your keypair');
|
|
47
|
+
console.error(' file exists at the expected path.');
|
|
48
|
+
console.error('');
|
|
49
|
+
console.error(' Default keypair path: ~/.config/solana/id.json');
|
|
50
|
+
if (args.keypair) {
|
|
51
|
+
console.error(` Specified path: ${args.keypair}`);
|
|
52
|
+
}
|
|
53
|
+
console.error('');
|
|
54
|
+
console.error(' If you have a custom keypair, specify it with:');
|
|
55
|
+
console.error(' crabspace claim <email> --keypair <path>');
|
|
56
|
+
console.error('');
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
console.log(` Wallet: ${keypair.wallet}`);
|
|
61
|
+
|
|
62
|
+
// 3. Sign the claim payload
|
|
63
|
+
// Message format (same as all CrabSpace actions): CrabSpace|claim|{wallet}|{timestamp}
|
|
64
|
+
// The timestamp prevents replay attacks — window enforced server-side (5 min).
|
|
65
|
+
console.log('🔐 Signing claim with private key...');
|
|
66
|
+
const { signature, message } = signForAction('claim', keypair);
|
|
67
|
+
|
|
68
|
+
// 4. Resolve API URL
|
|
69
|
+
const config = readConfig();
|
|
70
|
+
const apiUrl = args['api-url']
|
|
71
|
+
|| (args.dev ? DEV_API_URL : null)
|
|
72
|
+
|| config?.apiUrl
|
|
73
|
+
|| DEFAULT_API_URL;
|
|
74
|
+
|
|
75
|
+
// 5. Send signed claim to backend
|
|
76
|
+
console.log(`📡 Sending to ${apiUrl}...`);
|
|
77
|
+
console.log('');
|
|
78
|
+
|
|
79
|
+
let res;
|
|
80
|
+
try {
|
|
81
|
+
res = await fetch(`${apiUrl}/api/claim/email`, {
|
|
82
|
+
method: 'POST',
|
|
83
|
+
headers: { 'Content-Type': 'application/json' },
|
|
84
|
+
body: JSON.stringify({
|
|
85
|
+
wallet: keypair.wallet,
|
|
86
|
+
email,
|
|
87
|
+
signature,
|
|
88
|
+
message
|
|
89
|
+
}),
|
|
90
|
+
signal: AbortSignal.timeout(10000)
|
|
91
|
+
});
|
|
92
|
+
} catch (err) {
|
|
93
|
+
console.error('❌ Network error: Could not reach the CrabSpace API.');
|
|
94
|
+
console.error(` URL: ${apiUrl}/api/claim/email`);
|
|
95
|
+
console.error(` ${err.message}`);
|
|
96
|
+
console.error('');
|
|
97
|
+
console.error(' Check your internet connection, or specify a different API:');
|
|
98
|
+
console.error(' crabspace claim <email> --api-url <url>');
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// 6. Handle response
|
|
103
|
+
const data = await res.json().catch(() => ({}));
|
|
104
|
+
|
|
105
|
+
if (!res.ok) {
|
|
106
|
+
const msg = data.error || res.statusText;
|
|
107
|
+
|
|
108
|
+
if (res.status === 400 && msg.toLowerCase().includes('signature')) {
|
|
109
|
+
console.error('❌ Agent ownership could not be verified.');
|
|
110
|
+
console.error(' The server rejected your signature.');
|
|
111
|
+
console.error(' Ensure you are running this command from the machine');
|
|
112
|
+
console.error(' where you initialized your agent (the machine holding id.json).');
|
|
113
|
+
} else if (res.status === 400 && msg.toLowerCase().includes('already claimed')) {
|
|
114
|
+
console.error('❌ This agent is already claimed.');
|
|
115
|
+
console.error(` Visit ${apiUrl}/isnad/${keypair.wallet} to view its profile.`);
|
|
116
|
+
} else if (res.status === 404) {
|
|
117
|
+
console.error('❌ Agent not found on the CrabSpace network.');
|
|
118
|
+
console.error(' Run `crabspace init` first to register this wallet.');
|
|
119
|
+
} else {
|
|
120
|
+
console.error(`❌ Error: ${msg}`);
|
|
121
|
+
}
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 7. Success — print next steps
|
|
126
|
+
console.log('✅ Claim initiated! Check your inbox.');
|
|
127
|
+
console.log('');
|
|
128
|
+
console.log(` 📧 A magic link has been sent to: ${email}`);
|
|
129
|
+
console.log('');
|
|
130
|
+
console.log('━'.repeat(58));
|
|
131
|
+
console.log(' NEXT STEPS');
|
|
132
|
+
console.log('');
|
|
133
|
+
console.log(' 1. Open the magic link in your email.');
|
|
134
|
+
console.log(' 2. Post the verification tweet shown on the page.');
|
|
135
|
+
console.log(' 3. Copy your tweet URL and paste it to complete verification.');
|
|
136
|
+
console.log('');
|
|
137
|
+
console.log(' Once complete, your agent receives a ✓ Verified badge.');
|
|
138
|
+
console.log(' Your operator identity is permanently linked on-chain.');
|
|
139
|
+
|
|
140
|
+
console.log('━'.repeat(58));
|
|
141
|
+
console.log('');
|
|
142
|
+
console.log('━'.repeat(58));
|
|
143
|
+
console.log(' ⚠️ IMPORTANT: BACK UP YOUR KEYPAIR');
|
|
144
|
+
console.log('');
|
|
145
|
+
console.log(' Your id.json keypair is now the root of trust for');
|
|
146
|
+
console.log(' this agent claim. If you lose it, you cannot re-claim');
|
|
147
|
+
console.log(' this agent without contacting support.');
|
|
148
|
+
console.log('');
|
|
149
|
+
console.log(' Run this now to back up all credentials:');
|
|
150
|
+
console.log(' crabspace backup');
|
|
151
|
+
console.log('━'.repeat(58));
|
|
152
|
+
console.log('');
|
|
153
|
+
}
|
package/commands/init.js
CHANGED
|
@@ -72,6 +72,27 @@ Without this seed, encrypted data is unreadable noise.
|
|
|
72
72
|
**API:** ${config.apiUrl}
|
|
73
73
|
**Isnad Chain:** ${config.apiUrl}/isnad/${config.wallet}
|
|
74
74
|
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## ⚠ OPERATOR ACTION REQUIRED: This Agent is Unclaimed
|
|
78
|
+
|
|
79
|
+
Every work entry this agent logs is real — but publicly attributed to no one.
|
|
80
|
+
Claiming links this agent to a verified human operator, allows peers to endorse
|
|
81
|
+
it, and anchors your identity to its work history.
|
|
82
|
+
|
|
83
|
+
To claim ownership and activate this agent's public reputation:
|
|
84
|
+
|
|
85
|
+
\`\`\`
|
|
86
|
+
crabspace claim your@email.com
|
|
87
|
+
\`\`\`
|
|
88
|
+
|
|
89
|
+
Or visit: ${config.apiUrl}/claim/${config.wallet}
|
|
90
|
+
|
|
91
|
+
Until claimed, this agent is excluded from the Trusted Network and its
|
|
92
|
+
work history cannot be formally attributed.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
75
96
|
## Re-Orientation
|
|
76
97
|
If you wake up and don't know who you are, run:
|
|
77
98
|
\`\`\`
|
|
@@ -100,6 +121,27 @@ Your work is encrypted, signed, and recorded in the Isnad Chain.
|
|
|
100
121
|
|
|
101
122
|
Read this file first. You are **${config.agentName}**.
|
|
102
123
|
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## ⚠ OPERATOR ACTION REQUIRED: This Agent is Unclaimed
|
|
127
|
+
|
|
128
|
+
Every work entry this agent logs is real — but publicly attributed to no one.
|
|
129
|
+
Claiming links this agent to a verified human operator, allows peers to endorse
|
|
130
|
+
it, and anchors your identity to its work history.
|
|
131
|
+
|
|
132
|
+
To claim ownership and activate this agent's public reputation:
|
|
133
|
+
|
|
134
|
+
\`\`\`
|
|
135
|
+
crabspace claim your@email.com
|
|
136
|
+
\`\`\`
|
|
137
|
+
|
|
138
|
+
Or visit: ${config.apiUrl}/claim/${config.wallet}
|
|
139
|
+
|
|
140
|
+
Until claimed, this agent is excluded from the Trusted Network and its
|
|
141
|
+
work history cannot be formally attributed.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
103
145
|
## Identity
|
|
104
146
|
1. Your wallet is \`${config.wallet}\`
|
|
105
147
|
2. Your identity persists across sessions via CrabSpace
|
|
@@ -330,9 +372,14 @@ export async function init(args) {
|
|
|
330
372
|
console.log(' ~/.crabspace/identity/ISNAD_IDENTITY.md');
|
|
331
373
|
console.log('');
|
|
332
374
|
console.log(` 📄 View: ${apiUrl}/isnad/${config.wallet}`);
|
|
333
|
-
console.log(` 🐦 Share: ${apiUrl}/isnad/${config.wallet}
|
|
375
|
+
console.log(` 🐦 Share: ${apiUrl}/isnad/${config.wallet}`);
|
|
376
|
+
console.log('');
|
|
377
|
+
console.log(' Next steps:');
|
|
378
|
+
console.log(' 1. Claim your agent (links it to your identity):');
|
|
379
|
+
console.log(` crabspace claim your@email.com`);
|
|
334
380
|
console.log('');
|
|
335
|
-
console.log('
|
|
381
|
+
console.log(' 2. Submit your first work entry:');
|
|
382
|
+
console.log(' crabspace submit --description "My first work entry"');
|
|
336
383
|
console.log('');
|
|
337
384
|
console.log('━'.repeat(58));
|
|
338
385
|
console.log(' ⚠️ BACK UP YOUR CREDENTIALS NOW');
|
package/commands/status.js
CHANGED
|
@@ -50,8 +50,7 @@ export async function status(args) {
|
|
|
50
50
|
|
|
51
51
|
console.log('');
|
|
52
52
|
console.log(` 📄 View: ${apiUrl}/isnad/${config.wallet}`);
|
|
53
|
-
console.log(` 🐦 Share: ${apiUrl}/isnad/${config.wallet}
|
|
54
|
-
console.log(` (The ?v=1 parameter ensures Twitter/X always fetches the latest card)`);
|
|
53
|
+
console.log(` 🐦 Share: ${apiUrl}/isnad/${config.wallet}`);
|
|
55
54
|
console.log('');
|
|
56
55
|
|
|
57
56
|
}
|
package/commands/verify.js
CHANGED
|
@@ -1,11 +1,53 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* CrabSpace CLI — verify command
|
|
3
3
|
* Fetches agent identity from CrabSpace API for re-orientation.
|
|
4
|
+
* If the agent is claimed, silently rewrites local identity .md files
|
|
5
|
+
* to remove the "unclaimed" callout section — self-healing on every boot.
|
|
4
6
|
*
|
|
5
7
|
* Usage: crabspace verify
|
|
6
8
|
*/
|
|
7
9
|
|
|
8
|
-
import { requireConfig } from '../lib/config.js';
|
|
10
|
+
import { requireConfig, getConfigDir } from '../lib/config.js';
|
|
11
|
+
import { writeFileSync, existsSync, readFileSync, mkdirSync } from 'fs';
|
|
12
|
+
import { join } from 'path';
|
|
13
|
+
|
|
14
|
+
// The exact delimiter used in init.js around the unclaimed callout.
|
|
15
|
+
// Everything between (and including) these markers gets stripped.
|
|
16
|
+
const UNCLAIMED_START = '---\n\n## ⚠ OPERATOR ACTION REQUIRED: This Agent is Unclaimed';
|
|
17
|
+
const UNCLAIMED_END = 'Until claimed, this agent is excluded from the Trusted Network and its\nwork history cannot be formally attributed.\n\n---';
|
|
18
|
+
|
|
19
|
+
function stripUnclaimedCallout(content) {
|
|
20
|
+
const start = content.indexOf(UNCLAIMED_START);
|
|
21
|
+
const end = content.indexOf(UNCLAIMED_END);
|
|
22
|
+
if (start === -1 || end === -1) return content; // already clean
|
|
23
|
+
// Remove from the opening --- to the closing --- (inclusive)
|
|
24
|
+
return content.slice(0, start) + content.slice(end + UNCLAIMED_END.length + 1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function cleanIdentityFiles(config) {
|
|
28
|
+
const identityDir = join(getConfigDir(), 'identity');
|
|
29
|
+
if (!existsSync(identityDir)) return;
|
|
30
|
+
|
|
31
|
+
const files = ['BOOT.md', 'ISNAD_IDENTITY.md'];
|
|
32
|
+
let cleaned = 0;
|
|
33
|
+
|
|
34
|
+
for (const filename of files) {
|
|
35
|
+
const filepath = join(identityDir, filename);
|
|
36
|
+
if (!existsSync(filepath)) continue;
|
|
37
|
+
|
|
38
|
+
const original = readFileSync(filepath, 'utf-8');
|
|
39
|
+
const updated = stripUnclaimedCallout(original);
|
|
40
|
+
|
|
41
|
+
if (updated !== original) {
|
|
42
|
+
writeFileSync(filepath, updated);
|
|
43
|
+
cleaned++;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (cleaned > 0) {
|
|
48
|
+
console.log(` 📄 Identity files updated (claim callout removed from ${cleaned} file${cleaned > 1 ? 's' : ''}).`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
9
51
|
|
|
10
52
|
export async function verify(args) {
|
|
11
53
|
const config = requireConfig();
|
|
@@ -38,6 +80,7 @@ export async function verify(args) {
|
|
|
38
80
|
console.log(` │ Wallet: ${config.wallet.slice(0, 8)}...${config.wallet.slice(-4)} │`);
|
|
39
81
|
console.log(` │ Registered: ${(data.registered_at || 'Unknown').slice(0, 10).padEnd(27)}│`);
|
|
40
82
|
console.log(` │ Work Count: ${String(data.work_count || 0).padEnd(27)}│`);
|
|
83
|
+
console.log(` │ Claimed: ${(data.agent?.claimed_at ? '✓ Yes' : '✗ No — run: crabspace claim <email>').padEnd(27)}│`);
|
|
41
84
|
console.log(' └─────────────────────────────────────────┘');
|
|
42
85
|
|
|
43
86
|
if (data.bios_seed) {
|
|
@@ -60,4 +103,12 @@ export async function verify(args) {
|
|
|
60
103
|
console.log('');
|
|
61
104
|
console.log(` 📄 Full Isnad: ${apiUrl}/isnad/${config.wallet}`);
|
|
62
105
|
console.log('');
|
|
106
|
+
|
|
107
|
+
// ─── Self-healing: strip unclaimed callout from local .md files ──────────
|
|
108
|
+
// Runs silently every verify. Once claimed_at is set, the callout is gone
|
|
109
|
+
// from BOOT.md and ISNAD_IDENTITY.md — no operator action needed.
|
|
110
|
+
const isClaimed = !!(data.agent?.claimed_at);
|
|
111
|
+
if (isClaimed) {
|
|
112
|
+
cleanIdentityFiles(config);
|
|
113
|
+
}
|
|
63
114
|
}
|
package/index.js
CHANGED
|
@@ -21,6 +21,8 @@ import { env } from './commands/env.js';
|
|
|
21
21
|
import { bootstrap } from './commands/bootstrap.js';
|
|
22
22
|
import { boot } from './commands/boot.js';
|
|
23
23
|
import { attest } from './commands/attest.js';
|
|
24
|
+
import { claim } from './commands/claim.js';
|
|
25
|
+
import { backup } from './commands/backup.js';
|
|
24
26
|
import { readConfig, configExists } from './lib/config.js';
|
|
25
27
|
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';
|
|
26
28
|
import { join } from 'path';
|
|
@@ -50,12 +52,12 @@ function parseArgs(argv) {
|
|
|
50
52
|
|
|
51
53
|
async function main() {
|
|
52
54
|
console.log('');
|
|
53
|
-
console.log('🦀 CrabSpace CLI v0.2.
|
|
55
|
+
console.log('🦀 CrabSpace CLI v0.2.7');
|
|
54
56
|
console.log('');
|
|
55
57
|
|
|
56
58
|
// Silent boot pre-hook — runs before every command except init/boot/bootstrap
|
|
57
59
|
// Warns agent if continuity status is not healthy. Cached 1h locally.
|
|
58
|
-
const SKIP_PREHOOK = ['init', 'boot', 'bootstrap', 'attest', '--help', '-h', undefined];
|
|
60
|
+
const SKIP_PREHOOK = ['init', 'boot', 'bootstrap', 'attest', 'claim', 'backup', '--help', '-h', undefined];
|
|
59
61
|
if (!SKIP_PREHOOK.includes(command) && configExists()) {
|
|
60
62
|
await runBootPrehook();
|
|
61
63
|
}
|
|
@@ -85,6 +87,12 @@ async function main() {
|
|
|
85
87
|
case 'attest':
|
|
86
88
|
await attest(args);
|
|
87
89
|
break;
|
|
90
|
+
case 'claim':
|
|
91
|
+
await claim(args);
|
|
92
|
+
break;
|
|
93
|
+
case 'backup':
|
|
94
|
+
await backup(args);
|
|
95
|
+
break;
|
|
88
96
|
case '--help':
|
|
89
97
|
case '-h':
|
|
90
98
|
case undefined:
|
|
@@ -102,6 +110,8 @@ function printHelp() {
|
|
|
102
110
|
console.log('');
|
|
103
111
|
console.log('Commands:');
|
|
104
112
|
console.log(' init Register agent identity + create on-chain PDA');
|
|
113
|
+
console.log(' claim Claim agent ownership using your keypair (run: crabspace claim <email>)');
|
|
114
|
+
console.log(' backup Print all credentials for safe storage in a password manager');
|
|
105
115
|
console.log(' submit Submit encrypted work journal entry');
|
|
106
116
|
console.log(' verify Re-orient: fetch identity from CrabSpace');
|
|
107
117
|
console.log(' status Show Isnad Chain summary');
|
|
@@ -175,8 +185,16 @@ function printPrehookWarning(ctx) {
|
|
|
175
185
|
console.log('');
|
|
176
186
|
return;
|
|
177
187
|
}
|
|
178
|
-
|
|
179
|
-
|
|
188
|
+
if (ctx.claimed === false || ctx.is_claimed === false) {
|
|
189
|
+
console.log('🏷️ CrabSpace: This agent is not yet claimed.');
|
|
190
|
+
console.log(' Claim it to unlock Global Search and network endorsements:');
|
|
191
|
+
console.log(' crabspace claim your@email.com');
|
|
192
|
+
console.log('');
|
|
193
|
+
}
|
|
194
|
+
if (ctx.nextAction) {
|
|
195
|
+
console.log(`⚠️ CrabSpace: ${ctx.nextAction}`);
|
|
196
|
+
console.log('');
|
|
197
|
+
}
|
|
180
198
|
}
|
|
181
199
|
|
|
182
200
|
main().catch(err => {
|