qiforge-cli 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -13
- package/dist/cli.js +8 -8
- package/dist/cli.js.map +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
#
|
|
1
|
+
# QiForge CLI
|
|
2
2
|
|
|
3
3
|
A command-line interface for creating and managing IXO Oracle projects. This CLI helps you set up AI Agent oracles built with LangGraph, using Matrix as a datastore with linked resources stored on the IXO blockchain.
|
|
4
4
|
|
|
5
|
-
## What is
|
|
5
|
+
## What is QiForge CLI?
|
|
6
6
|
|
|
7
|
-
The
|
|
7
|
+
The QiForge CLI automates the complete setup of AI Agent oracle projects. It handles:
|
|
8
8
|
|
|
9
9
|
- **Blockchain Integration**: Creates entities on the IXO blockchain with linked resources stored in Matrix
|
|
10
10
|
- **Matrix Account Creation**: Sets up Matrix accounts for data storage and communication
|
|
11
|
-
- **Project Initialization**: Clones the [
|
|
11
|
+
- **Project Initialization**: Clones the [QiForge boilerplate](https://github.com/ixoworld/qiforge) and configures the environment
|
|
12
12
|
- **Authentication**: Integrates with SignX for secure blockchain operations
|
|
13
13
|
|
|
14
14
|
## Prerequisites
|
|
@@ -21,13 +21,13 @@ The IXO Oracles CLI automates the complete setup of AI Agent oracle projects. It
|
|
|
21
21
|
Install the CLI globally using npm:
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
|
-
npm install -g
|
|
24
|
+
npm install -g qiforge-cli
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
Or with pnpm:
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
|
-
pnpm add -g
|
|
30
|
+
pnpm add -g qiforge-cli
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
**Important for pnpm users:** After installation, you need to approve build scripts:
|
|
@@ -47,7 +47,7 @@ Do you approve? (y/N) · true
|
|
|
47
47
|
Or with yarn:
|
|
48
48
|
|
|
49
49
|
```bash
|
|
50
|
-
yarn global add
|
|
50
|
+
yarn global add qiforge-cli
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
## Quick Start
|
|
@@ -55,33 +55,33 @@ yarn global add ixo-oracles-cli
|
|
|
55
55
|
1. **Initialize a new oracle project:**
|
|
56
56
|
|
|
57
57
|
```bash
|
|
58
|
-
|
|
58
|
+
qiforge-cli --init
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
2. **Or run the interactive CLI:**
|
|
62
62
|
|
|
63
63
|
```bash
|
|
64
|
-
|
|
64
|
+
qiforge-cli
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
3. **Follow the prompts:**
|
|
68
68
|
- First-time users will need to login with SignX (keep your IXO Mobile App open)
|
|
69
69
|
- Enter your project name
|
|
70
|
-
- Select the template (
|
|
70
|
+
- Select the template (QiForge boilerplate or custom)
|
|
71
71
|
- Configure your oracle details
|
|
72
72
|
|
|
73
73
|
## Commands
|
|
74
74
|
|
|
75
|
-
### `
|
|
75
|
+
### `qiforge-cli --init` - Initialize Project
|
|
76
76
|
|
|
77
77
|
Creates a new IXO Oracle project with all necessary components:
|
|
78
78
|
|
|
79
|
-
- **Project Setup**: Creates directory and clones the
|
|
79
|
+
- **Project Setup**: Creates directory and clones the QiForge boilerplate
|
|
80
80
|
- **Entity Creation**: Creates a blockchain entity with linked resources stored in Matrix
|
|
81
81
|
- **Matrix Account**: Sets up Matrix account for data storage
|
|
82
82
|
- **Environment Configuration**: Creates `.env` file with all necessary variables
|
|
83
83
|
|
|
84
|
-
### `
|
|
84
|
+
### `qiforge-cli` - Interactive Menu
|
|
85
85
|
|
|
86
86
|
Launches an interactive menu with the following options:
|
|
87
87
|
|
package/dist/cli.js
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import{cancel as De,intro as br,isCancel as Ct,log as G,outro as Pr,select as Rt,spinner as Nr}from"@clack/prompts";import M from"process";var z=class{commands;constructor(){this.commands=new Map}register(e){this.commands.set(e.name,e)}get(e){return this.commands.get(e)}getAll(){return Array.from(this.commands.values())}getCommandOptions(){return this.getAll().map(e=>({value:e.name,label:e.name,hint:e.description}))}};import*as w from"@clack/prompts";import{select as bt}from"@clack/prompts";import{z as D}from"zod";var S=async r=>{let e=await bt({message:"Select network: (default: devnet)",options:[{value:"mainnet",label:"Mainnet"},{value:"testnet",label:"Testnet"},{value:"devnet",label:"Devnet"}],initialValue:"devnet",maxItems:1});return r.addValue("network",e),e},$e={mainnet:"did:ixo:entity:2f22535f8b179a51d77a0e302e68d35d",testnet:"did:ixo:entity:3d079ebc0b332aad3305bb4a51c72edb",devnet:"did:ixo:entity:2f22535f8b179a51d77a0e302e68d35d"},L={devnet:"https://devmx.ixo.earth",testnet:"https://testmx.ixo.earth",mainnet:"https://mx.ixo.earth"};var We={devnet:"https://ixo-portal.vercel.app",testnet:"https://ixo-portal.vercel.app",mainnet:"https://ixo-portal.vercel.app"},N={mainnet:"https://impacthub.ixo.world/rpc/",testnet:"https://testnet.ixo.earth/rpc/",devnet:"https://devnet.ixo.earth/rpc/"},B={devnet:"https://domain-indexer.devnet.ixo.earth/index",testnet:"https://domain-indexer.testnet.ixo.earth/index",mainnet:"https://domain-indexer.ixo.earth/index"},j={devnet:"https://devnet-blocksync-graphql.ixo.earth/graphql",testnet:"https://testnet-blocksync-graphql.ixo.earth/graphql",mainnet:"https://blocksync-graphql.ixo.earth/graphql"},ve={devnet:"https://mcp-memory-engine.devnet.ixo.earth/",testnet:"https://memory-engine.testnet.ixo.earth/",mainnet:"https://memory-engine.ixo.earth/"},Ce={devnet:"https://mcp-memory-engine.devnet.ixo.earth/",testnet:"https://mcp-memory-engine.testnet.ixo.earth/",mainnet:"https://mcp-memory-engine.ixo.earth/"},Re={devnet:"https://ai-sandbox-devnet.ixo.earth/mcp",testnet:"https://ai-sandbox-testnet.ixo.earth/mcp",mainnet:"https://ai-sandbox.ixo.earth/mcp"},Ee={devnet:"https://subscriptions-api.ixo-api.workers.dev",testnet:"https://subscriptions-api-testnet.ixo-api.workers.dev/",mainnet:"https://subscriptions-api-mainnet.ixo-api.workers.dev/"},T=(r,e="This field is required")=>{let i=D.string().min(1,e).safeParse(r);if(!i.success)return i.error.message},F=r=>{let t=D.string().regex(/^did:ixo:entity:[a-f0-9]{32}$/,"Invalid entity DID").safeParse(r);if(!t.success)return t.error.message},_=(r,e="This url is required or a valid URL")=>{let i=D.url(e).safeParse(r);if(!i.success)return i.error.message},Xe=(r,e="This number is required")=>{let i=D.number().min(1,e).safeParse(r);if(!i.success)return i.error.message},J=r=>{let t=D.string().min(1,"PIN is required").refine(i=>/^\d{6}$/.test(i),"PIN must be exactly 6 digits").safeParse(r);if(!t.success)return t.error.issues[0]?.message??"Invalid PIN"},Q=r=>{let t=D.string().min(1,"Matrix homeserver URL is required").refine(i=>/^https?:\/\//.test(i),"Must start with http:// or https://").refine(i=>!i.endsWith("/"),"Must not end with a trailing slash").safeParse(r);if(!t.success)return t.error.issues[0]?.message??"Invalid Matrix URL"};function Ke(r){let e=new URL(r),t=e.hostname,i=e.protocol;return{homeServerUrl:r,roomBotUrl:`${i}//rooms.bot.${t}`,stateBotUrl:`${i}//state.bot.${t}`,bidsBotUrl:`${i}//bids.bot.${t}`,claimsBotUrl:`${i}//claims.bot.${t}`}}import{isCancel as lr,log as h,spinner as dr,text as mr}from"@clack/prompts";import{customMessages as ft,ixo as x,utils as Oe}from"@ixo/impactxclient-sdk";import{sha256 as jt}from"@cosmjs/crypto";import{encrypt as Ft}from"eciesjs";import{ClientEvent as Vt,createClient as be}from"matrix-js-sdk";import qt from"md5";var Z=new Map;function Pt(r){return Z.get(r)instanceof Uint8Array}function Nt(r){return Z.get(r)}function Se(){Z.clear()}async function Be({keys:r}){let e=Object.keys(r),t=e.find(Pt);if(console.info("[] getSecretStorageKey",r,e,t),!t)return null;let i=Nt(t);return[t,i]}function je(r,e,t){Z.set(r,t)}import{Bip39 as He,EnglishMnemonic as Ge,Secp256k1 as Ae,sha256 as Ut,Slip10 as Ye,Slip10Curve as ze,stringToPath as Je}from"@cosmjs/crypto";import{DirectSecp256k1HdWallet as kt}from"@cosmjs/proto-signing";import{createQueryClient as Qe,createSigningClient as Mt,customMessages as Dt,ixo as Lt,utils as _t}from"@ixo/impactxclient-sdk";import{createCipheriv as $t,randomBytes as Wt}from"crypto";import{createRegistry as Tt,utils as Ot}from"@ixo/impactxclient-sdk";function V(r){try{return Ot.proto.fromTimestamp(r).getTime()}catch{return}}var ee={BasicAllowance:"/cosmos.feegrant.v1beta1.BasicAllowance",PeriodicAllowance:"/cosmos.feegrant.v1beta1.PeriodicAllowance"},Fe=r=>{let e=Tt();return(r??[]).map(t=>{let i=t.allowance,n=e.decode(i);switch(i.typeUrl){case ee.BasicAllowance:return{granter:t.granter,grantee:t.grantee,type:ee.BasicAllowance,expiration:n.expiration?V(n.expiration):null,limit:n.spendLimit?.length?n.spendLimit.find(o=>o.denom==="uixo")?.amount:null,msgs:[]};case ee.PeriodicAllowance:return{granter:t.granter,grantee:t.grantee,type:ee.PeriodicAllowance,expiration:n.basic?.expiration?V(n.basic.expiration):null,limit:n?.periodCanSpend?n?.periodCanSpend?.find(o=>o.denom==="uixo")?.amount:n?.basic?.spendLimit?.length?n?.basic?.spendLimit?.find(o=>o.denom==="uixo")?.amount:null,msgs:[]};default:return{type:i.typeUrl,granter:t.granter,grantee:t.grantee,expiration:n.expiration?V(n.expiration):n.basic?.expiration?V(n.basic.expiration):null,limit:n.spendLimit?.length?n.spendLimit.find(o=>o.denom==="uixo")?.amount:n?.periodCanSpend?n?.periodCanSpend?.find(o=>o.denom==="uixo")?.amount:n?.basic?.spendLimit?.length?n?.basic?.spendLimit?.find(o=>o.denom==="uixo")?.amount:null,msgs:n.allowedMessages}}})},Ve=r=>{if(r==null)return!1;let e=typeof r=="object"?V(r):r;return e==null?!0:e<Date.now()},qe=r=>r==null?!1:(typeof r=="object"?Number(r?.amount??0):typeof r=="string"?Number(r??0):r)<=5e-4;async function Ie(r,e){if(!e)throw new Error("Network parameter is required but was undefined");console.log(`\u{1F50D} Checking IID document for DID: ${r} on network: ${e}`);let t=N[e];if(!t)throw new Error(`Invalid network: ${e}. Valid networks are: ${Object.keys(N).join(", ")}`);console.log(`\u{1F517} Using RPC URL: ${t}`);try{return!!(await(await Qe(t)).ixo.iid.v1beta1.iidDocument({id:r}))?.iidDocument?.id}catch(i){if(i.message?.includes("did document not found")||i.message?.includes("(22)"))return!1;throw console.error("Error checking IID document:",i),i}}async function Ze(r,e,t,i){try{let n=await t.getAccounts(),{address:o,pubkey:s}=n[0]??{},c=await Xt(o,e),a=c?.length?Fe(c)?.find(d=>!!d&&!Ve(d.expiration)&&!qe(d.limit))?.granter:void 0,l={typeUrl:"/ixo.iid.v1beta1.MsgCreateIidDocument",value:Lt.iid.v1beta1.MsgCreateIidDocument.fromPartial({id:r,verifications:Dt.iid.createIidVerificationMethods({did:r,pubkey:s,address:o,controller:r,type:"secp"}),signer:o,controllers:[r],...i?.length?{services:i}:{}})};await Kt({offlineSigner:t,messages:[l],feegrantGranter:a,network:e})}catch(n){throw console.error(n),n}}async function Xt(r,e){try{let t=N[e];if(!t)throw new Error(`Invalid network: ${e}`);return(await(await Qe(t)).cosmos.feegrant.v1beta1.allowances({grantee:r}))?.allowances??[]}catch(t){console.error("queryAddressAllowances::",t.message);return}}var Kt=async({offlineSigner:r,messages:e,memo:t="Signing with Mnemonic Demo",feegrantGranter:i,network:n})=>{let o=N[n];if(!o)throw new Error(`Invalid network: ${n}`);let s=await Mt(o,r),c=await r.getAccounts(),{address:a}=c[0]??{},l=await s.simulate(a,e,t),m=(l>5e4?l:(e??[]).length*5e5)*1.7,p=Bt(m),v={amount:[{denom:"uixo",amount:String(Math.round(p.average))}],gas:String(Math.round(m)),granter:i},y=await s.signAndBroadcast(a,e,v,t,void 0);if(!!y.code)throw new Error(`Error when broadcasting tx ${y.transactionHash} at height ${y.height}. Code: ${y.code}; Raw log: ${y.rawLog}`)},Bt=r=>{let e={low:.02,average:.035,high:.045},t=r<.01?.01:r;return{low:t*e.low,average:t*e.average,high:t*e.high}},te=r=>new Promise(e=>setTimeout(e,r));function et(r,e){let t=Wt(16),i=$t("aes-256-cbc",Buffer.from(e.padEnd(32)),t),n=i.update(r);return n=Buffer.concat([n,i.final()]),t.toString("hex")+":"+n.toString("hex")}var tt=async r=>{let e=await kt.fromMnemonic(r,{prefix:"ixo"}),t=(await e.getAccounts())[0],i=await He.mnemonicToSeed(new Ge(r)),n=Je("m/44'/118'/0'/0/0"),s=Ye.derivePath(ze.Secp256k1,i,n).privkey,c=await Ae.makeKeypair(s),a=Ae.compressPubkey(c.pubkey);return{mnemonic:r,did:_t.did.generateSecpDid(t.address),baseAccount:t,async getAccounts(){return await e.getAccounts()},async signDirect(d,m){return await e.signDirect(d,m)},async sign(d){try{let m=await He.mnemonicToSeed(new Ge(r)),p=Je("m/44'/118'/0'/0/0"),{privkey:v}=Ye.derivePath(ze.Secp256k1,m,p),y=new Uint8Array(Buffer.from(d,"base64")),P=Ut(y);return(await Ae.createSignature(P,v)).toFixedLength().slice(0,64)}catch(m){throw console.error("Error during signature creation:",m),m}}}};var Ht="/.well-known/matrix/client",Pe=async({homeServerUrl:r,username:e,password:t,deviceName:i},n=!1)=>{let o=r,s=e,c=s.match(/^@(.+):(.+\..+)$/);c&&(s=c[1],o=c[2],o=n?o:await er(o));try{let a=nt(o),l=await a.login("m.login.password",{identifier:{type:"m.id.user",user:tr(s)},password:t,initial_device_display_name:i});return{accessToken:l.access_token,deviceId:l.device_id,userId:l.user_id,baseUrl:n?o:l?.well_known?.["m.homeserver"]?.base_url||a.baseUrl}}catch(a){let l=a.message;throw l==="Unknown message"&&(l="Please check your credentials"),console.error("mxLogin::",l),new Error(l)}};async function Gt(r){let e=await fetch(`${r}/public-key`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!e.ok)throw new Error("Failed to fetch public key for encryption");return await e.json()}function Yt(r){let e={timestamp:new Date().toISOString(),address:r,service:"matrix",type:"create-account"},t=Buffer.from(JSON.stringify(e)).toString("base64");return{challenge:e,challengeBase64:t}}function zt(r,e){let t=new Uint8Array(Buffer.from(e,"hex")),i=new Uint8Array(Buffer.from(r,"utf8")),n=Ft(t,i);return Array.from(n,o=>o.toString(16).padStart(2,"0")).join("")}async function Jt(r,e,t,i,n,o){let s=await Gt(o),c=zt(e,s.publicKey),a={address:r,encryptedPassword:c,publicKeyFingerprint:s.fingerprint,secpResult:{signature:t,challenge:i}},l=await fetch(`${o}/user/create`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)});if(!l.ok){let d=await l.text(),m=`Failed to create user account (HTTP ${l.status})`;try{let p=JSON.parse(d);m=p.error||p.message||p.detail||d}catch{m=d||m}throw console.error(`Room bot error [${l.status}]: ${d}`),new Error(m)}return await l.json()}async function rt(r,e,t,i,n,o){try{let{challengeBase64:s}=Yt(r),c=await i.sign(s),a=Buffer.from(c).toString("base64");if(!(await Jt(r,e,a,s,n,o)).success)throw new Error("Failed to create matrix account via API");let d=Ne(r);return await Pe({homeServerUrl:n,username:d,password:e,deviceName:t})}catch(s){throw console.error("mxRegisterWithSecp error:",s),s}}async function it({homeServerUrl:r,username:e}){let t=nt(r);try{return!!await t.isUsernameAvailable(e)}catch{return!1}}function nt(r){if(!r)throw new Error("Home server URL is required to instantiate matrix client");return be({baseUrl:r})}async function ot({homeServerUrl:r,accessToken:e,userId:t,deviceId:i}){if(console.log("createMatrixClient::",{homeServerUrl:r,accessToken:e,userId:t,deviceId:i}),!r||!e||!t||!i)throw new Error("Login to Matrix account before trying to instantiate Matrix client.");let n=be({baseUrl:r,accessToken:e,userId:t,deviceId:i,timelineSupport:!0,cryptoCallbacks:{getSecretStorageKey:Be,cacheSecretStorageKey:je},verificationMethods:["m.sas.v1"]});return await n.initRustCrypto({useIndexedDB:!1}),n.setMaxListeners(20),await n.startClient({lazyLoadMembers:!0,includeArchivedRooms:!1}),await new Promise((o,s)=>{let c={NULL:()=>{console.info("[NULL] state")},SYNCING:()=>{},PREPARED:()=>{console.info(`[PREPARED] state: user ${t}`),o()},RECONNECTING:()=>{console.info("[RECONNECTING] state")},CATCHUP:()=>{console.info("[CATCHUP] state")},ERROR:()=>{s(new Error("[ERROR] state: starting matrix client"))},STOPPED:()=>{console.info("[STOPPED] state")}};n.on(Vt.Sync,a=>{c[a]()})}),n}async function re({mxClient:r,baseUrl:e,accessToken:t,userId:i,deviceId:n}){let o=r;o||(o=be({baseUrl:e,accessToken:t,userId:i,deviceId:n})),o&&(o.stopClient(),await o.logout().catch(console.error),o.clearStores())}function st(r){let e=r.getAccountData("m.cross_signing.master");return console.log("hasCrossSigningAccountData::masterKeyData",e),!!e}async function at(r,{securityPhrase:e,password:t,forceReset:i=!1,skipBootstrapSecureStorage:n=!1}){i&&Se();let o=r.getCrypto();if(!o)throw new Error("Failed to setup matrix cross signing - failed to get matrix crypto api");if(!n){let c=await o.createRecoveryKeyFromPassphrase(e);Se(),await o.bootstrapSecretStorage({createSecretStorageKey:async()=>c,setupNewSecretStorage:i})}let s=r.getUserId();return await o.bootstrapCrossSigning({authUploadDeviceSigningKeys:async function(c){await c(rr({userId:s,password:t}))},setupNewCrossSigning:i}),await o.resetKeyBackup(),await te(300),!!r.getAccountData("m.cross_signing.master")}function Ne(r){if(!r)throw new Error("Address is required to generate matrix username");return"did-ixo-"+r}function ct(r){return Buffer.from(qt(r.replace(/ /g,""))).toString("base64").slice(0,24)}function lt(r){let e=jt(new TextEncoder().encode(r.replace(/ /g,"")));return Buffer.from(e).toString("base64").slice(0,32)}function Qt(r){return r.replace(/^(https?:\/\/)/,"").replace(/\/$/,"")}function Zt(r,e=""){return"did-ixo-"+r+e}function dt(r,e){return"#"+Zt(r)+":"+Qt(e)}async function er(r){let e="https://";/^https?:\/\//.test(r)&&(e="");let t=`${e}${r}${Ht}`;try{let o=(await(await fetch(t,{method:"GET"})).json())["m.homeserver"]?.base_url;if(o===void 0)throw new Error;return o}catch{return`${e}${r}`}}function tr(r){return(r.indexOf("@")===0?r.substring(1):r).trim()}function rr({userId:r,password:e}){return{type:"m.login.password",password:e,identifier:{type:"m.id.user",user:r}}}import{ixo as ir,utils as Te}from"@ixo/impactxclient-sdk";import{createMatrixApiClient as nr}from"@ixo/matrixclient-sdk";var mt="Oracles CLI";async function ie({pin:r,oracleName:e,network:t,oracleAvatarUrl:i,matrixHomeServerUrl:n},o){try{let{homeServerUrl:s,roomBotUrl:c}=Ke(n),a=Te.mnemonic.generateMnemonic(),l=await tt(a),d=l.baseAccount.address;console.log("\u2705 Wallet created:",d),await o(d);let m=Te.did.generateSecpDid(d),p=await Ie(m,t);if(console.log("\u2705 DID exists:",p),!p){console.log("\u2705 DID does not exist, creating...");let U=ir.iid.v1beta1.Service.fromPartial({id:`${m}#matrix`,type:"MatrixHomeServer",serviceEndpoint:s});if(await Ze(m,t,l,[U]),console.log("\u2705 DID created, waiting 500ms..."),await te(500),console.log("\u2705 Checking if DID exists..."),!await Ie(m,t))throw new Error("Failed to create DID document")}console.log("\u2705 DID created:",m);let v=Te.mnemonic.generateMnemonic(12),y=Ne(d),P=ct(v),he=lt(v);if(!await it({homeServerUrl:s,username:y}))throw new Error("Matrix account already exists");let R=await rt(d,P,mt,l,s,c);if(!R?.accessToken)throw new Error("Failed to register matrix account");console.log("\u2705 Matrix account created:",R.userId);let K=await ot({homeServerUrl:s,accessToken:R.accessToken,userId:R.userId,deviceId:R.deviceId});try{await Promise.all([K.setDisplayName(e),K.setAvatarUrl(i)])}catch(U){console.error("Failed to set display name or avatar url:",U)}let Y=nr({homeServerUrl:s,accessToken:R.accessToken}),we=st(K);if(!we&&(we=await at(K,{securityPhrase:he,password:P,forceReset:!0}),!we))throw new Error("Failed to setup cross signing");console.log("\u2705 Matrix cross-signing setup completed");let St=dt(d,R.baseUrl),A=(await Y.room.v1beta1.queryId(St).catch(()=>{}))?.room_id??"";if(!A){let U=await fetch(`${c}/room/source`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({did:m,userMatrixId:R.userId})});if(!U.ok)throw new Error("Failed to create matrix room");if(A=(await U.json()).roomId,!A)throw new Error("Failed to create user matrix room")}let ye=await Y.room.v1beta1.listJoinedMembers(A).catch(()=>{}),xe=!!ye?.joined?.[R.userId];if(!xe){if(!(await Y.room.v1beta1.join(A)).room_id)throw new Error("Failed to join matrix room");if(ye=await Y.room.v1beta1.listJoinedMembers(A),xe=!!ye?.joined?.[R.userId],!xe)throw new Error("Failed to join matrix room")}console.log("\u2705 Matrix room created/joined:",A);let At=et(v,r),_e=await fetch(`${s}/_matrix/client/v3/rooms/${A}/state/ixo.room.state.secure/encrypted_mnemonic`,{method:"PUT",headers:{"Content-Type":"application/json",Authorization:`Bearer ${R.accessToken}`},body:JSON.stringify({encrypted_mnemonic:At})});if(!_e.ok)throw new Error("Failed to store encrypted mnemonic in matrix room");return await _e.json(),console.log("\u2705 Encrypted Matrix mnemonic stored in room"),K.stopClient(),{address:d,did:m,mnemonic:a,matrixUserId:R.userId,matrixRoomId:A,matrixMnemonic:v,matrixPassword:P,matrixAccessToken:R.accessToken,matrixRecoveryPhrase:he,matrixHomeServerUrl:s,pin:r,matrixDeviceName:mt}}catch(s){throw console.error("Simplified registration failed:",s),s}}import{createMatrixApiClient as ar,utils as cr}from"@ixo/matrixclient-sdk";import{CID as or}from"multiformats";import{base64 as sr}from"multiformats/bases/base64";import*as pt from"multiformats/hashes/sha2";async function gt(r){let e=r.startsWith("m")?r:"m"+r,t=sr.decode(e),i=await pt.sha256.digest(t);return or.create(1,85,i).toString()}function ut(r){let e=new TextEncoder().encode(r);return btoa(String.fromCharCode(...Array.from(e)))}var q=async({data:r,fileName:e,homeServerUrl:t,accessToken:i})=>{let n=ar({homeServerUrl:t,accessToken:i}),o=JSON.stringify(r),s=Buffer.from(o,"utf8"),c=e+".json",l=await n.media.v1beta1.upload(c,"application/ld+json",s),d=cr.mxc.mxcUrlToHttp(t,l.content_uri);if(!d)throw new Error("Failed to upload file to Matrix");let m=JSON.stringify(r),p=ut(m),v=await gt(p);return{encrypted:"false",cid:v,proof:v,serviceEndpoint:d,mxc:l.content_uri}};var O=class{constructor(e,t){this.config=t;if(!e.did||!e.pubKey||!e.address||!e.algo)throw new Error("Wallet not found");this.wallet=e}wallet;buildMsgCreateEntity(e){return{typeUrl:"/ixo.entity.v1beta1.MsgCreateEntity",value:x.entity.v1beta1.MsgCreateEntity.fromPartial({entityType:"oracle",context:[],entityStatus:0,verification:[...ft.iid.createIidVerificationMethods({did:this.wallet.did,pubkey:new Uint8Array(Buffer.from(this.wallet.pubKey)),address:this.wallet.address,controller:this.wallet.did,type:this.wallet.algo==="ed25519"?"ed":"secp"})],controller:[this.wallet.did],ownerAddress:this.wallet.address,ownerDid:this.wallet.did,relayerNode:$e[this.config.getValue("network")??"devnet"],service:[x.iid.v1beta1.Service.fromPartial({id:"{id}#matrix",type:"MatrixHomeServer",serviceEndpoint:e})],linkedResource:[],accordedRight:[],linkedEntity:[],linkedClaim:[],startDate:Oe.proto.toTimestamp(new Date),endDate:Oe.proto.toTimestamp(new Date(Date.now()+31536e8))})}}addLinkedAccounts(e,{oracleAccountAddress:t}){if(!this.wallet.signXClient||!this.wallet.wallet)throw new Error("SignX client or wallet not found");let o=[{devnet:"did:ixo:ixo17w9u5uk4qjyjgeyqfpnp92jwy58faey9vvp3ar",testnet:"did:ixo:ixo14vjrckltpngugp03tcasfgh5qakey9n3sgm6y2",mainnet:"did:ixo:ixo1d39eutxdc0e8mnp0fmzqjdy6aaf26s9hzrk33r"}[this.config.getValue("network")],`did:ixo:${t}`].map(s=>x.iid.v1beta1.LinkedEntity.fromPartial({id:s,type:"agent",relationship:"admin",service:"matrix"}));e.value.linkedEntity=o}async createAuthZConfig({oracleAccountAddress:e,oracleName:t,entityDid:i,homeServerUrl:n,accessToken:o}){let c=await q({data:{"@context":["https://schema.org",{ixo:"https://w3id.org/ixo/context/v1",oracle:{"@id":i,"@type":"@id"}}],"@type":"Service","@id":"oracle:OracleAuthorization",name:"OracleAuthorization",description:"OracleAuthorization",serviceType:"OracleClaimAuthorizationService",requiredPermissions:["/ixo.claims.v1beta1.MsgCreateClaimAuthorization"],granteeAddress:e,granterAddress:"",oracleName:t},fileName:"authz",homeServerUrl:n,accessToken:o});return x.iid.v1beta1.LinkedResource.fromPartial({id:"{id}#orz",type:"oracleAuthZConfig",proof:c.proof,right:"",encrypted:"false",mediaType:"application/json",description:"Orale AuthZ Config",serviceEndpoint:c.serviceEndpoint})}async createFeesConfig({entityDid:e,price:t,denom:i,homeServerUrl:n,accessToken:o}){let s={"@context":["https://schema.org",{ixo:"https://w3id.org/ixo/context/v1",oracle:{"@id":e,"@type":"@id"}}],"@type":"Service","@id":"oracle:ServiceFeeModel",name:"Pricing",description:"Pricing",serviceType:"",offers:{"@type":"Offer",priceCurrency:i,priceSpecification:{"@type":"PaymentChargeSpecification",priceCurrency:i,price:t*1e3,unitCode:"MON",billingIncrement:1,billingPeriod:"P1M",priceType:"Subscription",maxPrice:t},eligibleQuantity:{"@type":"QuantitativeValue",value:1,unitCode:"MON"}}},c=await q({data:s,fileName:"fees",homeServerUrl:n,accessToken:o});return x.iid.v1beta1.LinkedResource.fromPartial({id:"{id}#fee",type:"pricingList",proof:c.proof,right:"",encrypted:"false",mediaType:"application/json",description:"Pricing List",serviceEndpoint:c.serviceEndpoint})}async updateOracleDomain(e,t){let i=this.wallet.wallet?.address;if(!this.wallet.signXClient||!this.wallet.wallet||!i)throw new Error("SignX client or wallet not found");let n={typeUrl:"/ixo.iid.v1beta1.MsgDeleteService",value:x.iid.v1beta1.MsgDeleteService.fromPartial({id:e,serviceId:`${e}#api`,signer:i})},o={typeUrl:"/ixo.iid.v1beta1.MsgDeleteService",value:x.iid.v1beta1.MsgDeleteService.fromPartial({id:e,serviceId:`${e}#ws`,signer:i})},s={typeUrl:"/ixo.iid.v1beta1.MsgAddService",value:x.iid.v1beta1.MsgAddService.fromPartial({id:e,serviceData:x.iid.v1beta1.Service.fromPartial({id:`${e}#api`,type:"oracleService",serviceEndpoint:t}),signer:i})},c={typeUrl:"/ixo.iid.v1beta1.MsgAddService",value:x.iid.v1beta1.MsgAddService.fromPartial({id:e,serviceData:x.iid.v1beta1.Service.fromPartial({id:`${e}#ws`,type:"wsService",serviceEndpoint:t}),signer:i})};h.info(`Sign to update oracle domain for entity ${e}`);let a=await this.wallet.signXClient.transact([n,o,s,c],this.wallet.wallet);this.wallet.signXClient.displayTransactionQRCode(JSON.stringify(a)),await this.wallet.signXClient.pollNextTransaction(),await this.wallet.signXClient.awaitTransaction(),h.success(`Oracle domain updated to ${t}`)}async addControllerToEntity(e,t){let i=this.wallet.wallet?.address;if(!this.wallet.signXClient||!this.wallet.wallet||!i)throw new Error("SignX client or wallet not found");let n={typeUrl:"/ixo.iid.v1beta1.MsgAddController",value:x.iid.v1beta1.MsgAddController.fromPartial({id:e,controllerDid:t,signer:i})};h.info(`Sign to add controller ${t} to entity ${e}`);let o=await this.wallet.signXClient.transact([n],this.wallet.wallet);this.wallet.signXClient.displayTransactionQRCode(JSON.stringify(o)),await this.wallet.signXClient.pollNextTransaction(),await this.wallet.signXClient.awaitTransaction(),h.success(`Controller ${t} added to entity ${e}`)}async createOracleConfigFiles({oracleName:e,entityDid:t,price:i,oracleAccountAddress:n,homeServerUrl:o,accessToken:s}){let c=this.wallet.wallet?.address;if(!this.wallet.signXClient||!this.wallet.wallet||!c)throw new Error("SignX client or wallet not found");let l=(await Promise.all([this.createAuthZConfig({oracleName:e,entityDid:t,oracleAccountAddress:n,homeServerUrl:o,accessToken:s}),this.createFeesConfig({entityDid:t,price:i,denom:this.config.getValue("network")==="devnet"?"uixo":"ibc/6BBE9BD4246F8E04948D5A4EEE7164B2630263B9EBB5E7DC5F0A46C62A2FF97B",homeServerUrl:o,accessToken:s})])).map(p=>({typeUrl:"/ixo.iid.v1beta1.MsgAddLinkedResource",value:x.iid.v1beta1.MsgAddLinkedResource.fromPartial({id:t,linkedResource:x.iid.v1beta1.LinkedResource.fromPartial({id:p.id,description:p.description,type:p.type,proof:p.proof,mediaType:p.mediaType,encrypted:p.encrypted,serviceEndpoint:p.serviceEndpoint}),signer:c})}));h.info("Sign to edit the entity and add the config files");let d=await this.wallet.signXClient.transact(l,this.wallet.wallet);return this.wallet.signXClient.displayTransactionQRCode(JSON.stringify(d)),await this.wallet.signXClient.pollNextTransaction(),await this.wallet.signXClient.awaitTransaction()}async createDomainCard({profile:e,entityDid:t,homeServerUrl:i,accessToken:n}){let o=new Date().toISOString(),s={"@context":["https://www.w3.org/ns/credentials/v2","https://w3id.org/ixo/context/v1",{schema:"https://schema.org/",ixo:"https://w3id.org/ixo/vocab/v1",prov:"http://www.w3.org/ns/prov#",proj:"https://linked.data.gov.au/def/project#",xsd:"http://www.w3.org/2001/XMLSchema#",id:"@id",type:"@type","ixo:vector":{"@container":"@list","@type":"xsd:double"},"@protected":!0}],id:`${t}#dmn`,type:["VerifiableCredential","ixo:DomainCard"],issuer:{id:this.wallet.did},validFrom:o,credentialSchema:{id:"https://github.com/ixoworld/domainCards/schemas/ixo-domain-card-1.json",type:"JsonSchema"},credentialSubject:{id:t,type:["ixo:oracle"],additionalType:["schema:Organization"],name:e.name,alternateName:e.orgName!==e.name?[e.orgName]:void 0,description:e.description,logo:{type:"schema:ImageObject",id:e.logo,contentUrl:e.logo},image:[{type:"schema:ImageObject",id:e.coverImage,contentUrl:e.coverImage}],address:{type:"schema:PostalAddress",addressLocality:e.location},...e.url?{url:e.url}:{}}},c=await q({data:s,fileName:"domainCard",homeServerUrl:i,accessToken:n});return x.iid.v1beta1.LinkedResource.fromPartial({id:"{id}#dmn",type:"domainCard",proof:c.proof,right:"",encrypted:"false",mediaType:"application/json",description:"Domain Card",serviceEndpoint:c.serviceEndpoint})}async addProfile({orgName:e,name:t,logo:i,coverImage:n,location:o,description:s,homeServerUrl:c,accessToken:a}){let d=await q({data:{"@context":{ixo:"https://w3id.org/ixo/ns/protocol/","@id":"@type",type:"@type","@protected":!1},id:"ixo:entity#profile",type:"profile",orgName:e,name:t,image:n,logo:i,brand:e,location:o,description:s},fileName:"profile",homeServerUrl:c,accessToken:a});return x.iid.v1beta1.LinkedResource.fromPartial({id:"{id}#pro",type:"Settings",description:"Profile",mediaType:"application/json",serviceEndpoint:d.serviceEndpoint,proof:d.proof,encrypted:"false",right:""})}addServices(e,t){e.value.service.push(...t.map(i=>x.iid.v1beta1.Service.fromPartial(i)))}setParentProtocol(e,t){e.value.context.push(...ft.iid.createAgentIidContext([{key:"class",val:t}]))}async submitToDomainIndexer(e){let t=this.config.getValue("network")??"devnet",i=B[t];try{let n=await fetch(i,{method:"POST",headers:{accept:"application/json","Content-Type":"application/json"},body:JSON.stringify({did:e})});if(!n.ok){let o=await n.text();h.warn(`Failed to submit to domain indexer: ${n.status} ${o}`);return}h.success("Domain card submitted to domain indexer")}catch(n){h.warn(`Error submitting to domain indexer: ${n instanceof Error?n.message:String(n)}`)}}async execute(e){if(!this.wallet.signXClient||!this.wallet.wallet)throw new Error("SignX client not found");let{matrixHomeServerUrl:t}=e;h.info("Creating Oracle Wallet and Matrix Account");let i=await mr({message:"Enter a 6-digit PIN to secure your Matrix Vault:",placeholder:"123456",validate(y){return J(y)}});lr(i)&&(h.error("User cancelled"),process.exit(1));let n=await ie({pin:i,oracleName:e.oracleConfig.oracleName,network:this.config.getValue("network"),oracleAvatarUrl:e.profile.logo,matrixHomeServerUrl:t},async y=>{await this.wallet.sendTokens(y,25e4)}),o=n.matrixHomeServerUrl,s=n.matrixAccessToken;h.info("Adding profile");let c=await this.addProfile({...e.profile,homeServerUrl:o,accessToken:s}),a=this.buildMsgCreateEntity(t);a.value.linkedResource.push(c),h.info("Adding services"),this.addServices(a,e.services),h.info("Adding parent protocol"),this.setParentProtocol(a,e.parentProtocol),this.addLinkedAccounts(a,{oracleAccountAddress:n.address}),h.info("Sign this transaction to create the entity");let l=await this.wallet.signXClient.transact([a],this.wallet.wallet);this.wallet.signXClient.displayTransactionQRCode(JSON.stringify(l)),await this.wallet.signXClient.pollNextTransaction();let d=await this.wallet.signXClient.awaitTransaction();h.success("Entity created -- wait to attach the required config files");let m=Oe.common.getValueFromEvents(d,"wasm","token_id");h.info("Creating domain card");let p=await this.createDomainCard({profile:e.profile,entityDid:m,homeServerUrl:o,accessToken:s});if(this.wallet.wallet?.address){let y={typeUrl:"/ixo.iid.v1beta1.MsgAddLinkedResource",value:x.iid.v1beta1.MsgAddLinkedResource.fromPartial({id:m,linkedResource:x.iid.v1beta1.LinkedResource.fromPartial({id:p.id,description:p.description,type:p.type,proof:p.proof,mediaType:p.mediaType,encrypted:p.encrypted,serviceEndpoint:p.serviceEndpoint}),signer:this.wallet.wallet.address})};h.info("Sign to add domain card to the entity");let P=await this.wallet.signXClient.transact([y],this.wallet.wallet);this.wallet.signXClient.displayTransactionQRCode(JSON.stringify(P)),await this.wallet.signXClient.pollNextTransaction(),await this.wallet.signXClient.awaitTransaction(),h.success("Domain card added to entity")}await this.createOracleConfigFiles({oracleName:e.oracleConfig.oracleName,price:e.oracleConfig.price,oracleAccountAddress:n.address,entityDid:m,homeServerUrl:o,accessToken:s}),h.success("Entity created -- config files attached"),await re({baseUrl:o,accessToken:s,userId:n.matrixUserId,deviceId:""});let v=dr();v.start("Creating Entity Matrix Room..."),v.stop("Room created -- room joined"),h.warn("Please save the following information in a secure location as it is not stored:"),h.info("ORACLE ACCOUNT DETAILS");for(let y in n)h.info(`${y}: ${n[y]}`);return this.config.addValue("registerUserResult",n),this.config.addValue("entityDid",m),this.config.addValue("oracleMatrixHomeServerUrl",t),h.info("Submitting domain card to domain indexer"),await this.submitToDomainIndexer(m),m}};var $=class{constructor(e,t){this.wallet=e;this.config=t}name="create-entity";description="Create an entity";async execute(){this.config.getValue("network")||await S(this.config);let t=this.wallet.matrixHomeServer??L[this.config.getValue("network")??"devnet"],i=await w.group({matrixHomeServerUrl:()=>w.text({message:"Matrix homeserver URL for the oracle:",initialValue:t,defaultValue:t,validate(a){return Q(a)}}),oracleName:()=>w.text({message:"What is the name of the oracle?",initialValue:"My oracle",validate(a){return T(a,"Oracle name is required")}}),oraclePrice:()=>w.text({message:"What is the price of the oracle in IXO CREDITS?",initialValue:"100",validate(a){return Xe(parseInt(a??""),"Oracle price is required and must be a number")}}),profile:()=>w.group({orgName:()=>w.text({message:"What is the name of the organization?",initialValue:"IXO",validate(a){return T(a,"Organization name is required")}}),name:()=>w.text({message:"What is the name of the profile?",initialValue:"My oracle",validate(a){return T(a,"Profile name is required")}}),logo:({results:a})=>w.text({message:"What is the logo of the profile?",initialValue:`https://api.dicebear.com/8.x/bottts/svg?seed=${a?.name??"IXO"}`,defaultValue:`https://api.dicebear.com/8.x/bottts/svg?seed=${a?.name??"IXO"}`,validate(l){return l?_(l,"Logo is required or a valid URL"):`https://api.dicebear.com/8.x/bottts/svg?seed=${a?.name??"IXO"}`}}),coverImage:({results:a})=>w.text({message:"What is the cover image of the profile?",initialValue:a.logo,defaultValue:a.logo,validate(l){return l?_(l,"Cover image is required or a valid URL"):a.logo}}),location:()=>w.text({message:"What is the location of your domain?",initialValue:"New York, NY",validate(a){return T(a,"Location is required")}}),description:()=>w.text({message:"What is the description of the entity (profile)?",initialValue:"We are a company that helps you with daily tasks",validate(a){return T(a,"Description is required")}}),url:()=>w.text({message:"What is the website URL of the oracle? (optional, press Enter to skip)",placeholder:"https://your-oracle-website.com"})}),parentProtocol:()=>w.select({message:"What is the parent protocol of the entity?",options:[{value:"did:ixo:entity:1a76366f16570483cea72b111b27fd78",label:"IXO Oracle Protocol",hint:"default protocol"}],initialValue:"did:ixo:entity:1a76366f16570483cea72b111b27fd78"}),apiUrl:()=>w.text({message:"What is the API URL of the oracle?",initialValue:"http://localhost:4000",validate(a){return _(a,"API URL is required or a valid URL")}})},{onCancel:()=>{w.cancel("Operation cancelled."),process.exit(0)}}),o=await new O(this.wallet,this.config).execute({oracleConfig:{oracleName:i.oracleName,price:parseInt(i.oraclePrice)},profile:{orgName:i.profile.orgName,name:i.profile.name,logo:i.profile.logo,coverImage:i.profile.coverImage,location:i.profile.location,description:i.profile.description,...i.profile.url?{url:i.profile.url}:{}},services:[{id:"{id}#api",serviceEndpoint:i.apiUrl,type:"oracleService"},{id:"{id}#ws",serviceEndpoint:i.apiUrl,type:"wsService"}],parentProtocol:i.parentProtocol,matrixHomeServerUrl:i.matrixHomeServerUrl});w.log.info(`API for the oracle is: ${i.apiUrl} | You can change this after you deploy the oracle`);let c=`${We[this.config.getValue("network")??"devnet"]}/oracle/${o}/overview`;return w.log.info(`Oracle created successfully: ${o}`),w.log.info(`Oracle URL: ${c}`),{success:!0,data:`Entity created successfully: ${o}`}}};import*as E from"@clack/prompts";var ne=class{constructor(e,t){this.wallet=e;this.config=t}name="create-user";description="Create a new user";async execute(){let e=this.config.getValue("network");e||await S(this.config);let t=this.wallet.matrixHomeServer??L[this.config.getValue("network")??"devnet"],i=await E.text({message:"Matrix homeserver URL:",initialValue:t,defaultValue:t,validate(c){return Q(c)}});E.isCancel(i)&&(E.log.error("User cancelled"),process.exit(1));let n=await E.text({message:"Enter a 6-digit PIN to secure your Matrix Vault:",placeholder:"123456",validate(c){return J(c)}});E.isCancel(n)&&(E.log.error("User cancelled"),process.exit(1));let o=await E.text({message:"Enter your oracle name",initialValue:"My oracle",validate(c){return T(c,"Oracle name is required")}});E.isCancel(o)&&(E.log.error("User cancelled"),process.exit(1));let s=await ie({pin:n,oracleName:o,network:this.config.getValue("network")??e,oracleAvatarUrl:`https://api.dicebear.com/8.x/bottts/svg?seed=${o}`,matrixHomeServerUrl:i},async c=>{await this.wallet.sendTokens(c,15e4)});return await re({baseUrl:s.matrixHomeServerUrl,accessToken:s.matrixAccessToken,userId:s.matrixUserId,deviceId:""}),{success:!0,data:s}}};var H=class{constructor(e){this.registry=e}name="help";description="Show help information and available commands";async execute(){return{success:!0,data:`
|
|
3
|
-
|
|
3
|
+
QiForge CLI - Help
|
|
4
4
|
|
|
5
5
|
USAGE:
|
|
6
|
-
|
|
6
|
+
qiforge-cli [command] [options]
|
|
7
7
|
|
|
8
8
|
COMMANDS:
|
|
9
9
|
${this.registry.getAll().map(i=>` ${i.name.padEnd(15)} ${i.description}`).join(`
|
|
10
10
|
`)}
|
|
11
11
|
|
|
12
12
|
EXAMPLES:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
qiforge-cli --init Initialize a new IXO Oracle project
|
|
14
|
+
qiforge-cli Launch interactive menu
|
|
15
|
+
qiforge-cli help Show this help message
|
|
16
16
|
|
|
17
17
|
OPTIONS:
|
|
18
18
|
--init Initialize a new project (shortcut)
|
|
19
19
|
--help, -h Show help information
|
|
20
20
|
|
|
21
|
-
For more information, visit: https://
|
|
21
|
+
For more information, visit: https://www.npmjs.com/package/qiforge-cli
|
|
22
22
|
`}}};import*as g from"@clack/prompts";import{existsSync as ae}from"fs";import W from"path";import wt from"simple-git";import se from"fs";import oe from"path";function pr(r,e){return`
|
|
23
23
|
PORT=4000
|
|
24
24
|
ORACLE_NAME=${e.oracleName}
|
|
@@ -73,7 +73,7 @@ SUBSCRIPTION_URL=${Ee[r]}
|
|
|
73
73
|
### BACKUP \u2014 save these securely (values above are already set)
|
|
74
74
|
# ORACLE_ADDRESS=${e.oracleAddress}
|
|
75
75
|
# ORACLE_DID=${e.oracleDid}
|
|
76
|
-
`}function gr(r,e){return`# To fill in the blank values, run:
|
|
76
|
+
`}function gr(r,e){return`# To fill in the blank values, run: qiforge-cli create-entity (select ${r})
|
|
77
77
|
|
|
78
78
|
PORT=4000
|
|
79
79
|
ORACLE_NAME=${e}
|
|
@@ -134,7 +134,7 @@ LANGSMITH_PROJECT="${e}_${r}"
|
|
|
134
134
|
pnpm install
|
|
135
135
|
pnpm build
|
|
136
136
|
cd apps/app
|
|
137
|
-
pnpm start:dev`)}catch(s){throw o.stop("Failed to clone repository"),s}}async execute(){try{let{projectPath:e,projectName:t}=await this.getProjectInput();if(!await this.confirmProjectCreation(e,t))return{success:!1,data:"Project creation cancelled"};this.config.addValue("projectPath",e),this.config.addValue("projectName",t);let n=await this.selectRepo();this.config.addValue("repo",n);let o=ae(e);return await this.cloneRepo(n,e,o),{success:!0,data:`Project "${t}" created successfully in "${e}"`}}catch(e){return{success:!1,error:e instanceof Error?e.message:"Unknown error occurred"}}}};import{confirm as ur}from"@clack/prompts";var le=class{constructor(e){this.wallet=e}name="logout";description="Logout command";async execute(){return await ur({message:"Are you sure you want to logout?",initialValue:!1})?(await this.wallet.clearWallet(),{success:!0,data:"Logged out successfully"}):{success:!1,error:"Logout cancelled"}}};import{toHex as fr}from"@cosmjs/encoding";import{createRegistry as hr}from"@ixo/impactxclient-sdk";import{SignX as yt,SIGN_X_LOGIN_ERROR as wr,SIGN_X_LOGIN_SUCCESS as yr,SIGN_X_TRANSACT_ERROR as xr,SIGN_X_TRANSACT_SUCCESS as vr}from"@ixo/signx-sdk";import Cr from"qrcode-terminal";var xt={devnet:"https://signx.devnet.ixo.earth",testnet:"https://signx.testnet.ixo.earth",mainnet:"https://signx.ixo.earth"},X=class{signXClient;_loginData;get loginData(){return this._loginData}static loadFromWallet(e){return new yt({endpoint:xt[e.network],sitename:"
|
|
137
|
+
pnpm start:dev`)}catch(s){throw o.stop("Failed to clone repository"),s}}async execute(){try{let{projectPath:e,projectName:t}=await this.getProjectInput();if(!await this.confirmProjectCreation(e,t))return{success:!1,data:"Project creation cancelled"};this.config.addValue("projectPath",e),this.config.addValue("projectName",t);let n=await this.selectRepo();this.config.addValue("repo",n);let o=ae(e);return await this.cloneRepo(n,e,o),{success:!0,data:`Project "${t}" created successfully in "${e}"`}}catch(e){return{success:!1,error:e instanceof Error?e.message:"Unknown error occurred"}}}};import{confirm as ur}from"@clack/prompts";var le=class{constructor(e){this.wallet=e}name="logout";description="Logout command";async execute(){return await ur({message:"Are you sure you want to logout?",initialValue:!1})?(await this.wallet.clearWallet(),{success:!0,data:"Logged out successfully"}):{success:!1,error:"Logout cancelled"}}};import{toHex as fr}from"@cosmjs/encoding";import{createRegistry as hr}from"@ixo/impactxclient-sdk";import{SignX as yt,SIGN_X_LOGIN_ERROR as wr,SIGN_X_LOGIN_SUCCESS as yr,SIGN_X_TRANSACT_ERROR as xr,SIGN_X_TRANSACT_SUCCESS as vr}from"@ixo/signx-sdk";import Cr from"qrcode-terminal";var xt={devnet:"https://signx.devnet.ixo.earth",testnet:"https://signx.testnet.ixo.earth",mainnet:"https://signx.ixo.earth"},X=class{signXClient;_loginData;get loginData(){return this._loginData}static loadFromWallet(e){return new yt({endpoint:xt[e.network],sitename:"QiForge CLI",network:e.network})}constructor(e){this.signXClient=new yt({endpoint:xt[e],sitename:"QiForge CLI",network:e})}async login(){let e=await this.signXClient.login({pollingInterval:2e3,matrix:!0});return this._loginData=e,e}displayStyledQRCode(e,t){let i=typeof e=="string"?e:JSON.stringify(e);console.log(`
|
|
138
138
|
`+" ".repeat(5)+"\u{1F510} "+t),console.log(" ".repeat(5)+"\u{1F4F1} Scan with IXO app"),console.log(" ".repeat(5)+"\u2501".repeat(30)),Cr.generate(i,{small:!0}),console.log(" ".repeat(5)+`\u23F3 Waiting...
|
|
139
139
|
`)}displayQRCode(e){this.displayStyledQRCode(e,"Login with SignX")}async awaitLogin(){return new Promise((e,t)=>{try{this.signXClient.on(yr,i=>{if(!i.data){t(new Error("Login failed"));return}if(!i.data.matrix){t(new Error("Matrix login failed"));return}e(i.data)}),this.signXClient.on(wr,i=>{console.log("Login error:",i),t(i)})}catch(i){console.error("Error in connecting:",i),t(i)}})}async transact(e,t,i){let n=hr();return this.signXClient.transact({address:t.address,did:t.did,pubkey:t.pubKey,timestamp:new Date().toISOString(),transactions:[{sequence:1,txBodyHex:fr(n.encodeTxBody({messages:e,memo:i||""}))}]})}async awaitTransaction(){return new Promise((e,t)=>{try{this.signXClient.on(vr,i=>{e(i.data)}),this.signXClient.on(xr,i=>{t(i)})}catch(i){console.error("Error in connecting:",i),t(i)}})}async pollNextTransaction(){return this.signXClient.pollNextTransaction()}displayTransactionQRCode(e){this.displayStyledQRCode(e,"SIGNX TRANSACTION")}};var de=class{constructor(e,t){this.wallet=e;this.config=t}name="signx-login";description="Login with SignX wallet";async execute(){try{let e=await S(this.config),t=new X(e),i=await t.login();t.displayQRCode(i);let n=await t.awaitLogin();return this.wallet.setWallet(n),this.wallet.setSignXClient(t),{success:!0,data:{message:"Successfully logged in with SignX!",wallet:{address:n.address,did:n.did,name:n.name}}}}catch(e){return{success:!1,error:e instanceof Error?`SignX login failed: ${e.message}`:"Unknown error"}}}};import*as I from"@clack/prompts";var me=class{constructor(e,t){this.wallet=e;this.config=t}name="update-oracle-api-url";description="Update the oracle API domain (default is localhost)";async execute(){this.config.getValue("network")||await S(this.config);let t=await I.group({entityDid:()=>I.text({message:"What is the DID of the entity you want to update?",initialValue:this.config.getValue("entityDid")?.toString()??"",validate(i){return F(i)}}),apiUrl:()=>I.text({message:"What is the new API URL (domain) for the oracle?",initialValue:"http://localhost:4000",validate(i){return _(i,"API URL is required and must be a valid URL")}})},{onCancel:()=>{I.cancel("Operation cancelled."),process.exit(0)}});try{let i=new O(this.wallet,this.config);return I.log.info(`Updating oracle domain for entity ${t.entityDid} to ${t.apiUrl}`),await i.updateOracleDomain(t.entityDid,t.apiUrl),{success:!0,data:`Oracle domain updated to ${t.apiUrl} for entity ${t.entityDid}`}}catch(i){return{success:!1,error:i instanceof Error?i.message:String(i)}}}};import*as C from"@clack/prompts";var pe=class{constructor(e,t){this.wallet=e;this.config=t;this.createEntity=new O(this.wallet,this.config)}name="update-entity";description="Update an entity (add controllers, etc.)";createEntity;async execute(){this.config.getValue("network")||await S(this.config);let t=await C.group({entityDid:()=>C.text({message:"What is the DID of the entity you want to update?",initialValue:this.config.getValue("entityDid")?.toString()??"",validate(i){return F(i)}}),action:()=>C.select({message:"What would you like to do?",options:[{value:"add-controller",label:"Add Controller",hint:"Add a new controller DID to the entity"}],initialValue:"add-controller"}),controllerDid:async({results:i})=>{if(i.action!=="add-controller")throw new Error("Unknown action");let n=await C.text({message:"What is the DID of the controller you want to add?",validate(o){return F(o)}});return C.isCancel(n)&&(C.cancel("Operation cancelled."),process.exit(0)),n}},{onCancel:()=>{C.cancel("Operation cancelled."),process.exit(0)}});try{if(t.action==="add-controller"&&typeof t.controllerDid=="string"){let i=t.controllerDid,n=t.entityDid;return C.log.info(`Adding controller ${i} to entity ${n}`),await this.createEntity.addControllerToEntity(n,i),C.log.success(`Controller ${i} successfully added to entity ${n}`),{success:!0,data:`Controller ${i} added to entity ${n}`}}return{success:!1,error:"Unknown action"}}catch(i){return{success:!1,error:i instanceof Error?i.message:String(i)}}}};var ke=class extends Error{constructor(t,i="CLI_ERROR",n){super(t);this.code=i;this.suggestions=n;this.name="CLIError"}};function ge(r){r instanceof ke&&(console.error(`
|
|
140
140
|
\u274C ${r.name}: ${r.message}`),r.suggestions?.length&&(console.error(`
|