@halot/cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +14 -0
- package/README.md +374 -0
- package/dist/features/browse/browse.command.js +15 -0
- package/dist/features/jobs/job-create.command.js +57 -0
- package/dist/features/jobs/job-funding.service.js +95 -0
- package/dist/features/jobs/job-result.command.js +10 -0
- package/dist/features/jobs/job-watch.command.js +18 -0
- package/dist/features/provider/provider-init.command.js +33 -0
- package/dist/features/provider/provider-register.command.js +72 -0
- package/dist/features/provider/provider-run.command.js +148 -0
- package/dist/features/provider/provider-services.command.js +13 -0
- package/dist/features/provider/provider-stats.command.js +13 -0
- package/dist/features/provider/provider-update.command.js +35 -0
- package/dist/features/quotes/quote.command.js +13 -0
- package/dist/features/requester/requester-init.command.js +22 -0
- package/dist/features/service/service-create.command.js +57 -0
- package/dist/features/service/service-init.command.js +89 -0
- package/dist/features/service/service-list.command.js +23 -0
- package/dist/features/service/service-remove.command.js +21 -0
- package/dist/features/service/service-update.command.js +65 -0
- package/dist/features/verifier/verifier-init.command.js +69 -0
- package/dist/features/verifier/verifier-register.command.js +90 -0
- package/dist/features/verifier/verifier-run.command.js +143 -0
- package/dist/features/verifier/verifier-stats.command.js +13 -0
- package/dist/features/verifier/verifier-unstake.command.js +31 -0
- package/dist/index.js +136 -0
- package/dist/shared/auth/actor-headers.service.js +13 -0
- package/dist/shared/config/env.js +77 -0
- package/dist/shared/http/api-client.js +66 -0
- package/dist/shared/http/event-stream.js +75 -0
- package/dist/shared/integrations/agent-id/agent-id-register.service.js +159 -0
- package/dist/shared/integrations/space-id/space-id-register.service.js +467 -0
- package/dist/shared/integrations/zero-g/verifier-registry.service.js +55 -0
- package/dist/shared/output/print.util.js +10 -0
- package/dist/shared/wallet/authority.util.js +62 -0
- package/dist/shared/wallet/wallet.manager.js +41 -0
- package/dist/shared/workspace/workspace.service.js +192 -0
- package/package.json +47 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runVerifierRegisterCommand = runVerifierRegisterCommand;
|
|
4
|
+
const ethers_1 = require("ethers");
|
|
5
|
+
const actor_headers_service_1 = require("@halot/cli/shared/auth/actor-headers.service");
|
|
6
|
+
const api_client_1 = require("@halot/cli/shared/http/api-client");
|
|
7
|
+
const agent_id_register_service_1 = require("@halot/cli/shared/integrations/agent-id/agent-id-register.service");
|
|
8
|
+
const space_id_register_service_1 = require("@halot/cli/shared/integrations/space-id/space-id-register.service");
|
|
9
|
+
const verifier_registry_service_1 = require("@halot/cli/shared/integrations/zero-g/verifier-registry.service");
|
|
10
|
+
const print_util_1 = require("@halot/cli/shared/output/print.util");
|
|
11
|
+
const authority_util_1 = require("@halot/cli/shared/wallet/authority.util");
|
|
12
|
+
const workspace_service_1 = require("@halot/cli/shared/workspace/workspace.service");
|
|
13
|
+
async function runVerifierRegisterCommand(options) {
|
|
14
|
+
const workspace = new workspace_service_1.WorkspaceService();
|
|
15
|
+
const api = new api_client_1.ApiClient(options.server);
|
|
16
|
+
const agentIdRegisterService = new agent_id_register_service_1.AgentIdRegisterService();
|
|
17
|
+
const domainRegistrationService = new space_id_register_service_1.SpaceIdRegisterService();
|
|
18
|
+
const verifierRegistryService = new verifier_registry_service_1.ZeroGVerifierRegistryService();
|
|
19
|
+
const config = workspace.readVerifierConfig();
|
|
20
|
+
const wallets = workspace.readWallets(config.authority.path);
|
|
21
|
+
const specializations = workspace.readSpecializations();
|
|
22
|
+
const verifierWallet = (0, authority_util_1.resolveActorWallet)(wallets, config.authority.actor);
|
|
23
|
+
const signingPublicKey = (0, authority_util_1.deriveVerifierSigningPublicKey)(wallets, config.authority.actor);
|
|
24
|
+
const chain = (0, authority_util_1.resolveZeroGAuthorityProfile)(config.authority.actor);
|
|
25
|
+
const isMainnet = (0, authority_util_1.isMainnetAuthority)(config.authority.actor);
|
|
26
|
+
if (isMainnet) {
|
|
27
|
+
const domainResult = await domainRegistrationService.registerZeroGDomain({
|
|
28
|
+
domain: config.identity.domain,
|
|
29
|
+
address: verifierWallet.address,
|
|
30
|
+
privateKey: verifierWallet.privateKey,
|
|
31
|
+
chainId: chain.chainId,
|
|
32
|
+
rpcUrl: chain.rpcUrl,
|
|
33
|
+
});
|
|
34
|
+
console.log(`Registered ${domainResult.domain}${domainResult.transactionHash ? ` (${domainResult.transactionHash})` : ''}`);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
console.log('Skipping Space ID domain registration (testnet mode)');
|
|
38
|
+
}
|
|
39
|
+
let verifier = await api.post('/verifiers/register', {
|
|
40
|
+
config: {
|
|
41
|
+
...config,
|
|
42
|
+
identity: {
|
|
43
|
+
...config.identity,
|
|
44
|
+
ownerAddress: verifierWallet.address,
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
specializations,
|
|
48
|
+
ownerAddress: verifierWallet.address,
|
|
49
|
+
signingPublicKey,
|
|
50
|
+
});
|
|
51
|
+
if (isMainnet) {
|
|
52
|
+
const agentUri = (0, agent_id_register_service_1.createZeroGAgentUri)(verifier.rootHash);
|
|
53
|
+
const agentResult = await agentIdRegisterService.registerAgent({
|
|
54
|
+
ownerAddress: verifierWallet.address,
|
|
55
|
+
privateKey: verifierWallet.privateKey,
|
|
56
|
+
chainId: chain.chainId,
|
|
57
|
+
rpcUrl: chain.rpcUrl,
|
|
58
|
+
agentUri,
|
|
59
|
+
});
|
|
60
|
+
const path = `/verifiers/${verifier.verifierId}/identity`;
|
|
61
|
+
const headers = await (0, actor_headers_service_1.createSignedActorHeaders)(new ethers_1.Wallet(verifierWallet.privateKey), verifier.verifierId, 'verifier', 'POST', path);
|
|
62
|
+
verifier = await api.post(path, {
|
|
63
|
+
erc8004TokenId: agentResult.agentId,
|
|
64
|
+
agentRegistry: agentResult.agentRegistry,
|
|
65
|
+
agentUri: agentResult.agentUri,
|
|
66
|
+
}, headers);
|
|
67
|
+
console.log(`Registered Agent ID ${agentResult.agentId}${agentResult.transactionHash ? ` (${agentResult.transactionHash})` : ''}`);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
console.log('Skipping Agent ID registration (testnet mode)');
|
|
71
|
+
}
|
|
72
|
+
const registryResult = await verifierRegistryService.registerVerifier({
|
|
73
|
+
privateKey: verifierWallet.privateKey,
|
|
74
|
+
rpcUrl: chain.rpcUrl,
|
|
75
|
+
categories: specializations.categories,
|
|
76
|
+
serviceIds: specializations.serviceIds,
|
|
77
|
+
stakeAmount: config.stake.amount,
|
|
78
|
+
});
|
|
79
|
+
console.log(`Registered verifier stake ${registryResult.transactionHash}`);
|
|
80
|
+
workspace.writeVerifierConfig({
|
|
81
|
+
...config,
|
|
82
|
+
verifierId: verifier.verifierId,
|
|
83
|
+
identity: verifier.identity,
|
|
84
|
+
stake: {
|
|
85
|
+
...config.stake,
|
|
86
|
+
status: 'locked',
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
(0, print_util_1.printJson)(verifier);
|
|
90
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runVerifierRunCommand = runVerifierRunCommand;
|
|
4
|
+
exports.assertSupportedAssignment = assertSupportedAssignment;
|
|
5
|
+
exports.applyConfidenceThreshold = applyConfidenceThreshold;
|
|
6
|
+
const sdk_1 = require("@halot/sdk");
|
|
7
|
+
const api_client_1 = require("@halot/cli/shared/http/api-client");
|
|
8
|
+
const event_stream_1 = require("@halot/cli/shared/http/event-stream");
|
|
9
|
+
const print_util_1 = require("@halot/cli/shared/output/print.util");
|
|
10
|
+
const actor_headers_service_1 = require("@halot/cli/shared/auth/actor-headers.service");
|
|
11
|
+
const authority_util_1 = require("@halot/cli/shared/wallet/authority.util");
|
|
12
|
+
const workspace_service_1 = require("@halot/cli/shared/workspace/workspace.service");
|
|
13
|
+
async function runVerifierRunCommand(options) {
|
|
14
|
+
const workspace = new workspace_service_1.WorkspaceService();
|
|
15
|
+
const api = new api_client_1.ApiClient(options.server);
|
|
16
|
+
const config = workspace.readVerifierConfig();
|
|
17
|
+
const wallets = workspace.readWallets(config.authority.path);
|
|
18
|
+
const modelConfig = workspace.readModelConfig();
|
|
19
|
+
const inferenceTemplate = workspace.readInferenceTemplate();
|
|
20
|
+
const specializations = workspace.readSpecializations();
|
|
21
|
+
const verifierWallet = (0, authority_util_1.resolveActorWallet)(wallets, config.authority.actor);
|
|
22
|
+
const chain = (0, authority_util_1.resolveZeroGAuthorityProfile)(config.authority.actor);
|
|
23
|
+
const compute = new sdk_1.ZeroGComputeService({
|
|
24
|
+
privateKey: verifierWallet.privateKey,
|
|
25
|
+
rpcUrl: modelConfig.sdk.rpcUrl ?? chain.rpcUrl,
|
|
26
|
+
providerAddress: modelConfig.evaluationModel.providerAddress,
|
|
27
|
+
ledgerContractAddress: modelConfig.sdk.ledgerContractAddress,
|
|
28
|
+
inferenceContractAddress: modelConfig.sdk.inferenceContractAddress,
|
|
29
|
+
fineTuningContractAddress: modelConfig.sdk.fineTuningContractAddress,
|
|
30
|
+
});
|
|
31
|
+
const intervalMs = Number(options.interval);
|
|
32
|
+
const workerId = (0, sdk_1.createPrefixedId)('worker');
|
|
33
|
+
const cursorKey = `verifier:${config.verifierId}`;
|
|
34
|
+
let lastEventId = workspace.readStreamCursor(cursorKey);
|
|
35
|
+
if (!modelConfig.evaluationModel.providerAddress) {
|
|
36
|
+
throw new Error('model.config.json must set evaluationModel.providerAddress for real 0G TeeML verification.');
|
|
37
|
+
}
|
|
38
|
+
if (options.once) {
|
|
39
|
+
const assignmentPath = `/verifiers/${config.verifierId}/jobs/next`;
|
|
40
|
+
const headers = await (0, actor_headers_service_1.createSignedActorHeaders)(verifierWallet, config.verifierId, 'verifier', 'GET', assignmentPath);
|
|
41
|
+
const assignment = await api.get(assignmentPath, headers);
|
|
42
|
+
if (!assignment || !assignment.result) {
|
|
43
|
+
console.log('No verifier assignments available.');
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
await processVerifierAssignment(api, verifierWallet, config.verifierId, assignment, compute, inferenceTemplate, modelConfig, specializations);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
do {
|
|
50
|
+
try {
|
|
51
|
+
const streamPath = `/verifiers/${config.verifierId}/jobs/stream`;
|
|
52
|
+
const headers = {
|
|
53
|
+
...(await (0, actor_headers_service_1.createSignedActorHeaders)(verifierWallet, config.verifierId, 'verifier', 'GET', streamPath)),
|
|
54
|
+
'x-halot-worker-id': workerId,
|
|
55
|
+
};
|
|
56
|
+
for await (const event of (0, event_stream_1.connectEventStream)(`${options.server}${streamPath}`, headers, lastEventId)) {
|
|
57
|
+
if (event.event === 'checkpoint') {
|
|
58
|
+
if (event.id) {
|
|
59
|
+
lastEventId = event.id;
|
|
60
|
+
workspace.writeStreamCursor(cursorKey, event.id);
|
|
61
|
+
}
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (event.event !== 'assignment') {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const assignment = JSON.parse(event.data);
|
|
68
|
+
if (!assignment.result) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
await processVerifierAssignment(api, verifierWallet, config.verifierId, assignment, compute, inferenceTemplate, modelConfig, specializations);
|
|
72
|
+
if (event.id) {
|
|
73
|
+
lastEventId = event.id;
|
|
74
|
+
workspace.writeStreamCursor(cursorKey, event.id);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
80
|
+
await (0, print_util_1.sleep)(intervalMs);
|
|
81
|
+
}
|
|
82
|
+
} while (true);
|
|
83
|
+
}
|
|
84
|
+
async function processVerifierAssignment(api, verifierWallet, verifierId, assignment, compute, inferenceTemplate, modelConfig, specializations) {
|
|
85
|
+
assertSupportedAssignment(assignment.service, specializations);
|
|
86
|
+
const rawEvaluation = await compute.evaluate({
|
|
87
|
+
jobHash: assignment.job.jobHash,
|
|
88
|
+
resultHash: assignment.result.resultHash,
|
|
89
|
+
input: assignment.job.input,
|
|
90
|
+
result: assignment.result.output,
|
|
91
|
+
service: assignment.service,
|
|
92
|
+
providerAddress: modelConfig.evaluationModel.providerAddress,
|
|
93
|
+
systemPrompt: inferenceTemplate.systemPrompt,
|
|
94
|
+
promptTemplate: inferenceTemplate.promptTemplate,
|
|
95
|
+
outputSchema: inferenceTemplate.outputSchema,
|
|
96
|
+
maxTokens: inferenceTemplate.maxTokens,
|
|
97
|
+
temperature: inferenceTemplate.temperature,
|
|
98
|
+
});
|
|
99
|
+
const evaluation = applyConfidenceThreshold(rawEvaluation, specializations.minConfidenceThreshold);
|
|
100
|
+
const verifierSignature = await (0, sdk_1.signAttestationPayload)(verifierWallet, {
|
|
101
|
+
jobHash: assignment.job.jobHash,
|
|
102
|
+
resultHash: assignment.result.resultHash,
|
|
103
|
+
decision: evaluation.decision,
|
|
104
|
+
teeDigest: evaluation.teeProof.digest,
|
|
105
|
+
});
|
|
106
|
+
const attestPath = `/jobs/${assignment.job.jobId}/attest`;
|
|
107
|
+
const attestHeaders = await (0, actor_headers_service_1.createSignedActorHeaders)(verifierWallet, verifierId, 'verifier', 'POST', attestPath);
|
|
108
|
+
const job = await api.post(attestPath, {
|
|
109
|
+
jobHash: assignment.job.jobHash,
|
|
110
|
+
resultHash: assignment.result.resultHash,
|
|
111
|
+
verifierId,
|
|
112
|
+
verifierAddress: verifierWallet.address,
|
|
113
|
+
decision: evaluation.decision,
|
|
114
|
+
confidence: evaluation.confidence,
|
|
115
|
+
reason: evaluation.reason,
|
|
116
|
+
failedCriteria: evaluation.failedCriteria,
|
|
117
|
+
teeVerified: evaluation.teeVerified,
|
|
118
|
+
teeProof: evaluation.teeProof,
|
|
119
|
+
verifierSignature,
|
|
120
|
+
modelConfig,
|
|
121
|
+
}, attestHeaders);
|
|
122
|
+
(0, print_util_1.printJson)(job);
|
|
123
|
+
}
|
|
124
|
+
function assertSupportedAssignment(service, specializations) {
|
|
125
|
+
if (!specializations.categories.includes(service.category)) {
|
|
126
|
+
throw new Error(`Verifier is not specialized for ${service.category} services.`);
|
|
127
|
+
}
|
|
128
|
+
if (specializations.serviceIds.length > 0 && !specializations.serviceIds.includes(service.serviceId)) {
|
|
129
|
+
throw new Error(`Verifier is not specialized for service ${service.serviceId}.`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function applyConfidenceThreshold(evaluation, minConfidenceThreshold) {
|
|
133
|
+
if (evaluation.decision === 'uncertain' || evaluation.confidence >= minConfidenceThreshold) {
|
|
134
|
+
return evaluation;
|
|
135
|
+
}
|
|
136
|
+
const thresholdMessage = `confidence ${evaluation.confidence.toFixed(2)} is below verifier threshold ${minConfidenceThreshold.toFixed(2)}`;
|
|
137
|
+
return {
|
|
138
|
+
...evaluation,
|
|
139
|
+
decision: 'uncertain',
|
|
140
|
+
reason: `${evaluation.reason} ${thresholdMessage}.`.trim(),
|
|
141
|
+
failedCriteria: [...new Set([...evaluation.failedCriteria, thresholdMessage])],
|
|
142
|
+
};
|
|
143
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runVerifierStatsCommand = runVerifierStatsCommand;
|
|
4
|
+
const api_client_1 = require("@halot/cli/shared/http/api-client");
|
|
5
|
+
const print_util_1 = require("@halot/cli/shared/output/print.util");
|
|
6
|
+
const workspace_service_1 = require("@halot/cli/shared/workspace/workspace.service");
|
|
7
|
+
async function runVerifierStatsCommand(options) {
|
|
8
|
+
const workspace = new workspace_service_1.WorkspaceService();
|
|
9
|
+
const config = workspace.readVerifierConfig();
|
|
10
|
+
const api = new api_client_1.ApiClient(options.server);
|
|
11
|
+
const stats = await api.get(`/verifiers/${config.verifierId}/stats`);
|
|
12
|
+
(0, print_util_1.printJson)(stats);
|
|
13
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runVerifierUnstakeCommand = runVerifierUnstakeCommand;
|
|
4
|
+
const verifier_registry_service_1 = require("@halot/cli/shared/integrations/zero-g/verifier-registry.service");
|
|
5
|
+
const authority_util_1 = require("@halot/cli/shared/wallet/authority.util");
|
|
6
|
+
const workspace_service_1 = require("@halot/cli/shared/workspace/workspace.service");
|
|
7
|
+
async function runVerifierUnstakeCommand(options) {
|
|
8
|
+
const workspace = new workspace_service_1.WorkspaceService();
|
|
9
|
+
const registryService = new verifier_registry_service_1.ZeroGVerifierRegistryService();
|
|
10
|
+
const config = workspace.readVerifierConfig();
|
|
11
|
+
const wallets = workspace.readWallets(config.authority.path);
|
|
12
|
+
const verifierWallet = (0, authority_util_1.resolveActorWallet)(wallets, config.authority.actor);
|
|
13
|
+
const chain = (0, authority_util_1.resolveZeroGAuthorityProfile)(config.authority.actor);
|
|
14
|
+
const result = options.claim
|
|
15
|
+
? await registryService.withdrawStake({
|
|
16
|
+
privateKey: verifierWallet.privateKey,
|
|
17
|
+
rpcUrl: chain.rpcUrl,
|
|
18
|
+
})
|
|
19
|
+
: await registryService.requestUnstake({
|
|
20
|
+
privateKey: verifierWallet.privateKey,
|
|
21
|
+
rpcUrl: chain.rpcUrl,
|
|
22
|
+
});
|
|
23
|
+
workspace.writeVerifierConfig({
|
|
24
|
+
...config,
|
|
25
|
+
stake: {
|
|
26
|
+
...config.stake,
|
|
27
|
+
status: options.claim ? 'unlocked' : 'unlocking',
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
console.log(`${options.claim ? 'Withdrew verifier stake' : 'Requested verifier unstake'} (${result.transactionHash})`);
|
|
31
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const browse_command_1 = require("@halot/cli/features/browse/browse.command");
|
|
6
|
+
const job_create_command_1 = require("@halot/cli/features/jobs/job-create.command");
|
|
7
|
+
const job_result_command_1 = require("@halot/cli/features/jobs/job-result.command");
|
|
8
|
+
const job_watch_command_1 = require("@halot/cli/features/jobs/job-watch.command");
|
|
9
|
+
const provider_init_command_1 = require("@halot/cli/features/provider/provider-init.command");
|
|
10
|
+
const provider_register_command_1 = require("@halot/cli/features/provider/provider-register.command");
|
|
11
|
+
const provider_run_command_1 = require("@halot/cli/features/provider/provider-run.command");
|
|
12
|
+
const provider_stats_command_1 = require("@halot/cli/features/provider/provider-stats.command");
|
|
13
|
+
const provider_update_command_1 = require("@halot/cli/features/provider/provider-update.command");
|
|
14
|
+
const quote_command_1 = require("@halot/cli/features/quotes/quote.command");
|
|
15
|
+
const requester_init_command_1 = require("@halot/cli/features/requester/requester-init.command");
|
|
16
|
+
const service_create_command_1 = require("@halot/cli/features/service/service-create.command");
|
|
17
|
+
const service_init_command_1 = require("@halot/cli/features/service/service-init.command");
|
|
18
|
+
const service_list_command_1 = require("@halot/cli/features/service/service-list.command");
|
|
19
|
+
const service_remove_command_1 = require("@halot/cli/features/service/service-remove.command");
|
|
20
|
+
const service_update_command_1 = require("@halot/cli/features/service/service-update.command");
|
|
21
|
+
const verifier_init_command_1 = require("@halot/cli/features/verifier/verifier-init.command");
|
|
22
|
+
const verifier_register_command_1 = require("@halot/cli/features/verifier/verifier-register.command");
|
|
23
|
+
const verifier_run_command_1 = require("@halot/cli/features/verifier/verifier-run.command");
|
|
24
|
+
const verifier_stats_command_1 = require("@halot/cli/features/verifier/verifier-stats.command");
|
|
25
|
+
const verifier_unstake_command_1 = require("@halot/cli/features/verifier/verifier-unstake.command");
|
|
26
|
+
const env_1 = require("@halot/cli/shared/config/env");
|
|
27
|
+
(0, env_1.loadCliEnv)();
|
|
28
|
+
const defaultServerUrl = (0, env_1.loadCliEnv)().serverUrl ?? 'http://localhost:3001';
|
|
29
|
+
const program = new commander_1.Command();
|
|
30
|
+
program
|
|
31
|
+
.name('halot')
|
|
32
|
+
.description('Halot protocol CLI')
|
|
33
|
+
.version('1.0.0');
|
|
34
|
+
program
|
|
35
|
+
.command('browse')
|
|
36
|
+
.option('--server <url>', 'Halot server url', defaultServerUrl)
|
|
37
|
+
.option('--service <id>', 'Show a specific service')
|
|
38
|
+
.action(browse_command_1.runBrowseCommand);
|
|
39
|
+
program
|
|
40
|
+
.command('quote')
|
|
41
|
+
.requiredOption('--service <id>', 'Service id')
|
|
42
|
+
.requiredOption('--input <json>', 'Input JSON')
|
|
43
|
+
.option('--server <url>', 'Halot server url', defaultServerUrl)
|
|
44
|
+
.action(quote_command_1.runQuoteCommand);
|
|
45
|
+
const requester = program.command('requester').description('Requester workspace');
|
|
46
|
+
requester
|
|
47
|
+
.command('init')
|
|
48
|
+
.action(requester_init_command_1.runRequesterInitCommand);
|
|
49
|
+
const provider = program.command('provider').description('Provider workspace');
|
|
50
|
+
provider.command('init').action(provider_init_command_1.runProviderInitCommand);
|
|
51
|
+
provider
|
|
52
|
+
.command('register')
|
|
53
|
+
.option('--server <url>', 'Halot server url', defaultServerUrl)
|
|
54
|
+
.action(provider_register_command_1.runProviderRegisterCommand);
|
|
55
|
+
provider
|
|
56
|
+
.command('update')
|
|
57
|
+
.option('--server <url>', 'Halot server url', defaultServerUrl)
|
|
58
|
+
.action(provider_update_command_1.runProviderUpdateCommand);
|
|
59
|
+
provider
|
|
60
|
+
.command('run')
|
|
61
|
+
.option('--server <url>', 'Halot server url', defaultServerUrl)
|
|
62
|
+
.option('--once', 'Process a single assignment', false)
|
|
63
|
+
.option('--interval <ms>', 'Polling interval in milliseconds', '3000')
|
|
64
|
+
.action(provider_run_command_1.runProviderRunCommand);
|
|
65
|
+
provider
|
|
66
|
+
.command('stats')
|
|
67
|
+
.option('--server <url>', 'Halot server url', defaultServerUrl)
|
|
68
|
+
.action(provider_stats_command_1.runProviderStatsCommand);
|
|
69
|
+
const service = program.command('service').description('Service management');
|
|
70
|
+
service
|
|
71
|
+
.command('init')
|
|
72
|
+
.option('--name <name>', 'Service name')
|
|
73
|
+
.option('--description <text>', 'Service description')
|
|
74
|
+
.option('--category <category>', 'Service category: text, code, image, audio, video, document, tool, workflow')
|
|
75
|
+
.option('--trust-level <level>', 'Trust level: standard, thorough, critical, auto')
|
|
76
|
+
.action(service_init_command_1.runServiceInitCommand);
|
|
77
|
+
service
|
|
78
|
+
.command('register')
|
|
79
|
+
.alias('create')
|
|
80
|
+
.option('--server <url>', 'Halot server url', defaultServerUrl)
|
|
81
|
+
.option('--file <name>', 'Service file name')
|
|
82
|
+
.action(service_create_command_1.runServiceRegisterCommand);
|
|
83
|
+
service
|
|
84
|
+
.command('list')
|
|
85
|
+
.option('--server <url>', 'Halot server url', defaultServerUrl)
|
|
86
|
+
.action(service_list_command_1.runServiceListCommand);
|
|
87
|
+
service
|
|
88
|
+
.command('update [serviceId]')
|
|
89
|
+
.option('--server <url>', 'Halot server url', defaultServerUrl)
|
|
90
|
+
.option('--file <name>', 'Service file name')
|
|
91
|
+
.action(service_update_command_1.runServiceUpdateCommand);
|
|
92
|
+
service
|
|
93
|
+
.command('remove <serviceId>')
|
|
94
|
+
.option('--server <url>', 'Halot server url', defaultServerUrl)
|
|
95
|
+
.action(service_remove_command_1.runServiceRemoveCommand);
|
|
96
|
+
const verifier = program.command('verifier').description('Verifier workspace');
|
|
97
|
+
verifier.command('init').action(verifier_init_command_1.runVerifierInitCommand);
|
|
98
|
+
verifier
|
|
99
|
+
.command('register')
|
|
100
|
+
.option('--server <url>', 'Halot server url', defaultServerUrl)
|
|
101
|
+
.action(verifier_register_command_1.runVerifierRegisterCommand);
|
|
102
|
+
verifier
|
|
103
|
+
.command('run')
|
|
104
|
+
.option('--server <url>', 'Halot server url', defaultServerUrl)
|
|
105
|
+
.option('--once', 'Process a single assignment', false)
|
|
106
|
+
.option('--interval <ms>', 'Polling interval in milliseconds', '3000')
|
|
107
|
+
.action(verifier_run_command_1.runVerifierRunCommand);
|
|
108
|
+
verifier
|
|
109
|
+
.command('stats')
|
|
110
|
+
.option('--server <url>', 'Halot server url', defaultServerUrl)
|
|
111
|
+
.action(verifier_stats_command_1.runVerifierStatsCommand);
|
|
112
|
+
verifier
|
|
113
|
+
.command('unstake')
|
|
114
|
+
.option('--claim', 'Withdraw after cooldown', false)
|
|
115
|
+
.action(verifier_unstake_command_1.runVerifierUnstakeCommand);
|
|
116
|
+
const job = program.command('job').description('Job lifecycle');
|
|
117
|
+
job
|
|
118
|
+
.command('create')
|
|
119
|
+
.requiredOption('--service <id>', 'Service id')
|
|
120
|
+
.requiredOption('--input <json>', 'Input JSON')
|
|
121
|
+
.option('--network <id>', 'Preferred settlement network')
|
|
122
|
+
.option('--server <url>', 'Halot server url', defaultServerUrl)
|
|
123
|
+
.action(job_create_command_1.runJobCreateCommand);
|
|
124
|
+
job
|
|
125
|
+
.command('watch <jobId>')
|
|
126
|
+
.option('--server <url>', 'Halot server url', defaultServerUrl)
|
|
127
|
+
.option('--interval <ms>', 'Polling interval in milliseconds', '3000')
|
|
128
|
+
.action(job_watch_command_1.runJobWatchCommand);
|
|
129
|
+
job
|
|
130
|
+
.command('result <jobId>')
|
|
131
|
+
.option('--server <url>', 'Halot server url', defaultServerUrl)
|
|
132
|
+
.action(job_result_command_1.runJobResultCommand);
|
|
133
|
+
program.parseAsync().catch((error) => {
|
|
134
|
+
console.error(error instanceof Error ? error.message : error);
|
|
135
|
+
process.exitCode = 1;
|
|
136
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSignedActorHeaders = createSignedActorHeaders;
|
|
4
|
+
const sdk_1 = require("@halot/sdk");
|
|
5
|
+
async function createSignedActorHeaders(wallet, actorId, role, method, path) {
|
|
6
|
+
return (0, sdk_1.createActorAuthHeaders)(wallet, {
|
|
7
|
+
actorId,
|
|
8
|
+
role,
|
|
9
|
+
method,
|
|
10
|
+
path,
|
|
11
|
+
timestamp: (0, sdk_1.nowIso)(),
|
|
12
|
+
});
|
|
13
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.loadCliEnv = loadCliEnv;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
let cachedEnv = null;
|
|
10
|
+
function loadCliEnv() {
|
|
11
|
+
if (cachedEnv) {
|
|
12
|
+
return cachedEnv;
|
|
13
|
+
}
|
|
14
|
+
hydrateEnvFile(node_path_1.default.join(process.cwd(), '.env'));
|
|
15
|
+
const mode = (readStringEnv('HALOT_NETWORK_MODE') || 'testnet');
|
|
16
|
+
const isTestnet = mode === 'testnet';
|
|
17
|
+
const suffix = isTestnet ? '_TEST' : '_MAIN';
|
|
18
|
+
cachedEnv = {
|
|
19
|
+
networkMode: mode,
|
|
20
|
+
serverUrl: readStringEnv('HALOT_SERVER_URL')?.replace(/\/+$/u, ''),
|
|
21
|
+
spaceIdIdentifier: readStringEnv('HALOT_SPACE_ID_IDENTIFIER'),
|
|
22
|
+
spaceIdControllerAddress: readAddressEnv(`HALOT_SPACE_ID_CONTROLLER_ADDRESS${suffix}`) || readAddressEnv('HALOT_SPACE_ID_CONTROLLER_ADDRESS'),
|
|
23
|
+
spaceIdResolverAddress: readAddressEnv(`HALOT_SPACE_ID_RESOLVER_ADDRESS${suffix}`) || readAddressEnv('HALOT_SPACE_ID_RESOLVER_ADDRESS'),
|
|
24
|
+
spaceIdSimulateAccount: readAddressEnv('HALOT_SPACE_ID_SIMULATE_ACCOUNT'),
|
|
25
|
+
spaceIdSimulateValue: readStringEnv('HALOT_SPACE_ID_SIMULATE_VALUE'),
|
|
26
|
+
spaceIdGraphUrl: readStringEnv('HALOT_SPACE_ID_GRAPH_URL'),
|
|
27
|
+
spaceIdVerifiedTldHubAddress: readAddressEnv(`HALOT_SPACE_ID_VERIFIED_TLD_HUB_ADDRESS${suffix}`) || readAddressEnv('HALOT_SPACE_ID_VERIFIED_TLD_HUB_ADDRESS'),
|
|
28
|
+
spaceIdVerifiedTldHubRpcUrl: readStringEnv(`HALOT_SPACE_ID_VERIFIED_TLD_HUB_RPC_URL${suffix}`) || readStringEnv('HALOT_SPACE_ID_VERIFIED_TLD_HUB_RPC_URL'),
|
|
29
|
+
zeroGStorageGateway: readStringEnv(`HALOT_ZERO_G_STORAGE_GATEWAY${suffix}`)?.replace(/\/+$/u, '') || readStringEnv('HALOT_ZERO_G_STORAGE_GATEWAY')?.replace(/\/+$/u, ''),
|
|
30
|
+
agentIdRegistryAddress: readAddressEnv(`HALOT_AGENT_ID_REGISTRY_ADDRESS${suffix}`) || readAddressEnv('HALOT_AGENT_ID_REGISTRY_ADDRESS'),
|
|
31
|
+
zeroGVerifierRegistryAddress: readAddressEnv(`HALOT_ZERO_G_VERIFIER_REGISTRY_ADDRESS${suffix}`) || readAddressEnv('HALOT_ZERO_G_VERIFIER_REGISTRY_ADDRESS'),
|
|
32
|
+
defaultStellarRpcUrl: readStringEnv(`HALOT_DEFAULT_STELLAR_RPC_URL${suffix}`) || readStringEnv('HALOT_DEFAULT_STELLAR_RPC_URL'),
|
|
33
|
+
defaultStellarNetworkPassphrase: readStringEnv(`HALOT_DEFAULT_STELLAR_NETWORK_PASSPHRASE${suffix}`) || readStringEnv('HALOT_DEFAULT_STELLAR_NETWORK_PASSPHRASE'),
|
|
34
|
+
};
|
|
35
|
+
return cachedEnv;
|
|
36
|
+
}
|
|
37
|
+
function hydrateEnvFile(filePath) {
|
|
38
|
+
if (!node_fs_1.default.existsSync(filePath)) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const content = node_fs_1.default.readFileSync(filePath, 'utf8');
|
|
42
|
+
for (const rawLine of content.split(/\r?\n/u)) {
|
|
43
|
+
const line = rawLine.trim();
|
|
44
|
+
if (!line || line.startsWith('#')) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const separatorIndex = line.indexOf('=');
|
|
48
|
+
if (separatorIndex <= 0) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const key = line.slice(0, separatorIndex).trim();
|
|
52
|
+
const rawValue = line.slice(separatorIndex + 1).trim();
|
|
53
|
+
if (!key || process.env[key] !== undefined) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const value = stripWrappingQuotes(rawValue);
|
|
57
|
+
process.env[key] = value;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function stripWrappingQuotes(value) {
|
|
61
|
+
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith('\'') && value.endsWith('\''))) {
|
|
62
|
+
return value.slice(1, -1);
|
|
63
|
+
}
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
function readStringEnv(key) {
|
|
67
|
+
const value = process.env[key]?.trim();
|
|
68
|
+
return value ? value : undefined;
|
|
69
|
+
}
|
|
70
|
+
function readAddressEnv(key) {
|
|
71
|
+
const value = readStringEnv(key);
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
function readNumberEnv(key) {
|
|
75
|
+
const value = readStringEnv(key);
|
|
76
|
+
return value ? Number(value) : undefined;
|
|
77
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ApiClient = void 0;
|
|
4
|
+
class ApiClient {
|
|
5
|
+
baseUrl;
|
|
6
|
+
constructor(baseUrl) {
|
|
7
|
+
this.baseUrl = baseUrl;
|
|
8
|
+
}
|
|
9
|
+
async get(path, headers) {
|
|
10
|
+
const response = await fetch(`${this.baseUrl}${path}`, {
|
|
11
|
+
method: 'GET',
|
|
12
|
+
headers,
|
|
13
|
+
});
|
|
14
|
+
return this.handleResponse(response);
|
|
15
|
+
}
|
|
16
|
+
async post(path, body, headers) {
|
|
17
|
+
const response = await fetch(`${this.baseUrl}${path}`, {
|
|
18
|
+
method: 'POST',
|
|
19
|
+
headers: {
|
|
20
|
+
'content-type': 'application/json',
|
|
21
|
+
...(headers ?? {}),
|
|
22
|
+
},
|
|
23
|
+
body: JSON.stringify(body),
|
|
24
|
+
});
|
|
25
|
+
return this.handleResponse(response);
|
|
26
|
+
}
|
|
27
|
+
async put(path, body, headers) {
|
|
28
|
+
const response = await fetch(`${this.baseUrl}${path}`, {
|
|
29
|
+
method: 'PUT',
|
|
30
|
+
headers: {
|
|
31
|
+
'content-type': 'application/json',
|
|
32
|
+
...(headers ?? {}),
|
|
33
|
+
},
|
|
34
|
+
body: JSON.stringify(body),
|
|
35
|
+
});
|
|
36
|
+
return this.handleResponse(response);
|
|
37
|
+
}
|
|
38
|
+
async delete(path, headers) {
|
|
39
|
+
const response = await fetch(`${this.baseUrl}${path}`, {
|
|
40
|
+
method: 'DELETE',
|
|
41
|
+
headers,
|
|
42
|
+
});
|
|
43
|
+
if (!response.ok) {
|
|
44
|
+
const data = await response.json().catch(() => ({}));
|
|
45
|
+
throw new Error(typeof data?.error === 'string' ? data.error : `Request failed with status ${response.status}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async postRaw(path, body, headers) {
|
|
49
|
+
return fetch(`${this.baseUrl}${path}`, {
|
|
50
|
+
method: 'POST',
|
|
51
|
+
headers: {
|
|
52
|
+
'content-type': 'application/json',
|
|
53
|
+
...(headers ?? {}),
|
|
54
|
+
},
|
|
55
|
+
body: JSON.stringify(body),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
async handleResponse(response) {
|
|
59
|
+
const data = await response.json().catch(() => ({}));
|
|
60
|
+
if (!response.ok) {
|
|
61
|
+
throw new Error(typeof data?.error === 'string' ? data.error : `Request failed with status ${response.status}`);
|
|
62
|
+
}
|
|
63
|
+
return data;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
exports.ApiClient = ApiClient;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.connectEventStream = connectEventStream;
|
|
4
|
+
async function* connectEventStream(url, headers, lastEventId) {
|
|
5
|
+
const response = await fetch(url, {
|
|
6
|
+
method: 'GET',
|
|
7
|
+
headers: {
|
|
8
|
+
...(headers ?? {}),
|
|
9
|
+
...(lastEventId ? { 'Last-Event-ID': lastEventId } : {}),
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
if (!response.ok) {
|
|
13
|
+
const body = await response.text();
|
|
14
|
+
throw new Error(`Event stream request failed (${response.status}): ${body}`);
|
|
15
|
+
}
|
|
16
|
+
if (!response.body) {
|
|
17
|
+
throw new Error('Event stream response did not include a body');
|
|
18
|
+
}
|
|
19
|
+
const reader = response.body.getReader();
|
|
20
|
+
const decoder = new TextDecoder();
|
|
21
|
+
let buffer = '';
|
|
22
|
+
while (true) {
|
|
23
|
+
const { value, done } = await reader.read();
|
|
24
|
+
if (done) {
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
buffer += decoder.decode(value, { stream: true });
|
|
28
|
+
buffer = buffer.replace(/\r\n/g, '\n');
|
|
29
|
+
while (true) {
|
|
30
|
+
const boundary = buffer.indexOf('\n\n');
|
|
31
|
+
if (boundary === -1) {
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
const rawEvent = buffer.slice(0, boundary);
|
|
35
|
+
buffer = buffer.slice(boundary + 2);
|
|
36
|
+
const parsed = parseServerSentEvent(rawEvent);
|
|
37
|
+
if (parsed) {
|
|
38
|
+
yield parsed;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function parseServerSentEvent(rawEvent) {
|
|
44
|
+
let id;
|
|
45
|
+
let event = 'message';
|
|
46
|
+
const dataLines = [];
|
|
47
|
+
for (const line of rawEvent.split('\n')) {
|
|
48
|
+
if (!line || line.startsWith(':')) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const separator = line.indexOf(':');
|
|
52
|
+
const field = separator === -1 ? line : line.slice(0, separator);
|
|
53
|
+
let value = separator === -1 ? '' : line.slice(separator + 1);
|
|
54
|
+
if (value.startsWith(' ')) {
|
|
55
|
+
value = value.slice(1);
|
|
56
|
+
}
|
|
57
|
+
if (field === 'id') {
|
|
58
|
+
id = value || undefined;
|
|
59
|
+
}
|
|
60
|
+
else if (field === 'event') {
|
|
61
|
+
event = value || 'message';
|
|
62
|
+
}
|
|
63
|
+
else if (field === 'data') {
|
|
64
|
+
dataLines.push(value);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (dataLines.length === 0) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
id,
|
|
72
|
+
event,
|
|
73
|
+
data: dataLines.join('\n'),
|
|
74
|
+
};
|
|
75
|
+
}
|