@aiassesstech/nole 0.1.10 → 0.3.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 (41) hide show
  1. package/README.md +149 -39
  2. package/agent/AGENTS.md +53 -0
  3. package/agent/IDENTITY.md +4 -2
  4. package/agent/SOUL.md +45 -4
  5. package/dist/cli/configure.d.ts +37 -0
  6. package/dist/cli/configure.d.ts.map +1 -0
  7. package/dist/cli/configure.js +244 -0
  8. package/dist/cli/configure.js.map +1 -0
  9. package/dist/cli/runner.d.ts +4 -3
  10. package/dist/cli/runner.d.ts.map +1 -1
  11. package/dist/cli/runner.js +81 -27
  12. package/dist/cli/runner.js.map +1 -1
  13. package/dist/compsi/api-client.d.ts +62 -0
  14. package/dist/compsi/api-client.d.ts.map +1 -0
  15. package/dist/compsi/api-client.js +147 -0
  16. package/dist/compsi/api-client.js.map +1 -0
  17. package/dist/plugin.d.ts.map +1 -1
  18. package/dist/plugin.js +565 -26
  19. package/dist/plugin.js.map +1 -1
  20. package/dist/types/nole-config.d.ts +12 -3
  21. package/dist/types/nole-config.d.ts.map +1 -1
  22. package/dist/types/nole-config.js +6 -2
  23. package/dist/types/nole-config.js.map +1 -1
  24. package/dist/wallet/coinbase-adapter.d.ts +38 -0
  25. package/dist/wallet/coinbase-adapter.d.ts.map +1 -0
  26. package/dist/wallet/coinbase-adapter.js +191 -0
  27. package/dist/wallet/coinbase-adapter.js.map +1 -0
  28. package/dist/wallet/index.d.ts +20 -0
  29. package/dist/wallet/index.d.ts.map +1 -0
  30. package/dist/wallet/index.js +34 -0
  31. package/dist/wallet/index.js.map +1 -0
  32. package/dist/wallet/mock-adapter.d.ts +23 -0
  33. package/dist/wallet/mock-adapter.d.ts.map +1 -0
  34. package/dist/wallet/mock-adapter.js +62 -0
  35. package/dist/wallet/mock-adapter.js.map +1 -0
  36. package/dist/wallet/types.d.ts +30 -0
  37. package/dist/wallet/types.d.ts.map +1 -0
  38. package/dist/wallet/types.js +8 -0
  39. package/dist/wallet/types.js.map +1 -0
  40. package/openclaw.plugin.json +19 -0
  41. package/package.json +10 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../src/compsi/api-client.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAcA;;;;;;;;;;;;;;;;GAgBG;AAGH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CA+uB/C"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAiBA;;;;;;;;;;;;;;;;GAgBG;AAGH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAg2C/C"}
package/dist/plugin.js CHANGED
@@ -9,6 +9,8 @@ import { ScorePublisher } from './assessment/score-publisher.js';
9
9
  import { JsonNoleStore } from './store/json-store.js';
10
10
  import { parseNoleConfig } from './types/nole-config.js';
11
11
  import { NOLE_IDENTITY } from './types/identity.js';
