agentvault 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/.dfx/local/network-id +4 -0
- package/.next/trace +2 -0
- package/.vercel/README.txt +11 -0
- package/.vercel/project.json +1 -0
- package/AGENTS.md +43 -0
- package/CHANGELOG.md +196 -0
- package/LICENSE +21 -0
- package/PLAN_VAULT_INTEGRATION.md +318 -0
- package/README.md +253 -0
- package/backups/agentvault-backup-test-agent-2026-02-12T17-54-28-967Z.json +28 -0
- package/backups/agentvault-backup-test-agent-2026-02-12T17-54-29-032Z.backup +1 -0
- package/backups/agentvault-backup-test-agent-2026-02-12T17-57-42-373Z.json +28 -0
- package/backups/agentvault-backup-test-agent-2026-02-12T17-57-42-428Z.backup +1 -0
- package/backups/agentvault-backup-test-agent-2026-02-12T18-52-25-132Z.json +28 -0
- package/backups/agentvault-backup-test-agent-2026-02-12T18-52-25-247Z.backup +1 -0
- package/backups/agentvault-backup-test-agent-2026-02-12T18-54-09-216Z.json +28 -0
- package/backups/agentvault-backup-test-agent-2026-02-12T18-54-09-283Z.backup +1 -0
- package/backups/agentvault-backup-test-agent-2026-02-12T22-18-22-772Z.backup +1 -0
- package/backups/agentvault-backup-test-agent-2026-02-12T22-18-22-793Z.json +28 -0
- package/backups/test-backup.json +28 -0
- package/dist/cli/commands/approve.d.ts +4 -0
- package/dist/cli/commands/approve.js +232 -0
- package/dist/cli/commands/archive.d.ts +4 -0
- package/dist/cli/commands/archive.js +192 -0
- package/dist/cli/commands/backup.d.ts +4 -0
- package/dist/cli/commands/backup.js +164 -0
- package/dist/cli/commands/cloud-backup.d.ts +4 -0
- package/dist/cli/commands/cloud-backup.js +221 -0
- package/dist/cli/commands/cycles.d.ts +8 -0
- package/dist/cli/commands/cycles.js +83 -0
- package/dist/cli/commands/decrypt.d.ts +16 -0
- package/dist/cli/commands/decrypt.js +101 -0
- package/dist/cli/commands/deploy.d.ts +32 -0
- package/dist/cli/commands/deploy.js +208 -0
- package/dist/cli/commands/exec.d.ts +26 -0
- package/dist/cli/commands/exec.js +109 -0
- package/dist/cli/commands/fetch.d.ts +23 -0
- package/dist/cli/commands/fetch.js +164 -0
- package/dist/cli/commands/health.d.ts +8 -0
- package/dist/cli/commands/health.js +72 -0
- package/dist/cli/commands/identity.d.ts +8 -0
- package/dist/cli/commands/identity.js +140 -0
- package/dist/cli/commands/inference.d.ts +4 -0
- package/dist/cli/commands/inference.js +225 -0
- package/dist/cli/commands/info.d.ts +8 -0
- package/dist/cli/commands/info.js +59 -0
- package/dist/cli/commands/init.d.ts +19 -0
- package/dist/cli/commands/init.js +135 -0
- package/dist/cli/commands/instrument.d.ts +8 -0
- package/dist/cli/commands/instrument.js +35 -0
- package/dist/cli/commands/list.d.ts +36 -0
- package/dist/cli/commands/list.js +173 -0
- package/dist/cli/commands/logs.d.ts +8 -0
- package/dist/cli/commands/logs.js +96 -0
- package/dist/cli/commands/monitor.d.ts +8 -0
- package/dist/cli/commands/monitor.js +84 -0
- package/dist/cli/commands/network.d.ts +14 -0
- package/dist/cli/commands/network.js +258 -0
- package/dist/cli/commands/package.d.ts +36 -0
- package/dist/cli/commands/package.js +188 -0
- package/dist/cli/commands/profile.d.ts +8 -0
- package/dist/cli/commands/profile.js +76 -0
- package/dist/cli/commands/promote.d.ts +8 -0
- package/dist/cli/commands/promote.js +89 -0
- package/dist/cli/commands/rebuild.d.ts +21 -0
- package/dist/cli/commands/rebuild.js +140 -0
- package/dist/cli/commands/rollback.d.ts +8 -0
- package/dist/cli/commands/rollback.js +120 -0
- package/dist/cli/commands/show.d.ts +36 -0
- package/dist/cli/commands/show.js +200 -0
- package/dist/cli/commands/stats.d.ts +8 -0
- package/dist/cli/commands/stats.js +34 -0
- package/dist/cli/commands/status.d.ts +14 -0
- package/dist/cli/commands/status.js +83 -0
- package/dist/cli/commands/test.d.ts +8 -0
- package/dist/cli/commands/test.js +109 -0
- package/dist/cli/commands/tokens.d.ts +8 -0
- package/dist/cli/commands/tokens.js +62 -0
- package/dist/cli/commands/trace.d.ts +8 -0
- package/dist/cli/commands/trace.js +68 -0
- package/dist/cli/commands/wallet-export.d.ts +13 -0
- package/dist/cli/commands/wallet-export.js +140 -0
- package/dist/cli/commands/wallet-history.d.ts +10 -0
- package/dist/cli/commands/wallet-history.js +127 -0
- package/dist/cli/commands/wallet-import.d.ts +10 -0
- package/dist/cli/commands/wallet-import.js +209 -0
- package/dist/cli/commands/wallet-multi-send.d.ts +17 -0
- package/dist/cli/commands/wallet-multi-send.js +195 -0
- package/dist/cli/commands/wallet-process-queue.d.ts +19 -0
- package/dist/cli/commands/wallet-process-queue.js +209 -0
- package/dist/cli/commands/wallet-sign.d.ts +13 -0
- package/dist/cli/commands/wallet-sign.js +207 -0
- package/dist/cli/commands/wallet.d.ts +12 -0
- package/dist/cli/commands/wallet.js +794 -0
- package/dist/cli/index.d.ts +10 -0
- package/dist/cli/index.js +96 -0
- package/dist/vitest.config.d.ts +3 -0
- package/dist/vitest.config.js +14 -0
- package/fixup_1_0_OSS_release.md +136 -0
- package/fixup_REALEASE_PRD.md +136 -0
- package/package.json +79 -0
- package/pnpm-workspace.yaml +5 -0
- package/scripts/dev-dashboard.mjs +84 -0
- package/site/README.md +63 -0
- package/site/docusaurus.config.ts +148 -0
- package/site/package-lock.json +18383 -0
- package/site/package.json +47 -0
- package/site/sidebars.ts +86 -0
- package/site/static/.gitkeep +0 -0
- package/site/static/img/logo.svg +28 -0
- package/site/static/img/og-image.svg +35 -0
- package/src/archival/archive-manager.ts +372 -0
- package/src/archival/arweave-client.ts +289 -0
- package/src/archival/index.ts +8 -0
- package/src/backup/backup.ts +315 -0
- package/src/backup/index.ts +7 -0
- package/src/cloud-storage/cloud-sync.ts +461 -0
- package/src/cloud-storage/index.ts +11 -0
- package/src/cloud-storage/provider-detector.ts +198 -0
- package/src/cloud-storage/types.ts +104 -0
- package/src/debugging/index.ts +6 -0
- package/src/debugging/logs.ts +193 -0
- package/src/debugging/types.ts +100 -0
- package/src/deployment/deployer.ts +274 -0
- package/src/deployment/icpClient.ts +620 -0
- package/src/deployment/index.ts +46 -0
- package/src/deployment/promotion.ts +161 -0
- package/src/deployment/types.ts +111 -0
- package/src/icp/batch.ts +374 -0
- package/src/icp/cycles.ts +50 -0
- package/src/icp/environment.ts +215 -0
- package/src/icp/icpcli.ts +438 -0
- package/src/icp/icwasm.ts +222 -0
- package/src/icp/identity.ts +77 -0
- package/src/icp/index.ts +94 -0
- package/src/icp/optimization.ts +242 -0
- package/src/icp/tokens.ts +36 -0
- package/src/icp/tool-detector.ts +110 -0
- package/src/icp/types.ts +574 -0
- package/src/index.ts +25 -0
- package/src/inference/bittensor-client.ts +304 -0
- package/src/inference/index.ts +8 -0
- package/src/inference/inference-manager.ts +327 -0
- package/src/metrics/index.ts +7 -0
- package/src/metrics/metrics.ts +186 -0
- package/src/monitoring/alerting.ts +190 -0
- package/src/monitoring/health.ts +197 -0
- package/src/monitoring/index.ts +38 -0
- package/src/monitoring/info.ts +114 -0
- package/src/monitoring/types.ts +99 -0
- package/src/network/index.ts +5 -0
- package/src/network/network-config.ts +129 -0
- package/src/packaging/compiler.ts +647 -0
- package/src/packaging/config-persistence.ts +135 -0
- package/src/packaging/config-schemas.ts +156 -0
- package/src/packaging/detector.ts +220 -0
- package/src/packaging/index.ts +90 -0
- package/src/packaging/packager.ts +118 -0
- package/src/packaging/parsers/clawdbot.ts +278 -0
- package/src/packaging/parsers/cline.ts +223 -0
- package/src/packaging/parsers/generic.ts +266 -0
- package/src/packaging/parsers/goose.ts +214 -0
- package/src/packaging/parsers/index.ts +11 -0
- package/src/packaging/serializer.ts +260 -0
- package/src/packaging/types.ts +144 -0
- package/src/packaging/wasmedge-compiler.ts +406 -0
- package/src/security/index.ts +17 -0
- package/src/security/multisig.ts +415 -0
- package/src/security/types.ts +416 -0
- package/src/security/vetkeys.ts +655 -0
- package/src/testing/index.ts +6 -0
- package/src/testing/local-runner.ts +264 -0
- package/src/testing/types.ts +104 -0
- package/src/wallet/cbor-serializer.ts +323 -0
- package/src/wallet/chain-dispatcher.ts +313 -0
- package/src/wallet/cross-chain-aggregator.ts +346 -0
- package/src/wallet/index.ts +76 -0
- package/src/wallet/key-derivation.ts +425 -0
- package/src/wallet/providers/base-provider.ts +154 -0
- package/src/wallet/providers/cketh-provider.ts +434 -0
- package/src/wallet/providers/polkadot-provider.ts +503 -0
- package/src/wallet/providers/solana-provider.ts +490 -0
- package/src/wallet/transaction-queue.ts +284 -0
- package/src/wallet/types.ts +178 -0
- package/src/wallet/vetkeys-adapter.ts +431 -0
- package/src/wallet/wallet-manager.ts +597 -0
- package/src/wallet/wallet-storage.ts +380 -0
- package/vercel.json +8 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloud Storage Types
|
|
3
|
+
*
|
|
4
|
+
* Types for the cloud storage backup feature that lets users
|
|
5
|
+
* archive and restore AgentVault data using consumer cloud
|
|
6
|
+
* storage providers (Google Drive, iCloud, Dropbox, etc.)
|
|
7
|
+
* via their local sync directories — no crypto required.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Supported cloud storage providers detected via local sync directories.
|
|
12
|
+
*/
|
|
13
|
+
export type CloudProvider =
|
|
14
|
+
| 'google-drive'
|
|
15
|
+
| 'icloud-drive'
|
|
16
|
+
| 'dropbox'
|
|
17
|
+
| 'onedrive'
|
|
18
|
+
| 'custom';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A detected cloud provider with its local sync path.
|
|
22
|
+
*/
|
|
23
|
+
export interface DetectedProvider {
|
|
24
|
+
provider: CloudProvider;
|
|
25
|
+
label: string;
|
|
26
|
+
path: string;
|
|
27
|
+
available: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Configuration for cloud backup destination.
|
|
32
|
+
*/
|
|
33
|
+
export interface CloudBackupConfig {
|
|
34
|
+
provider: CloudProvider;
|
|
35
|
+
basePath: string;
|
|
36
|
+
subdirectory: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* What to include in a cloud backup archive.
|
|
41
|
+
*/
|
|
42
|
+
export interface CloudArchiveOptions {
|
|
43
|
+
agentName?: string;
|
|
44
|
+
includeConfigs: boolean;
|
|
45
|
+
includeWallets: boolean;
|
|
46
|
+
includeBackups: boolean;
|
|
47
|
+
includeNetworks: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Metadata written alongside the archive for identification and integrity.
|
|
52
|
+
*/
|
|
53
|
+
export interface CloudArchiveManifest {
|
|
54
|
+
version: string;
|
|
55
|
+
createdAt: string;
|
|
56
|
+
platform: string;
|
|
57
|
+
hostname: string;
|
|
58
|
+
agentVaultVersion: string;
|
|
59
|
+
agentName?: string;
|
|
60
|
+
components: string[];
|
|
61
|
+
files: CloudArchiveFileEntry[];
|
|
62
|
+
checksum: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Entry for a single file within the archive manifest.
|
|
67
|
+
*/
|
|
68
|
+
export interface CloudArchiveFileEntry {
|
|
69
|
+
relativePath: string;
|
|
70
|
+
sizeBytes: number;
|
|
71
|
+
checksum: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Result of an archive operation.
|
|
76
|
+
*/
|
|
77
|
+
export interface CloudArchiveResult {
|
|
78
|
+
success: boolean;
|
|
79
|
+
archivePath?: string;
|
|
80
|
+
manifestPath?: string;
|
|
81
|
+
fileCount?: number;
|
|
82
|
+
totalBytes?: number;
|
|
83
|
+
error?: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Result of a restore operation.
|
|
88
|
+
*/
|
|
89
|
+
export interface CloudRestoreResult {
|
|
90
|
+
success: boolean;
|
|
91
|
+
restoredFiles?: number;
|
|
92
|
+
components?: string[];
|
|
93
|
+
warnings: string[];
|
|
94
|
+
error?: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* A discovered archive available for restore.
|
|
99
|
+
*/
|
|
100
|
+
export interface DiscoveredArchive {
|
|
101
|
+
manifestPath: string;
|
|
102
|
+
archivePath: string;
|
|
103
|
+
manifest: CloudArchiveManifest;
|
|
104
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log aggregation for canister debugging
|
|
3
|
+
*
|
|
4
|
+
* Collects, stores, and queries logs from canisters
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import os from 'node:os';
|
|
10
|
+
import type { LogEntry, LogLevel } from './types.js';
|
|
11
|
+
|
|
12
|
+
const AGENTVAULT_DIR = path.join(os.homedir(), '.agentvault');
|
|
13
|
+
const LOGS_DIR = path.join(AGENTVAULT_DIR, 'logs');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Ensure logs directory exists
|
|
17
|
+
*/
|
|
18
|
+
function ensureLogsDir(): void {
|
|
19
|
+
if (!fs.existsSync(AGENTVAULT_DIR)) {
|
|
20
|
+
fs.mkdirSync(AGENTVAULT_DIR, { recursive: true });
|
|
21
|
+
}
|
|
22
|
+
if (!fs.existsSync(LOGS_DIR)) {
|
|
23
|
+
fs.mkdirSync(LOGS_DIR, { recursive: true });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get logs directory for a specific canister
|
|
29
|
+
*/
|
|
30
|
+
function getCanisterLogsDir(canisterId: string): string {
|
|
31
|
+
ensureLogsDir();
|
|
32
|
+
const canisterDir = path.join(LOGS_DIR, canisterId);
|
|
33
|
+
if (!fs.existsSync(canisterDir)) {
|
|
34
|
+
fs.mkdirSync(canisterDir, { recursive: true });
|
|
35
|
+
}
|
|
36
|
+
return canisterDir;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get log file path for a canister and date
|
|
41
|
+
*/
|
|
42
|
+
function getLogFilePath(canisterId: string, date?: Date): string {
|
|
43
|
+
const logsDir = getCanisterLogsDir(canisterId);
|
|
44
|
+
const logDate = date || new Date();
|
|
45
|
+
const dateStr = logDate.toISOString().split('T')[0];
|
|
46
|
+
return path.join(logsDir, `${dateStr}.jsonl`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Parse log line from canister output
|
|
51
|
+
*/
|
|
52
|
+
function parseLogLine(line: string, canisterId: string): LogEntry | null {
|
|
53
|
+
try {
|
|
54
|
+
const parsed = JSON.parse(line) as Record<string, unknown>;
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
timestamp: new Date(parsed.timestamp as string),
|
|
58
|
+
level: (parsed.level as LogLevel) || 'info',
|
|
59
|
+
message: (parsed.message as string) || '',
|
|
60
|
+
canisterId,
|
|
61
|
+
method: parsed.method as string | undefined,
|
|
62
|
+
context: parsed.context as Record<string, unknown> | undefined,
|
|
63
|
+
};
|
|
64
|
+
} catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Collect logs from canister output
|
|
71
|
+
*/
|
|
72
|
+
export async function collectLogs(canisterId: string, output: string): Promise<LogEntry[]> {
|
|
73
|
+
const logs: LogEntry[] = [];
|
|
74
|
+
const lines = output.split('\n');
|
|
75
|
+
|
|
76
|
+
for (const line of lines) {
|
|
77
|
+
if (line.trim()) {
|
|
78
|
+
const logEntry = parseLogLine(line, canisterId);
|
|
79
|
+
if (logEntry) {
|
|
80
|
+
logs.push(logEntry);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return logs;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Store log entries to disk
|
|
90
|
+
*/
|
|
91
|
+
export async function storeLogs(canisterId: string, logs: LogEntry[]): Promise<void> {
|
|
92
|
+
const logFilePath = getLogFilePath(canisterId);
|
|
93
|
+
const lines = logs.map((log) => JSON.stringify(log)).join('\n');
|
|
94
|
+
|
|
95
|
+
fs.appendFileSync(logFilePath, lines + '\n', 'utf8');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Retrieve logs for a canister with optional filtering
|
|
100
|
+
*/
|
|
101
|
+
export async function getLogs(
|
|
102
|
+
canisterId: string,
|
|
103
|
+
options: {
|
|
104
|
+
since?: Date;
|
|
105
|
+
level?: LogLevel;
|
|
106
|
+
pattern?: string;
|
|
107
|
+
limit?: number;
|
|
108
|
+
} = {},
|
|
109
|
+
): Promise<LogEntry[]> {
|
|
110
|
+
const logsDir = getCanisterLogsDir(canisterId);
|
|
111
|
+
const files = fs.readdirSync(logsDir)
|
|
112
|
+
.filter((f) => f.endsWith('.jsonl'))
|
|
113
|
+
.sort()
|
|
114
|
+
.reverse();
|
|
115
|
+
|
|
116
|
+
const allLogs: LogEntry[] = [];
|
|
117
|
+
|
|
118
|
+
for (const file of files) {
|
|
119
|
+
const filePath = path.join(logsDir, file);
|
|
120
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
121
|
+
const lines = content.split('\n');
|
|
122
|
+
|
|
123
|
+
for (const line of lines) {
|
|
124
|
+
if (line.trim()) {
|
|
125
|
+
const log = parseLogLine(line, canisterId);
|
|
126
|
+
if (log) {
|
|
127
|
+
allLogs.push(log);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (options.since) {
|
|
133
|
+
const fileDate = new Date(file.replace('.jsonl', ''));
|
|
134
|
+
if (fileDate < options.since) {
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const filteredLogs = allLogs.filter((log) => {
|
|
141
|
+
if (options.since && log.timestamp < options.since) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
if (options.level && log.level !== options.level) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
if (options.pattern && !log.message.includes(options.pattern)) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
return true;
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
if (options.limit) {
|
|
154
|
+
return filteredLogs.slice(-options.limit);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return filteredLogs.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Export logs to a file
|
|
162
|
+
*/
|
|
163
|
+
export async function exportLogs(
|
|
164
|
+
canisterId: string,
|
|
165
|
+
outputPath: string,
|
|
166
|
+
format: 'json' | 'csv' = 'json',
|
|
167
|
+
): Promise<void> {
|
|
168
|
+
const logs = await getLogs(canisterId);
|
|
169
|
+
|
|
170
|
+
if (format === 'json') {
|
|
171
|
+
fs.writeFileSync(outputPath, JSON.stringify(logs, null, 2), 'utf8');
|
|
172
|
+
} else if (format === 'csv') {
|
|
173
|
+
const headers = 'timestamp,level,message,canisterId,method,context\n';
|
|
174
|
+
const rows = logs.map((log) => {
|
|
175
|
+
const context = log.context ? JSON.stringify(log.context).replace(/"/g, '""') : '';
|
|
176
|
+
return `"${log.timestamp.toISOString()}","${log.level}","${log.message.replace(/"/g, '""')}","${log.canisterId}","${log.method || ''}","${context}"`;
|
|
177
|
+
}).join('\n');
|
|
178
|
+
|
|
179
|
+
fs.writeFileSync(outputPath, headers + rows, 'utf8');
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Clear logs for a canister
|
|
185
|
+
*/
|
|
186
|
+
export async function clearLogs(canisterId: string): Promise<void> {
|
|
187
|
+
const logsDir = getCanisterLogsDir(canisterId);
|
|
188
|
+
const files = fs.readdirSync(logsDir);
|
|
189
|
+
|
|
190
|
+
for (const file of files) {
|
|
191
|
+
fs.unlinkSync(path.join(logsDir, file));
|
|
192
|
+
}
|
|
193
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for debugging and instrumentation functionality
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/** Log level */
|
|
6
|
+
export type LogLevel = 'info' | 'warning' | 'error' | 'debug';
|
|
7
|
+
|
|
8
|
+
/** Log entry from canister or system */
|
|
9
|
+
export interface LogEntry {
|
|
10
|
+
/** Log timestamp */
|
|
11
|
+
timestamp: Date;
|
|
12
|
+
/** Log level */
|
|
13
|
+
level: LogLevel;
|
|
14
|
+
/** Log message */
|
|
15
|
+
message: string;
|
|
16
|
+
/** Source canister ID */
|
|
17
|
+
canisterId: string;
|
|
18
|
+
/** Method that generated the log (if applicable) */
|
|
19
|
+
method?: string;
|
|
20
|
+
/** Additional context */
|
|
21
|
+
context?: Record<string, unknown>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Trace filter options */
|
|
25
|
+
export interface TraceFilter {
|
|
26
|
+
/** Filter by method name */
|
|
27
|
+
method?: string;
|
|
28
|
+
/** Minimum duration in milliseconds */
|
|
29
|
+
minDuration?: number;
|
|
30
|
+
/** Maximum depth of the call tree */
|
|
31
|
+
maxDepth?: number;
|
|
32
|
+
/** Filter by caller principal */
|
|
33
|
+
caller?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Method statistics for profiling */
|
|
37
|
+
export interface MethodStats {
|
|
38
|
+
/** Number of calls */
|
|
39
|
+
count: number;
|
|
40
|
+
/** Total duration in milliseconds */
|
|
41
|
+
totalDuration: number;
|
|
42
|
+
/** Average duration in milliseconds */
|
|
43
|
+
avgDuration: number;
|
|
44
|
+
/** Maximum duration in milliseconds */
|
|
45
|
+
maxDuration: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Result of profiling a canister */
|
|
49
|
+
export interface ProfileResult {
|
|
50
|
+
/** Number of samples collected */
|
|
51
|
+
samples: number;
|
|
52
|
+
/** Duration of profiling in seconds */
|
|
53
|
+
duration: number;
|
|
54
|
+
/** Statistics per method */
|
|
55
|
+
methodStats: Map<string, MethodStats>;
|
|
56
|
+
/** Memory snapshots taken during profiling */
|
|
57
|
+
memorySnapshots: number[];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Instrument result */
|
|
61
|
+
export interface InstrumentResult {
|
|
62
|
+
/** Whether instrumentation succeeded */
|
|
63
|
+
success: boolean;
|
|
64
|
+
/** Path to instrumented WASM */
|
|
65
|
+
outputPath: string;
|
|
66
|
+
/** Any warnings from instrumentation */
|
|
67
|
+
warnings: string[];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Trace export format */
|
|
71
|
+
export type TraceExportFormat = 'json' | 'flamegraph' | 'text';
|
|
72
|
+
|
|
73
|
+
/** Dashboard metric types */
|
|
74
|
+
export interface DashboardMetrics {
|
|
75
|
+
/** Current cycles balance */
|
|
76
|
+
cycles: bigint;
|
|
77
|
+
/** Memory usage in bytes */
|
|
78
|
+
memory: bigint;
|
|
79
|
+
/** Requests per second */
|
|
80
|
+
requestRate: number;
|
|
81
|
+
/** Error rate */
|
|
82
|
+
errorRate: number;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Alert severity levels */
|
|
86
|
+
export type AlertSeverity = 'info' | 'warning' | 'error' | 'critical';
|
|
87
|
+
|
|
88
|
+
/** Alert entry */
|
|
89
|
+
export interface AlertEntry {
|
|
90
|
+
/** Alert timestamp */
|
|
91
|
+
timestamp: Date;
|
|
92
|
+
/** Alert severity */
|
|
93
|
+
severity: AlertSeverity;
|
|
94
|
+
/** Alert message */
|
|
95
|
+
message: string;
|
|
96
|
+
/** Related canister ID */
|
|
97
|
+
canisterId: string;
|
|
98
|
+
/** Alert type/category */
|
|
99
|
+
type: string;
|
|
100
|
+
}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Deployer
|
|
3
|
+
*
|
|
4
|
+
* Main orchestrator for the ICP canister deployment pipeline.
|
|
5
|
+
* Coordinates validation, client setup, and deployment operations.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import * as fs from 'node:fs';
|
|
9
|
+
import * as path from 'node:path';
|
|
10
|
+
import type {
|
|
11
|
+
DeployOptions,
|
|
12
|
+
DeployResult,
|
|
13
|
+
DeploymentError,
|
|
14
|
+
CanisterInfo,
|
|
15
|
+
NetworkType,
|
|
16
|
+
DeploymentStatus,
|
|
17
|
+
} from './types.js';
|
|
18
|
+
import { createICPClient } from './icpClient.js';
|
|
19
|
+
import { detectToolchain } from '../icp/tool-detector.js';
|
|
20
|
+
import * as icpcli from '../icp/icpcli.js';
|
|
21
|
+
import { getEnvironment } from '../icp/environment.js';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Extract agent name from WASM file path
|
|
25
|
+
*/
|
|
26
|
+
function extractAgentName(wasmPath: string): string {
|
|
27
|
+
const basename = path.basename(wasmPath);
|
|
28
|
+
// Remove .wasm extension
|
|
29
|
+
return basename.replace(/\.wasm$/, '');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Validate deployment options
|
|
34
|
+
*/
|
|
35
|
+
export function validateDeployOptions(options: DeployOptions): {
|
|
36
|
+
valid: boolean;
|
|
37
|
+
errors: DeploymentError[];
|
|
38
|
+
warnings: string[];
|
|
39
|
+
} {
|
|
40
|
+
const errors: DeploymentError[] = [];
|
|
41
|
+
const warnings: string[] = [];
|
|
42
|
+
|
|
43
|
+
// Validate WASM path using client
|
|
44
|
+
const client = createICPClient({ network: options.network });
|
|
45
|
+
const wasmValidation = client.validateWasmPath(options.wasmPath);
|
|
46
|
+
if (!wasmValidation.valid) {
|
|
47
|
+
errors.push({
|
|
48
|
+
code: 'INVALID_WASM',
|
|
49
|
+
message: wasmValidation.error!,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Validate network - requires standard network name or an explicit environment config
|
|
54
|
+
const knownNetworks = ['local', 'ic', 'mainnet', 'dev', 'staging', 'production'];
|
|
55
|
+
if (!knownNetworks.includes(options.network)) {
|
|
56
|
+
errors.push({
|
|
57
|
+
code: 'INVALID_NETWORK',
|
|
58
|
+
message: `Network '${options.network}' is not a standard name. Ensure it is defined in your icp.yaml.`,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Warn about mainnet deployment
|
|
63
|
+
if (options.network === 'ic' && !options.skipConfirmation) {
|
|
64
|
+
warnings.push(
|
|
65
|
+
'Deploying to IC mainnet will consume cycles. Ensure you have sufficient balance.'
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Warn about upgrade without canister ID check
|
|
70
|
+
if (options.canisterId) {
|
|
71
|
+
warnings.push(`Upgrading existing canister: ${options.canisterId}`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
valid: errors.length === 0,
|
|
76
|
+
errors,
|
|
77
|
+
warnings,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Get deployment preview/summary
|
|
83
|
+
*
|
|
84
|
+
* Useful for dry-run functionality
|
|
85
|
+
*/
|
|
86
|
+
export function getDeploySummary(options: DeployOptions): {
|
|
87
|
+
agentName: string;
|
|
88
|
+
wasmPath: string;
|
|
89
|
+
wasmHash: string;
|
|
90
|
+
wasmSize: number;
|
|
91
|
+
network: NetworkType;
|
|
92
|
+
isUpgrade: boolean;
|
|
93
|
+
canisterId?: string;
|
|
94
|
+
validation: ReturnType<typeof validateDeployOptions>;
|
|
95
|
+
} {
|
|
96
|
+
const validation = validateDeployOptions(options);
|
|
97
|
+
|
|
98
|
+
// Calculate WASM hash if file exists
|
|
99
|
+
let wasmHash = '';
|
|
100
|
+
let wasmSize = 0;
|
|
101
|
+
if (validation.valid) {
|
|
102
|
+
try {
|
|
103
|
+
const client = createICPClient({ network: options.network });
|
|
104
|
+
wasmHash = client.calculateWasmHash(options.wasmPath);
|
|
105
|
+
wasmSize = fs.statSync(options.wasmPath).size;
|
|
106
|
+
} catch {
|
|
107
|
+
// File doesn't exist or can't be read
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
agentName: extractAgentName(options.wasmPath),
|
|
113
|
+
wasmPath: options.wasmPath,
|
|
114
|
+
wasmHash,
|
|
115
|
+
wasmSize,
|
|
116
|
+
network: options.network,
|
|
117
|
+
isUpgrade: !!options.canisterId,
|
|
118
|
+
canisterId: options.canisterId,
|
|
119
|
+
validation,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Deploy an agent to ICP
|
|
125
|
+
*
|
|
126
|
+
* This is the main entry point for the deployment pipeline.
|
|
127
|
+
* Uses auto-detection to choose between icp-cli and the @dfinity/agent SDK.
|
|
128
|
+
*
|
|
129
|
+
* Priority: icp-cli > @dfinity/agent SDK (with dfx fallback)
|
|
130
|
+
*
|
|
131
|
+
* @param options - Deployment options
|
|
132
|
+
* @returns Deployment result with canister info
|
|
133
|
+
*/
|
|
134
|
+
export async function deployAgent(options: DeployOptions): Promise<DeployResult> {
|
|
135
|
+
// Validate options
|
|
136
|
+
const validation = validateDeployOptions(options);
|
|
137
|
+
if (!validation.valid) {
|
|
138
|
+
const errorMessages = validation.errors.map((e) => e.message).join('; ');
|
|
139
|
+
throw new Error(`Deployment validation failed: ${errorMessages}`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Detect available toolchain
|
|
143
|
+
const toolchain = await detectToolchain();
|
|
144
|
+
|
|
145
|
+
// Determine which tool to use
|
|
146
|
+
if (toolchain.icp.available && (options.environment || options.identity)) {
|
|
147
|
+
// Use icp-cli when explicitly requesting environments or identity features
|
|
148
|
+
return deployWithIcpCli(options, validation.warnings);
|
|
149
|
+
} else if (toolchain.preferredDeployTool === 'icp') {
|
|
150
|
+
// Prefer icp-cli when available
|
|
151
|
+
return deployWithIcpCli(options, validation.warnings);
|
|
152
|
+
} else {
|
|
153
|
+
// Fall back to @dfinity/agent SDK
|
|
154
|
+
return deployWithSdk(options, validation.warnings);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Deploy using icp-cli tool.
|
|
160
|
+
*/
|
|
161
|
+
async function deployWithIcpCli(
|
|
162
|
+
options: DeployOptions,
|
|
163
|
+
warnings: string[],
|
|
164
|
+
): Promise<DeployResult> {
|
|
165
|
+
// Resolve environment from options or network
|
|
166
|
+
const envName = options.environment ?? options.network;
|
|
167
|
+
const envConfig = getEnvironment(envName);
|
|
168
|
+
const identity = options.identity ?? envConfig.identity;
|
|
169
|
+
|
|
170
|
+
// Determine deploy mode
|
|
171
|
+
const mode = options.mode ?? (options.canisterId ? 'upgrade' : 'auto');
|
|
172
|
+
|
|
173
|
+
const result = await icpcli.deploy({
|
|
174
|
+
environment: envName,
|
|
175
|
+
identity,
|
|
176
|
+
mode,
|
|
177
|
+
projectRoot: options.projectRoot,
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
if (!result.success) {
|
|
181
|
+
throw new Error(`icp-cli deploy failed: ${result.stderr || result.stdout}`);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Parse canister ID from output (best effort)
|
|
185
|
+
const canisterIdMatch = result.stdout.match(/([a-z0-9]{5}-[a-z0-9]{5}-[a-z0-9]{5}-[a-z0-9]{5}-[a-z0-9]{3})/);
|
|
186
|
+
const canisterId = canisterIdMatch?.[1] ?? options.canisterId ?? 'unknown';
|
|
187
|
+
|
|
188
|
+
const canisterInfo: CanisterInfo = {
|
|
189
|
+
canisterId,
|
|
190
|
+
network: options.network,
|
|
191
|
+
agentName: extractAgentName(options.wasmPath),
|
|
192
|
+
deployedAt: new Date(),
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
canister: canisterInfo,
|
|
197
|
+
isUpgrade: mode === 'upgrade',
|
|
198
|
+
warnings: [...warnings, `Deployed via icp-cli (environment: ${envName})`],
|
|
199
|
+
deployTool: 'icp',
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Deploy using @dfinity/agent SDK (original implementation).
|
|
205
|
+
*/
|
|
206
|
+
async function deployWithSdk(
|
|
207
|
+
options: DeployOptions,
|
|
208
|
+
warnings: string[],
|
|
209
|
+
): Promise<DeployResult> {
|
|
210
|
+
// Create ICP client
|
|
211
|
+
const client = createICPClient({
|
|
212
|
+
network: options.network,
|
|
213
|
+
identity: options.identityPath,
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// Check network connection
|
|
217
|
+
const connectionCheck = await client.checkConnection();
|
|
218
|
+
if (!connectionCheck.connected) {
|
|
219
|
+
throw new Error(
|
|
220
|
+
`Failed to connect to ${options.network} network: ${connectionCheck.error ?? 'Unknown error'}`
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Deploy the WASM
|
|
225
|
+
const deployResult = await client.deploy(options.wasmPath, options.canisterId);
|
|
226
|
+
|
|
227
|
+
// Build canister info
|
|
228
|
+
const canisterInfo: CanisterInfo = {
|
|
229
|
+
canisterId: deployResult.canisterId,
|
|
230
|
+
network: options.network,
|
|
231
|
+
agentName: extractAgentName(options.wasmPath),
|
|
232
|
+
deployedAt: new Date(),
|
|
233
|
+
wasmHash: deployResult.wasmHash,
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
return {
|
|
237
|
+
canister: canisterInfo,
|
|
238
|
+
isUpgrade: deployResult.isUpgrade,
|
|
239
|
+
cyclesUsed: deployResult.cyclesUsed,
|
|
240
|
+
warnings,
|
|
241
|
+
deployTool: 'sdk',
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Check if a canister exists and get its status
|
|
247
|
+
*/
|
|
248
|
+
export async function getCanisterStatus(
|
|
249
|
+
canisterId: string,
|
|
250
|
+
network: NetworkType
|
|
251
|
+
): Promise<{
|
|
252
|
+
exists: boolean;
|
|
253
|
+
status?: DeploymentStatus;
|
|
254
|
+
memorySize?: bigint;
|
|
255
|
+
cycles?: bigint;
|
|
256
|
+
}> {
|
|
257
|
+
const client = createICPClient({ network });
|
|
258
|
+
|
|
259
|
+
try {
|
|
260
|
+
const status = await client.getCanisterStatus(canisterId);
|
|
261
|
+
if (!status.exists) {
|
|
262
|
+
return { exists: false };
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return {
|
|
266
|
+
exists: status.exists,
|
|
267
|
+
status: status.status,
|
|
268
|
+
memorySize: status.memorySize,
|
|
269
|
+
cycles: status.cycles,
|
|
270
|
+
};
|
|
271
|
+
} catch {
|
|
272
|
+
return { exists: false };
|
|
273
|
+
}
|
|
274
|
+
}
|