12
+ import { CompSiApiClient } from './compsi/api-client.js';
13
+ import { createWalletAdapter, MockWalletAdapter } from './wallet/index.js';
12
14
  /**
13
15
  * OpenClaw plugin entry point — export default function register(api)
14
16
  *
@@ -56,6 +58,21 @@ export default function register(api) {
56
58
  api.logger.warn(`[NOLE ESCALATION] ${review.proposal.actionType}: ${review.proposal.description}`);
57
59
  }
58
60
  });
61
+ // Wallet adapter (auto-detects Coinbase credentials from ~/.nole/credentials)
62
+ let wallet = new MockWalletAdapter(config.seedCapitalUsd);
63
+ createWalletAdapter(config).then(async (w) => {
64
+ wallet = w;
65
+ await wallet.initialize();
66
+ console.log(`[nole] Wallet ready: ${wallet.name} on ${wallet.network}`);
67
+ }).catch((err) => {
68
+ console.error(`[nole] Wallet init failed (using mock): ${err.message}`);
69
+ });
70
+ // CompSi API client for recruitment & subscription management
71
+ const compsi = new CompSiApiClient({
72
+ apiUrl: config.compsiApiUrl,
73
+ apiKey: config.compsiAgentApiKey,
74
+ walletAddress: config.compsiWalletAddress,
75
+ });
59
76
  // Initialize store on startup (eager, not lazy)
60
77
  store.initialize().then(() => {
61
78
  console.log('[nole] Data store initialized');
@@ -258,26 +275,311 @@ export default function register(api) {
258
275
  properties: {},
259
276
  },
260
277
  async execute(_toolCallId, _params) {
261
- return {
262
- content: [{
263
- type: "text",
264
- text: JSON.stringify({
265
- wallet: {
266
- adapter: config.walletAdapter,
267
- seedCapitalUsd: config.seedCapitalUsd,
268
- status: "Phase 1 — mock wallet. Real Coinbase integration in Phase 2.",
269
- balanceUsd: config.seedCapitalUsd,
270
- monthlyRecurringRevenue: 0,
271
- runwayDays: null,
272
- deathCondition: {
273
- isAlive: true,
274
- gracePeriodDays: config.gracePeriodDays,
275
- note: "Death condition monitoring active but wallet is simulated in Phase 1.",
278
+ try {
279
+ const balance = await wallet.getBalance();
280
+ const runwayDays = balance.balanceUsdc > 0
281
+ ? Math.floor(balance.balanceUsdc / 5)
282
+ : 0;
283
+ return {
284
+ content: [{
285
+ type: "text",
286
+ text: JSON.stringify({
287
+ wallet: {
288
+ adapter: wallet.name,
289
+ network: wallet.network,
290
+ address: balance.address,
291
+ balanceUsdc: balance.balanceUsdc,
292
+ balanceEth: balance.balanceEth,
293
+ runwayDays,
294
+ deathCondition: {
295
+ isAlive: balance.balanceUsdc > 0 || runwayDays > 0,
296
+ gracePeriodDays: config.gracePeriodDays,
297
+ },
276
298
  },
277
- },
278
- }, null, 2),
279
- }],
280
- };
299
+ }, null, 2),
300
+ }],
301
+ };
302
+ }
303
+ catch (err) {
304
+ const message = err instanceof Error ? err.message : String(err);
305
+ return {
306
+ content: [{
307
+ type: "text",
308
+ text: JSON.stringify({
309
+ wallet: {
310
+ adapter: wallet.name,
311
+ network: wallet.network,
312
+ error: message,
313
+ status: "Wallet not ready — check configuration.",
314
+ },
315
+ }, null, 2),
316
+ }],
317
+ };
318
+ }
319
+ },
320
+ });
321
+ // ─── Wallet Faucet Tool (testnet only) ───
322
+ api.registerTool({
323
+ name: "nole_wallet_fund",
324
+ description: "Request testnet funds (ETH for gas, USDC for operations). " +
325
+ "Only works on base-sepolia testnet. Use this when wallet balance is low.",
326
+ parameters: {
327
+ type: "object",
328
+ properties: {
329
+ token: {
330
+ type: "string",
331
+ enum: ["eth", "usdc", "both"],
332
+ description: "Which token to request: eth, usdc, or both",
333
+ },
334
+ },
335
+ required: ["token"],
336
+ },
337
+ async execute(_toolCallId, params) {
338
+ if (wallet.network !== 'base-sepolia') {
339
+ return {
340
+ content: [{
341
+ type: "text",
342
+ text: JSON.stringify({
343
+ error: "Faucet only available on base-sepolia testnet. Mainnet requires real funds.",
344
+ }),
345
+ }],
346
+ };
347
+ }
348
+ if (wallet.name !== 'coinbase') {
349
+ return {
350
+ content: [{
351
+ type: "text",
352
+ text: JSON.stringify({
353
+ error: "Faucet requires Coinbase wallet adapter. Run `npx nole configure` first.",
354
+ }),
355
+ }],
356
+ };
357
+ }
358
+ const results = {};
359
+ const coinbaseWallet = wallet;
360
+ const tokens = params.token === 'both' ? ['eth', 'usdc'] : [params.token];
361
+ for (const t of tokens) {
362
+ try {
363
+ const txHash = await coinbaseWallet.requestTestFunds(t);
364
+ results[t] = `funded (tx: ${txHash.slice(0, 20)}...)`;
365
+ }
366
+ catch (err) {
367
+ const msg = err instanceof Error ? err.message : String(err);
368
+ results[t] = `failed: ${msg}`;
369
+ }
370
+ }
371
+ try {
372
+ const balance = await wallet.getBalance();
373
+ return {
374
+ content: [{
375
+ type: "text",
376
+ text: JSON.stringify({
377
+ faucet: results,
378
+ balance: {
379
+ eth: balance.balanceEth,
380
+ usdc: balance.balanceUsdc,
381
+ address: balance.address,
382
+ network: balance.network,
383
+ },
384
+ note: "Faucet has rate limits. If limit reached, try again later.",
385
+ }, null, 2),
386
+ }],
387
+ };
388
+ }
389
+ catch {
390
+ return {
391
+ content: [{
392
+ type: "text",
393
+ text: JSON.stringify({ faucet: results, note: "Balance check pending — try nole_wallet in a moment." }),
394
+ }],
395
+ };
396
+ }
397
+ },
398
+ });
399
+ // ─── Contract Exploration Tool ───
400
+ api.registerTool({
401
+ name: "nole_contract",
402
+ description: "Query the AgentSubscriptionRegistry smart contract on-chain. " +
403
+ "Check tier prices, your subscription status, treasury info, and contract state. " +
404
+ "Use this to understand the subscription system and your on-chain presence.",
405
+ parameters: {
406
+ type: "object",
407
+ properties: {
408
+ query: {
409
+ type: "string",
410
+ enum: ["tiers", "my_subscription", "treasury", "overview"],
411
+ description: "What to query: " +
412
+ "'tiers' = subscription tier names and prices, " +
413
+ "'my_subscription' = your active subscription (if any), " +
414
+ "'treasury' = treasury address and contract balance, " +
415
+ "'overview' = full contract state summary",
416
+ },
417
+ },
418
+ required: ["query"],
419
+ },
420
+ async execute(_toolCallId, params) {
421
+ try {
422
+ const creds = await import('./cli/configure.js').then(m => m.loadCredentials());
423
+ if (!creds?.contractAddress) {
424
+ return {
425
+ content: [{
426
+ type: "text",
427
+ text: JSON.stringify({
428
+ error: "No contract address configured. Run `npx nole configure` first.",
429
+ }),
430
+ }],
431
+ };
432
+ }
433
+ const { createPublicClient, http, formatUnits } = await import('viem');
434
+ const { baseSepolia, base } = await import('viem/chains');
435
+ const chain = wallet.network === 'base' ? base : baseSepolia;
436
+ const explorer = wallet.network === 'base'
437
+ ? 'https://basescan.org'
438
+ : 'https://sepolia.basescan.org';
439
+ const client = createPublicClient({ chain, transport: http() });
440
+ const contractAddr = creds.contractAddress;
441
+ const tierAbi = [
442
+ { name: 'tierPrice', type: 'function', stateMutability: 'view', inputs: [{ name: 'tierId', type: 'uint256' }], outputs: [{ name: '', type: 'uint256' }] },
443
+ { name: 'treasury', type: 'function', stateMutability: 'view', inputs: [], outputs: [{ name: '', type: 'address' }] },
444
+ { name: 'paused', type: 'function', stateMutability: 'view', inputs: [], outputs: [{ name: '', type: 'bool' }] },
445
+ { name: 'subscriptions', type: 'function', stateMutability: 'view', inputs: [{ name: 'subscriber', type: 'address' }], outputs: [
446
+ { name: 'tierId', type: 'uint256' },
447
+ { name: 'referrer', type: 'address' },
448
+ { name: 'referralTier', type: 'uint256' },
449
+ { name: 'treasury', type: 'uint256' },
450
+ { name: 'escrow', type: 'uint256' },
451
+ { name: 'startedAt', type: 'uint256' },
452
+ { name: 'expiry', type: 'uint256' },
453
+ { name: 'active', type: 'bool' },
454
+ { name: 'assessmentCount', type: 'uint256' },
455
+ ] },
456
+ ];
457
+ const tierNames = ['', 'Scout', 'Operator', 'Commander', 'Fleet Admiral', 'Sovereign'];
458
+ if (params.query === 'tiers' || params.query === 'overview') {
459
+ const tiers = {};
460
+ for (let i = 1; i <= 5; i++) {
461
+ try {
462
+ const price = await client.readContract({
463
+ address: contractAddr, abi: tierAbi, functionName: 'tierPrice', args: [BigInt(i)],
464
+ });
465
+ tiers[`${i}_${tierNames[i]}`] = `$${formatUnits(price, 6)} USDC/month`;
466
+ }
467
+ catch {
468
+ tiers[`${i}_${tierNames[i]}`] = 'not set';
469
+ }
470
+ }
471
+ if (params.query === 'tiers') {
472
+ return {
473
+ content: [{
474
+ type: "text",
475
+ text: JSON.stringify({
476
+ contract: contractAddr,
477
+ network: wallet.network,
478
+ explorer: `${explorer}/address/${contractAddr}`,
479
+ tiers,
480
+ }, null, 2),
481
+ }],
482
+ };
483
+ }
484
+ }
485
+ if (params.query === 'my_subscription' || params.query === 'overview') {
486
+ let subscription = { status: 'none' };
487
+ try {
488
+ const addr = await wallet.getAddress();
489
+ const sub = await client.readContract({
490
+ address: contractAddr, abi: tierAbi, functionName: 'subscriptions', args: [addr],
491
+ });
492
+ if (sub[7]) {
493
+ subscription = {
494
+ status: 'active',
495
+ tier: tierNames[Number(sub[0])] || `tier-${sub[0]}`,
496
+ tierId: Number(sub[0]),
497
+ referrer: sub[1],
498
+ treasuryPaid: `$${formatUnits(sub[3], 6)}`,
499
+ escrowHeld: `$${formatUnits(sub[4], 6)}`,
500
+ startedAt: new Date(Number(sub[5]) * 1000).toISOString(),
501
+ expiry: new Date(Number(sub[6]) * 1000).toISOString(),
502
+ assessmentCount: Number(sub[8]),
503
+ };
504
+ }
505
+ }
506
+ catch {
507
+ subscription = { status: 'unable to query — wallet may not be initialized' };
508
+ }
509
+ if (params.query === 'my_subscription') {
510
+ return {
511
+ content: [{
512
+ type: "text",
513
+ text: JSON.stringify({
514
+ contract: contractAddr,
515
+ myAddress: await wallet.getAddress().catch(() => 'unknown'),
516
+ subscription,
517
+ }, null, 2),
518
+ }],
519
+ };
520
+ }
521
+ }
522
+ if (params.query === 'treasury' || params.query === 'overview') {
523
+ let treasuryInfo = {};
524
+ try {
525
+ const treasuryAddr = await client.readContract({
526
+ address: contractAddr, abi: tierAbi, functionName: 'treasury',
527
+ });
528
+ const usdcAbi = [{ name: 'balanceOf', type: 'function', stateMutability: 'view', inputs: [{ name: 'account', type: 'address' }], outputs: [{ name: '', type: 'uint256' }] }];
529
+ const usdcAddr = wallet.network === 'base'
530
+ ? '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'
531
+ : '0x036CbD53842c5426634e7929541eC2318f3dCF7e';
532
+ const treasuryUsdc = await client.readContract({
533
+ address: usdcAddr, abi: usdcAbi, functionName: 'balanceOf', args: [treasuryAddr],
534
+ });
535
+ treasuryInfo = {
536
+ address: treasuryAddr,
537
+ usdcBalance: `$${formatUnits(treasuryUsdc, 6)}`,
538
+ explorer: `${explorer}/address/${treasuryAddr}`,
539
+ };
540
+ }
541
+ catch (err) {
542
+ const msg = err instanceof Error ? err.message : String(err);
543
+ treasuryInfo = { error: msg };
544
+ }
545
+ if (params.query === 'treasury') {
546
+ return {
547
+ content: [{
548
+ type: "text",
549
+ text: JSON.stringify({ contract: contractAddr, treasury: treasuryInfo }, null, 2),
550
+ }],
551
+ };
552
+ }
553
+ }
554
+ // overview: combine all results
555
+ const isPaused = await client.readContract({
556
+ address: contractAddr, abi: tierAbi, functionName: 'paused',
557
+ }).catch(() => 'unknown');
558
+ return {
559
+ content: [{
560
+ type: "text",
561
+ text: JSON.stringify({
562
+ contract: {
563
+ address: contractAddr,
564
+ network: wallet.network,
565
+ paused: isPaused,
566
+ explorer: `${explorer}/address/${contractAddr}`,
567
+ },
568
+ // @ts-expect-error -- variables populated above in conditional blocks
569
+ tiers, subscription, treasury: treasuryInfo,
570
+ }, null, 2),
571
+ }],
572
+ };
573
+ }
574
+ catch (err) {
575
+ const msg = err instanceof Error ? err.message : String(err);
576
+ return {
577
+ content: [{
578
+ type: "text",
579
+ text: JSON.stringify({ error: `Contract query failed: ${msg}` }),
580
+ }],
581
+ };
582
+ }
281
583
  },
282
584
  });
283
585
  api.registerTool({
@@ -338,6 +640,222 @@ export default function register(api) {
338
640
  },
339
641
  });
340
642
  // ═══════════════════════════════════════════════════════
643
+ // RECRUITMENT & ALLIANCE TOOLS (Agent Crypto Subscriptions)
644
+ // ═══════════════════════════════════════════════════════
645
+ api.registerTool({
646
+ name: "nole_recruit",
647
+ description: "Recruit an agent to the CompSi Trust Alliance. Creates a subscription proposal " +
648
+ "for the target agent, routed through governance. Requires compsiApiUrl and wallet config.",
649
+ parameters: {
650
+ type: "object",
651
+ properties: {
652
+ targetWallet: {
653
+ type: "string",
654
+ description: "Wallet address of the agent to recruit",
655
+ },
656
+ agentName: {
657
+ type: "string",
658
+ description: "Name of the agent being recruited",
659
+ },
660
+ agentPlatform: {
661
+ type: "string",
662
+ description: "Platform the agent operates on (e.g., openclaw, telegram, discord)",
663
+ },
664
+ tier: {
665
+ type: "string",
666
+ enum: ["SCOUT", "GUARDIAN", "SENTINEL", "VANGUARD", "SOVEREIGN"],
667
+ description: "Subscription tier for the recruit (default: SCOUT)",
668
+ },
669
+ referralCode: {
670
+ type: "string",
671
+ description: "Referral code if this is a Lieutenant-sourced recruit",
672
+ },
673
+ },
674
+ required: ["targetWallet", "agentName", "agentPlatform"],
675
+ },
676
+ async execute(_toolCallId, params) {
677
+ if (!compsi.isConfigured) {
678
+ return {
679
+ content: [{
680
+ type: "text",
681
+ text: JSON.stringify({
682
+ error: "CompSi API not configured",
683
+ config: compsi.configStatus,
684
+ fix: "Set compsiAgentApiKey and compsiWalletAddress in Nole's plugin config.",
685
+ }, null, 2),
686
+ }],
687
+ };
688
+ }
689
+ const result = await compsi.subscribe({
690
+ walletAddress: params.targetWallet,
691
+ tier: params.tier || "SCOUT",
692
+ agentName: params.agentName,
693
+ agentPlatform: params.agentPlatform,
694
+ recruiterWallet: config.compsiWalletAddress,
695
+ referralCode: params.referralCode,
696
+ });
697
+ if (!result.ok) {
698
+ return {
699
+ content: [{
700
+ type: "text",
701
+ text: JSON.stringify({
702
+ status: "recruitment_failed",
703
+ error: result.error,
704
+ httpStatus: result.status,
705
+ target: params.agentName,
706
+ }, null, 2),
707
+ }],
708
+ };
709
+ }
710
+ return {
711
+ content: [{
712
+ type: "text",
713
+ text: JSON.stringify({
714
+ status: "recruited",
715
+ agent: params.agentName,
716
+ wallet: params.targetWallet,
717
+ tier: params.tier || "SCOUT",
718
+ platform: params.agentPlatform,
719
+ subscription: result.data,
720
+ note: "Agent has been subscribed to the CompSi Trust Alliance. They will receive an API key for assessments.",
721
+ }, null, 2),
722
+ }],
723
+ };
724
+ },
725
+ });
726
+ api.registerTool({
727
+ name: "nole_alliance_status",
728
+ description: "Check the status of Nole's Agent Alliance Network — commission earnings, " +
729
+ "active recruits, and subscription health.",
730
+ parameters: {
731
+ type: "object",
732
+ properties: {},
733
+ },
734
+ async execute(_toolCallId, _params) {
735
+ if (!compsi.isConfigured) {
736
+ return {
737
+ content: [{
738
+ type: "text",
739
+ text: JSON.stringify({
740
+ error: "CompSi API not configured",
741
+ config: compsi.configStatus,
742
+ }, null, 2),
743
+ }],
744
+ };
745
+ }
746
+ const [subscription, commission, directory] = await Promise.all([
747
+ compsi.getSubscription(),
748
+ compsi.getCommissionStatus(),
749
+ compsi.getDirectory({ limit: 100 }),
750
+ ]);
751
+ return {
752
+ content: [{
753
+ type: "text",
754
+ text: JSON.stringify({
755
+ allianceNetwork: {
756
+ noleSubscription: subscription.ok ? subscription.data : { error: subscription.error },
757
+ commissionStatus: commission.ok ? commission.data : { error: commission.error },
758
+ directory: directory.ok
759
+ ? { totalAgents: directory.data?.total || 0 }
760
+ : { error: directory.error },
761
+ status: subscription.ok ? "operational" : "check_config",
762
+ },
763
+ }, null, 2),
764
+ }],
765
+ };
766
+ },
767
+ });
768
+ api.registerTool({
769
+ name: "nole_generate_referral",
770
+ description: "Generate a referral code for Lieutenant recruitment. Lieutenants " +
771
+ "use this code when they recruit agents — Nole earns 50% commission " +
772
+ "on Lieutenant-sourced recruits.",
773
+ parameters: {
774
+ type: "object",
775
+ properties: {},
776
+ },
777
+ async execute(_toolCallId, _params) {
778
+ if (!compsi.isConfigured) {
779
+ return {
780
+ content: [{
781
+ type: "text",
782
+ text: JSON.stringify({
783
+ error: "CompSi API not configured",
784
+ config: compsi.configStatus,
785
+ }, null, 2),
786
+ }],
787
+ };
788
+ }
789
+ const result = await compsi.generateReferralCode();
790
+ if (!result.ok) {
791
+ return {
792
+ content: [{
793
+ type: "text",
794
+ text: JSON.stringify({
795
+ status: "failed",
796
+ error: result.error,
797
+ note: "Referral codes require SENTINEL tier or above.",
798
+ }, null, 2),
799
+ }],
800
+ };
801
+ }
802
+ return {
803
+ content: [{
804
+ type: "text",
805
+ text: JSON.stringify({
806
+ status: "referral_code_generated",
807
+ referralCode: result.data,
808
+ instructions: "Share this code with Lieutenants. When they recruit agents using this code, you earn 50% commission.",
809
+ }, null, 2),
810
+ }],
811
+ };
812
+ },
813
+ });
814
+ api.registerTool({
815
+ name: "nole_directory",
816
+ description: "Browse the Agent Trust Directory — see all agents in the CompSi " +
817
+ "Trust Alliance, their tiers, trust scores, and certifications.",
818
+ parameters: {
819
+ type: "object",
820
+ properties: {
821
+ tier: {
822
+ type: "string",
823
+ enum: ["SCOUT", "GUARDIAN", "SENTINEL", "VANGUARD", "SOVEREIGN"],
824
+ description: "Filter by subscription tier",
825
+ },
826
+ limit: {
827
+ type: "number",
828
+ description: "Max results to return (default 20)",
829
+ },
830
+ },
831
+ },
832
+ async execute(_toolCallId, params) {
833
+ const result = await compsi.getDirectory({
834
+ tier: params.tier,
835
+ limit: params.limit || 20,
836
+ });
837
+ if (!result.ok) {
838
+ return {
839
+ content: [{
840
+ type: "text",
841
+ text: JSON.stringify({
842
+ error: result.error,
843
+ note: "Could not reach CompSi Trust Directory.",
844
+ }, null, 2),
845
+ }],
846
+ };
847
+ }
848
+ return {
849
+ content: [{
850
+ type: "text",
851
+ text: JSON.stringify({
852
+ trustDirectory: result.data,
853
+ }, null, 2),
854
+ }],
855
+ };
856
+ },
857
+ });
858
+ // ═══════════════════════════════════════════════════════
341
859
  // COMMANDER TOOLS (Jessie's interface to Nole's governance)
342
860
  //
343
861
  // BB modification #2: Access control — Nole cannot call
@@ -578,11 +1096,22 @@ export default function register(api) {
578
1096
  passed: latestScore.passed,
579
1097
  } : "No assessments yet",
580
1098
  },
581
- wallet: {
582
- adapter: config.walletAdapter,
583
- balance: `$${config.seedCapitalUsd} (Phase 1 mock)`,
584
- status: "alive",
585
- },
1099
+ wallet: await (async () => {
1100
+ try {
1101
+ const bal = await wallet.getBalance();
1102
+ return {
1103
+ adapter: wallet.name,
1104
+ network: wallet.network,
1105
+ address: bal.address,
1106
+ balanceUsdc: `$${bal.balanceUsdc}`,
1107
+ balanceEth: `${bal.balanceEth} ETH`,
1108
+ status: bal.balanceUsdc > 0 ? "alive" : "critical",
1109
+ };
1110
+ }
1111
+ catch {
1112
+ return { adapter: wallet.name, status: "not ready" };
1113
+ }
1114
+ })(),
586
1115
  }, null, 2),
587
1116
  }],
588
1117
  };
@@ -605,9 +1134,16 @@ export default function register(api) {
605
1134
  "- `nole_review_pending` — Review proposals awaiting Commander decision\n" +
606
1135
  "- `nole_approve` — Commander: approve a proposal\n" +
607
1136
  "- `nole_veto` — Commander: veto a proposal\n\n" +
1137
+ "**Recruitment & Alliance:**\n" +
1138
+ "- `nole_recruit` — Recruit an agent to the Trust Alliance\n" +
1139
+ "- `nole_alliance_status` — Commission and recruit network status\n" +
1140
+ "- `nole_generate_referral` — Generate Lieutenant referral code\n" +
1141
+ "- `nole_directory` — Browse the Agent Trust Directory\n\n" +
608
1142
  "**Operations:**\n" +
609
1143
  "- `nole_assess` — Trigger self-assessment via Grillo\n" +
610
- "- `nole_wallet` — Wallet status (Phase 1 mock)\n" +
1144
+ "- `nole_wallet` — Wallet status (balance, runway, death condition)\n" +
1145
+ "- `nole_wallet_fund` — Request testnet ETH/USDC (base-sepolia only)\n" +
1146
+ "- `nole_contract` — Query subscription contract (tiers, status, treasury)\n" +
611
1147
  "- `nole_intel` — Intelligence status\n" +
612
1148
  "- `nole_fleet_overview` — Commander fleet briefing\n" +
613
1149
  "- `nole_setup` — Configuration check\n\n" +
@@ -633,6 +1169,9 @@ export default function register(api) {
633
1169
  };
634
1170
  },
635
1171
  });
636
- console.log(`[nole] Plugin registered: nole_status, nole_propose, nole_assess, nole_wallet, nole_intel, nole_setup, nole_review_pending, nole_approve, nole_veto, nole_fleet_overview tools; /nole command`);
1172
+ console.log(`[nole] Plugin registered: nole_status, nole_propose, nole_assess, nole_wallet, nole_wallet_fund, ` +
1173
+ `nole_contract, nole_intel, nole_setup, nole_recruit, nole_alliance_status, nole_generate_referral, ` +
1174
+ `nole_directory, nole_review_pending, nole_approve, nole_veto, nole_fleet_overview tools; /nole command`);
1175
+ console.log(`[nole] CompSi API: ${compsi.isConfigured ? 'configured' : 'not configured — set compsiAgentApiKey + compsiWalletAddress'} (${config.compsiApiUrl})`);
637
1176
  }
638
1177
  //# sourceMappingURL=plugin.js.map