@zan_team/cli 0.0.2 → 0.0.5
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 +111 -225
- package/dist/cli.js +206 -58
- package/package.json +2 -2
- package/dist/cli.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -645,7 +645,8 @@ function registerCompletions(program, outputWriter) {
|
|
|
645
645
|
|
|
646
646
|
// src/commands/evm.ts
|
|
647
647
|
import {
|
|
648
|
-
InvalidArgumentError as InvalidArgumentError3
|
|
648
|
+
InvalidArgumentError as InvalidArgumentError3,
|
|
649
|
+
Option
|
|
649
650
|
} from "commander";
|
|
650
651
|
import { parseEther, parseGwei } from "viem";
|
|
651
652
|
|
|
@@ -1247,7 +1248,9 @@ function registerEvm(program, outputWriter, getRuntimeContext, input) {
|
|
|
1247
1248
|
});
|
|
1248
1249
|
tx.command("sign").description(
|
|
1249
1250
|
"Sign a transaction locally and print the raw signed transaction"
|
|
1250
|
-
).requiredOption("--to <address>", "recipient address", parseAddressArgument).
|
|
1251
|
+
).requiredOption("--to <address>", "recipient address", parseAddressArgument).addOption(
|
|
1252
|
+
new Option("--value <ether>", "ether amount").argParser(parseEtherOption).default(0n, "0")
|
|
1253
|
+
).option("--data <hex>", "call data", parseHexDataOption, "0x").option("--nonce <n>", "explicit nonce", parseNonceOption).option("--gas-limit <n>", "explicit gas limit", parseGasLimitOption).option(
|
|
1251
1254
|
"--max-fee-per-gas <gwei>",
|
|
1252
1255
|
"EIP-1559 max fee in gwei",
|
|
1253
1256
|
parseGweiOption
|
|
@@ -1809,6 +1812,10 @@ function registerProject(program, outputWriter, getRuntimeContext, input, rpcKey
|
|
|
1809
1812
|
rpcKey.command("pull").description("Write the active Project RPC API Key to .env").action(async () => {
|
|
1810
1813
|
const { rpcKeyPullService } = await getRuntimeContext();
|
|
1811
1814
|
const result = await rpcKeyPullService.pull();
|
|
1815
|
+
for (const warning of result.warnings ?? []) {
|
|
1816
|
+
outputWriter.writeStderr(`Warning: ${warning}
|
|
1817
|
+
`);
|
|
1818
|
+
}
|
|
1812
1819
|
outputWriter.success(
|
|
1813
1820
|
result,
|
|
1814
1821
|
"ZAN_API_KEY was written to .env"
|
|
@@ -1891,7 +1898,7 @@ function registerSign(program, outputWriter, getRuntimeContext) {
|
|
|
1891
1898
|
}
|
|
1892
1899
|
|
|
1893
1900
|
// src/version.ts
|
|
1894
|
-
var CLI_VERSION = true ? "0.0.
|
|
1901
|
+
var CLI_VERSION = true ? "0.0.5" : pkg.version;
|
|
1895
1902
|
|
|
1896
1903
|
// src/commands/version.ts
|
|
1897
1904
|
function registerVersion(program, outputWriter) {
|
|
@@ -1901,7 +1908,7 @@ function registerVersion(program, outputWriter) {
|
|
|
1901
1908
|
}
|
|
1902
1909
|
|
|
1903
1910
|
// src/commands/skills.ts
|
|
1904
|
-
import { Option } from "commander";
|
|
1911
|
+
import { Option as Option2 } from "commander";
|
|
1905
1912
|
|
|
1906
1913
|
// src/skills/install.ts
|
|
1907
1914
|
import { createHash } from "crypto";
|
|
@@ -2087,7 +2094,7 @@ async function installSkill(options, environment = {}) {
|
|
|
2087
2094
|
|
|
2088
2095
|
// src/commands/skills.ts
|
|
2089
2096
|
function registerSkills(program, outputWriter, environment) {
|
|
2090
|
-
program.command("skills").description("Manage bundled ZAN CLI agent skills").command("install").description("Install or update the bundled skill (current project by default)").addOption(new
|
|
2097
|
+
program.command("skills").description("Manage bundled ZAN CLI agent skills").command("install").description("Install or update the bundled skill (current project by default)").addOption(new Option2("-a, --agent <agent>", "target agent").choices([...SKILL_AGENTS]).makeOptionMandatory()).option("-g, --global", "install for the current user instead of the current directory").option("--force", "replace the entire existing skill directory, discarding local changes").action(async (options) => {
|
|
2091
2098
|
const result = await installSkill(options, environment);
|
|
2092
2099
|
const invocation = result.agent === "codex" ? "$zan-cli" : "/zan-cli";
|
|
2093
2100
|
outputWriter.success(result, [
|
|
@@ -2166,7 +2173,7 @@ var ReadlineProjectPrompt = class {
|
|
|
2166
2173
|
|
|
2167
2174
|
// src/runtime/context.ts
|
|
2168
2175
|
import { homedir as readHomedir2 } from "os";
|
|
2169
|
-
import { join as
|
|
2176
|
+
import { join as join7 } from "path";
|
|
2170
2177
|
|
|
2171
2178
|
// src/auth/session-metadata-store.ts
|
|
2172
2179
|
import { z as z8 } from "zod";
|
|
@@ -2630,9 +2637,9 @@ var BrowserFlow = class {
|
|
|
2630
2637
|
// src/auth/browser-opener.ts
|
|
2631
2638
|
import { execFile as nodeExecFile } from "child_process";
|
|
2632
2639
|
var BrowserOpener = class {
|
|
2633
|
-
constructor(platform = process.platform,
|
|
2640
|
+
constructor(platform = process.platform, execFile2 = nodeExecFile) {
|
|
2634
2641
|
this.platform = platform;
|
|
2635
|
-
this.execFile =
|
|
2642
|
+
this.execFile = execFile2;
|
|
2636
2643
|
}
|
|
2637
2644
|
platform;
|
|
2638
2645
|
execFile;
|
|
@@ -5133,7 +5140,7 @@ var NetworkSelector = class {
|
|
|
5133
5140
|
};
|
|
5134
5141
|
|
|
5135
5142
|
// src/projects/dotenv-api-key-writer.ts
|
|
5136
|
-
import { randomUUID as
|
|
5143
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
5137
5144
|
import {
|
|
5138
5145
|
chmod as nodeChmod2,
|
|
5139
5146
|
lstat as nodeLstat2,
|
|
@@ -5142,7 +5149,111 @@ import {
|
|
|
5142
5149
|
rename as nodeRename,
|
|
5143
5150
|
unlink as nodeUnlink
|
|
5144
5151
|
} from "fs/promises";
|
|
5145
|
-
import { isAbsolute as isAbsolute3, join as
|
|
5152
|
+
import { isAbsolute as isAbsolute3, join as join5 } from "path";
|
|
5153
|
+
|
|
5154
|
+
// src/projects/dotenv-gitignore.ts
|
|
5155
|
+
import { execFile } from "child_process";
|
|
5156
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
5157
|
+
import { lstat as lstat4, mkdtemp as mkdtemp2, open as open2, readFile as readFile3, rename as rename2, rm as rm2 } from "fs/promises";
|
|
5158
|
+
import { tmpdir } from "os";
|
|
5159
|
+
import { join as join4 } from "path";
|
|
5160
|
+
import { promisify } from "util";
|
|
5161
|
+
var execute = promisify(execFile);
|
|
5162
|
+
var UNCONFIRMED_WARNING = "Unable to confirm .env is ignored by Git; there is a risk of committing the API Key. Check Git and .gitignore before committing.";
|
|
5163
|
+
function protectionFailure() {
|
|
5164
|
+
return new Error("Unable to verify Git ignore rules.");
|
|
5165
|
+
}
|
|
5166
|
+
async function appendRule(directory) {
|
|
5167
|
+
const filename = join4(directory, ".gitignore");
|
|
5168
|
+
let current = "";
|
|
5169
|
+
let mode = 420;
|
|
5170
|
+
try {
|
|
5171
|
+
const info = await lstat4(filename);
|
|
5172
|
+
if (!info.isFile() || info.isSymbolicLink()) throw protectionFailure();
|
|
5173
|
+
mode = info.mode & 511;
|
|
5174
|
+
current = await readFile3(filename, "utf8");
|
|
5175
|
+
} catch (error) {
|
|
5176
|
+
if (error.code !== "ENOENT") throw error;
|
|
5177
|
+
}
|
|
5178
|
+
const newline = current.includes("\r\n") ? "\r\n" : "\n";
|
|
5179
|
+
const separator = current.length === 0 || current.endsWith("\n") ? "" : newline;
|
|
5180
|
+
const temporary = join4(directory, `.gitignore.${randomUUID3()}.tmp`);
|
|
5181
|
+
try {
|
|
5182
|
+
const handle = await open2(temporary, "wx", mode);
|
|
5183
|
+
try {
|
|
5184
|
+
await handle.writeFile(`${current}${separator}/.env${newline}`, "utf8");
|
|
5185
|
+
await handle.sync();
|
|
5186
|
+
} finally {
|
|
5187
|
+
await handle.close();
|
|
5188
|
+
}
|
|
5189
|
+
await rename2(temporary, filename);
|
|
5190
|
+
} finally {
|
|
5191
|
+
await rm2(temporary, { force: true });
|
|
5192
|
+
}
|
|
5193
|
+
}
|
|
5194
|
+
async function ensureDotenvIgnored(directory) {
|
|
5195
|
+
const warnings = [];
|
|
5196
|
+
const env = { ...process.env, LC_ALL: "C" };
|
|
5197
|
+
for (const name of ["GIT_DIR", "GIT_WORK_TREE", "GIT_INDEX_FILE", "GIT_COMMON_DIR", "GIT_PREFIX"]) {
|
|
5198
|
+
delete env[name];
|
|
5199
|
+
}
|
|
5200
|
+
const git = async (args) => {
|
|
5201
|
+
try {
|
|
5202
|
+
return { code: 0, ...await execute("git", args, {
|
|
5203
|
+
cwd: directory,
|
|
5204
|
+
env,
|
|
5205
|
+
encoding: "utf8",
|
|
5206
|
+
timeout: 1e4,
|
|
5207
|
+
maxBuffer: 64 * 1024
|
|
5208
|
+
}) };
|
|
5209
|
+
} catch (error) {
|
|
5210
|
+
const failure = error;
|
|
5211
|
+
if (typeof failure.code !== "number") throw protectionFailure();
|
|
5212
|
+
return { code: failure.code, stdout: failure.stdout ?? "", stderr: failure.stderr ?? "" };
|
|
5213
|
+
}
|
|
5214
|
+
};
|
|
5215
|
+
let temporaryRepository;
|
|
5216
|
+
try {
|
|
5217
|
+
const repository = await git(["rev-parse", "--is-inside-work-tree"]);
|
|
5218
|
+
let prefix = [];
|
|
5219
|
+
if (repository.code === 0 && repository.stdout.trim() === "true") {
|
|
5220
|
+
const tracked = await git(["ls-files", "--error-unmatch", "--", ".env"]);
|
|
5221
|
+
if (tracked.code === 0) {
|
|
5222
|
+
warnings.push(
|
|
5223
|
+
".env is already tracked by Git; there is a risk of committing the API Key even with .gitignore. Run: git rm --cached -- .env, and review staged changes before committing."
|
|
5224
|
+
);
|
|
5225
|
+
} else if (tracked.code !== 1) {
|
|
5226
|
+
throw protectionFailure();
|
|
5227
|
+
}
|
|
5228
|
+
} else if (repository.code === 128 && repository.stderr.includes("not a git repository")) {
|
|
5229
|
+
temporaryRepository = await mkdtemp2(join4(tmpdir(), "zan-ignore-"));
|
|
5230
|
+
const initialized = await git(["init", "--bare", "--quiet", "--template=", temporaryRepository]);
|
|
5231
|
+
if (initialized.code !== 0) throw protectionFailure();
|
|
5232
|
+
prefix = [`--git-dir=${temporaryRepository}`, `--work-tree=${directory}`, "-c", "core.bare=false"];
|
|
5233
|
+
} else {
|
|
5234
|
+
throw protectionFailure();
|
|
5235
|
+
}
|
|
5236
|
+
const ignored = await git([...prefix, "check-ignore", "--quiet", "--no-index", "--", ".env"]);
|
|
5237
|
+
if (ignored.code === 0) return warnings;
|
|
5238
|
+
if (ignored.code !== 1) throw protectionFailure();
|
|
5239
|
+
await appendRule(directory);
|
|
5240
|
+
const verified = await git([...prefix, "check-ignore", "--quiet", "--no-index", "--", ".env"]);
|
|
5241
|
+
if (verified.code !== 0) throw protectionFailure();
|
|
5242
|
+
} catch {
|
|
5243
|
+
warnings.push(UNCONFIRMED_WARNING);
|
|
5244
|
+
} finally {
|
|
5245
|
+
if (temporaryRepository !== void 0) {
|
|
5246
|
+
try {
|
|
5247
|
+
await rm2(temporaryRepository, { recursive: true, force: true });
|
|
5248
|
+
} catch {
|
|
5249
|
+
warnings.push("Temporary Git metadata could not be removed; review the system temporary directory.");
|
|
5250
|
+
}
|
|
5251
|
+
}
|
|
5252
|
+
}
|
|
5253
|
+
return warnings;
|
|
5254
|
+
}
|
|
5255
|
+
|
|
5256
|
+
// src/projects/dotenv-api-key-writer.ts
|
|
5146
5257
|
var API_KEY_ASSIGNMENT = /^[ \t]*(?:export[ \t]+)?ZAN_API_KEY[ \t]*=/u;
|
|
5147
5258
|
function unsafeKeyFailure() {
|
|
5148
5259
|
return new CliFailure(
|
|
@@ -5220,7 +5331,7 @@ var DotenvApiKeyWriter = class {
|
|
|
5220
5331
|
this.options = options;
|
|
5221
5332
|
this.platform = options.platform ?? process.platform;
|
|
5222
5333
|
this.fileSystem = options.fileSystem ?? nodeDotenvApiKeyFileSystem;
|
|
5223
|
-
this.createTemporaryId = options.createTemporaryId ??
|
|
5334
|
+
this.createTemporaryId = options.createTemporaryId ?? randomUUID4;
|
|
5224
5335
|
}
|
|
5225
5336
|
options;
|
|
5226
5337
|
platform;
|
|
@@ -5234,8 +5345,9 @@ var DotenvApiKeyWriter = class {
|
|
|
5234
5345
|
if (!isAbsolute3(this.options.directory)) {
|
|
5235
5346
|
throw unsafeDotenvPathFailure();
|
|
5236
5347
|
}
|
|
5237
|
-
const lockPath =
|
|
5348
|
+
const lockPath = join5(this.options.directory, ".env.zan.lock");
|
|
5238
5349
|
let renamed = false;
|
|
5350
|
+
let warnings = [];
|
|
5239
5351
|
try {
|
|
5240
5352
|
await this.assertSafeOptionalPath(lockPath);
|
|
5241
5353
|
const lock = new FileLock(lockPath, {
|
|
@@ -5244,11 +5356,15 @@ var DotenvApiKeyWriter = class {
|
|
|
5244
5356
|
await lock.withLock(async () => {
|
|
5245
5357
|
const current = await this.readExistingFile();
|
|
5246
5358
|
const next = updateApiKeyAssignment(current, parsed.data);
|
|
5359
|
+
warnings = await ensureDotenvIgnored(this.options.directory);
|
|
5247
5360
|
await this.replaceAtomically(next, () => {
|
|
5248
5361
|
renamed = true;
|
|
5249
5362
|
});
|
|
5250
5363
|
});
|
|
5251
5364
|
} catch (error) {
|
|
5365
|
+
if (error instanceof CliFailure) {
|
|
5366
|
+
throw error;
|
|
5367
|
+
}
|
|
5252
5368
|
if (error instanceof UnsafeDotenvPathError) {
|
|
5253
5369
|
throw unsafeDotenvPathFailure();
|
|
5254
5370
|
}
|
|
@@ -5257,6 +5373,9 @@ var DotenvApiKeyWriter = class {
|
|
|
5257
5373
|
}
|
|
5258
5374
|
throw dotenvWriteFailure();
|
|
5259
5375
|
}
|
|
5376
|
+
if (warnings.length > 0) {
|
|
5377
|
+
return { warnings };
|
|
5378
|
+
}
|
|
5260
5379
|
}
|
|
5261
5380
|
async assertSafeOptionalPath(path) {
|
|
5262
5381
|
try {
|
|
@@ -5272,7 +5391,7 @@ var DotenvApiKeyWriter = class {
|
|
|
5272
5391
|
}
|
|
5273
5392
|
}
|
|
5274
5393
|
async readExistingFile() {
|
|
5275
|
-
const filename =
|
|
5394
|
+
const filename = join5(this.options.directory, ".env");
|
|
5276
5395
|
await this.assertSafeOptionalPath(filename);
|
|
5277
5396
|
try {
|
|
5278
5397
|
return await this.fileSystem.readFile(filename, "utf8");
|
|
@@ -5284,8 +5403,8 @@ var DotenvApiKeyWriter = class {
|
|
|
5284
5403
|
}
|
|
5285
5404
|
}
|
|
5286
5405
|
async replaceAtomically(content, onRenamed) {
|
|
5287
|
-
const filename =
|
|
5288
|
-
const temporaryFile =
|
|
5406
|
+
const filename = join5(this.options.directory, ".env");
|
|
5407
|
+
const temporaryFile = join5(
|
|
5289
5408
|
this.options.directory,
|
|
5290
5409
|
`.env.${process.pid}.${this.createTemporaryId()}.tmp`
|
|
5291
5410
|
);
|
|
@@ -5479,22 +5598,22 @@ import { posix, win32 } from "path";
|
|
|
5479
5598
|
// src/storage/atomic-json.ts
|
|
5480
5599
|
import {
|
|
5481
5600
|
chmod as chmod3,
|
|
5482
|
-
lstat as
|
|
5601
|
+
lstat as lstat5,
|
|
5483
5602
|
mkdir as mkdir3,
|
|
5484
|
-
open as
|
|
5485
|
-
readFile as
|
|
5486
|
-
rename as
|
|
5603
|
+
open as open3,
|
|
5604
|
+
readFile as readFile4,
|
|
5605
|
+
rename as rename3,
|
|
5487
5606
|
unlink as unlink2
|
|
5488
5607
|
} from "fs/promises";
|
|
5489
5608
|
import { dirname as dirname2 } from "path";
|
|
5490
|
-
import { randomUUID as
|
|
5609
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
5491
5610
|
var nodeAtomicJsonFileSystem = Object.freeze({
|
|
5492
5611
|
chmod: chmod3,
|
|
5493
|
-
lstat:
|
|
5612
|
+
lstat: lstat5,
|
|
5494
5613
|
mkdir: mkdir3,
|
|
5495
|
-
open:
|
|
5496
|
-
readFile:
|
|
5497
|
-
rename:
|
|
5614
|
+
open: open3,
|
|
5615
|
+
readFile: readFile4,
|
|
5616
|
+
rename: rename3,
|
|
5498
5617
|
unlink: unlink2
|
|
5499
5618
|
});
|
|
5500
5619
|
function hasErrorCode5(error, code) {
|
|
@@ -5538,7 +5657,7 @@ var AtomicJsonStore = class {
|
|
|
5538
5657
|
this.filename = filename;
|
|
5539
5658
|
this.fileSystem = options.fileSystem ?? nodeAtomicJsonFileSystem;
|
|
5540
5659
|
this.platform = options.platform ?? process.platform;
|
|
5541
|
-
this.createTemporaryId = options.createTemporaryId ??
|
|
5660
|
+
this.createTemporaryId = options.createTemporaryId ?? randomUUID5;
|
|
5542
5661
|
}
|
|
5543
5662
|
schema;
|
|
5544
5663
|
filename;
|
|
@@ -5840,6 +5959,13 @@ var ProjectEndpointCache = class {
|
|
|
5840
5959
|
).toString("base64url");
|
|
5841
5960
|
return `endpoint-cache-key-${scope}`;
|
|
5842
5961
|
}
|
|
5962
|
+
apiKeyAccount(projectId) {
|
|
5963
|
+
const scope = Buffer6.from(
|
|
5964
|
+
`${this.options.environment}:${projectId}`,
|
|
5965
|
+
"utf8"
|
|
5966
|
+
).toString("base64url");
|
|
5967
|
+
return `project-rpc-key-${scope}`;
|
|
5968
|
+
}
|
|
5843
5969
|
overrideAccount(projectId) {
|
|
5844
5970
|
const scope = Buffer6.from(
|
|
5845
5971
|
`${this.options.environment}:${projectId}`,
|
|
@@ -5895,6 +6021,18 @@ var ProjectEndpointCache = class {
|
|
|
5895
6021
|
}
|
|
5896
6022
|
throw error;
|
|
5897
6023
|
}
|
|
6024
|
+
let apiKey;
|
|
6025
|
+
for (const network of networks) {
|
|
6026
|
+
apiKey = this.extractCredential(network.endpoints.https);
|
|
6027
|
+
if (apiKey !== void 0) {
|
|
6028
|
+
break;
|
|
6029
|
+
}
|
|
6030
|
+
}
|
|
6031
|
+
if (apiKey === void 0) {
|
|
6032
|
+
await this.options.secretStore.delete(this.apiKeyAccount(projectId));
|
|
6033
|
+
} else {
|
|
6034
|
+
await this.options.secretStore.write(this.apiKeyAccount(projectId), apiKey);
|
|
6035
|
+
}
|
|
5898
6036
|
return networks;
|
|
5899
6037
|
}
|
|
5900
6038
|
status(projectId) {
|
|
@@ -5903,7 +6041,8 @@ var ProjectEndpointCache = class {
|
|
|
5903
6041
|
async clear(projectId) {
|
|
5904
6042
|
const results = await Promise.allSettled([
|
|
5905
6043
|
this.options.store.delete(projectId),
|
|
5906
|
-
this.options.secretStore.delete(this.cacheKeyAccount(projectId))
|
|
6044
|
+
this.options.secretStore.delete(this.cacheKeyAccount(projectId)),
|
|
6045
|
+
this.options.secretStore.delete(this.apiKeyAccount(projectId))
|
|
5907
6046
|
]);
|
|
5908
6047
|
const failure = results.find(
|
|
5909
6048
|
(result) => result.status === "rejected"
|
|
@@ -5962,20 +6101,23 @@ var ProjectEndpointCache = class {
|
|
|
5962
6101
|
this.overrideAccount(projectId)
|
|
5963
6102
|
);
|
|
5964
6103
|
if (override !== null) {
|
|
5965
|
-
const
|
|
5966
|
-
if (!
|
|
6104
|
+
const parsed2 = rpcApiKeySchema.safeParse(override);
|
|
6105
|
+
if (!parsed2.success) {
|
|
5967
6106
|
throw unavailableApiKey();
|
|
5968
6107
|
}
|
|
5969
|
-
return
|
|
6108
|
+
return parsed2.data;
|
|
5970
6109
|
}
|
|
5971
|
-
const
|
|
5972
|
-
|
|
5973
|
-
)
|
|
5974
|
-
|
|
5975
|
-
|
|
6110
|
+
const account = this.apiKeyAccount(projectId);
|
|
6111
|
+
let key = await this.options.secretStore.read(account);
|
|
6112
|
+
if (key === null) {
|
|
6113
|
+
await this.refresh(projectId);
|
|
6114
|
+
key = await this.options.secretStore.read(account);
|
|
6115
|
+
}
|
|
6116
|
+
const parsed = rpcApiKeySchema.safeParse(key);
|
|
6117
|
+
if (!parsed.success) {
|
|
5976
6118
|
throw unavailableApiKey();
|
|
5977
6119
|
}
|
|
5978
|
-
return
|
|
6120
|
+
return parsed.data;
|
|
5979
6121
|
}
|
|
5980
6122
|
async applyOverride(projectId, network) {
|
|
5981
6123
|
const key = await this.options.secretStore.read(
|
|
@@ -6032,33 +6174,39 @@ var ProjectEndpointCache = class {
|
|
|
6032
6174
|
);
|
|
6033
6175
|
}
|
|
6034
6176
|
}
|
|
6035
|
-
extractCredential(
|
|
6177
|
+
extractCredential(endpoint) {
|
|
6036
6178
|
try {
|
|
6037
|
-
const url = new URL(
|
|
6179
|
+
const url = new URL(endpoint);
|
|
6038
6180
|
const trustedHost = url.hostname === "zan.top" || url.hostname.endsWith(".zan.top");
|
|
6039
6181
|
const segments = url.pathname.slice(1).split("/");
|
|
6040
6182
|
if (url.protocol !== "https:" || !trustedHost || url.port.length > 0 || url.username.length > 0 || url.password.length > 0 || url.search.length > 0 || url.hash.length > 0 || !url.pathname.startsWith("/") || segments.some((segment) => segment.length === 0) || url.pathname !== `/${segments.join("/")}`) {
|
|
6041
6183
|
throw new Error("unsafe");
|
|
6042
6184
|
}
|
|
6043
|
-
|
|
6044
|
-
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
6049
|
-
|
|
6050
|
-
|
|
6051
|
-
|
|
6052
|
-
|
|
6053
|
-
|
|
6185
|
+
if (segments[0] !== "node" || segments[1] !== "v1" || !networkIdSchema.safeParse(segments[2]).success || !networkIdSchema.safeParse(segments[3]).success) {
|
|
6186
|
+
return void 0;
|
|
6187
|
+
}
|
|
6188
|
+
let suffix = "";
|
|
6189
|
+
switch (segments[2]) {
|
|
6190
|
+
case "hyperliquid":
|
|
6191
|
+
suffix = "evm";
|
|
6192
|
+
break;
|
|
6193
|
+
case "avax":
|
|
6194
|
+
suffix = "ext/bc/C/rpc";
|
|
6195
|
+
break;
|
|
6196
|
+
case "tron":
|
|
6197
|
+
suffix = "jsonrpc";
|
|
6198
|
+
break;
|
|
6054
6199
|
}
|
|
6055
|
-
|
|
6200
|
+
if (segments.slice(5).join("/") !== suffix) {
|
|
6201
|
+
return void 0;
|
|
6202
|
+
}
|
|
6203
|
+
const parsed = rpcApiKeySchema.safeParse(segments[4]);
|
|
6056
6204
|
if (!parsed.success) {
|
|
6057
6205
|
throw new Error("unsafe");
|
|
6058
6206
|
}
|
|
6059
6207
|
return parsed.data;
|
|
6060
6208
|
} catch {
|
|
6061
|
-
|
|
6209
|
+
return void 0;
|
|
6062
6210
|
}
|
|
6063
6211
|
}
|
|
6064
6212
|
};
|
|
@@ -6072,21 +6220,22 @@ var RpcKeyPullService = class {
|
|
|
6072
6220
|
async pull() {
|
|
6073
6221
|
const projectId = await this.dependencies.projects.activeId();
|
|
6074
6222
|
const key = await this.dependencies.keys.effectiveApiKey(projectId);
|
|
6075
|
-
await this.dependencies.writer.write(key);
|
|
6223
|
+
const result = await this.dependencies.writer.write(key);
|
|
6076
6224
|
return {
|
|
6077
6225
|
file: ".env",
|
|
6078
6226
|
variable: "ZAN_API_KEY",
|
|
6079
|
-
updated: true
|
|
6227
|
+
updated: true,
|
|
6228
|
+
...result?.warnings.length ? { warnings: result.warnings } : {}
|
|
6080
6229
|
};
|
|
6081
6230
|
}
|
|
6082
6231
|
};
|
|
6083
6232
|
|
|
6084
6233
|
// src/projects/project-service.ts
|
|
6085
|
-
import { randomUUID as
|
|
6234
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
6086
6235
|
var ProjectService = class {
|
|
6087
6236
|
constructor(options) {
|
|
6088
6237
|
this.options = options;
|
|
6089
|
-
this.createIdempotencyKey = options.createIdempotencyKey ??
|
|
6238
|
+
this.createIdempotencyKey = options.createIdempotencyKey ?? randomUUID6;
|
|
6090
6239
|
}
|
|
6091
6240
|
options;
|
|
6092
6241
|
createIdempotencyKey;
|
|
@@ -6480,7 +6629,7 @@ var SettingsStore = class {
|
|
|
6480
6629
|
};
|
|
6481
6630
|
|
|
6482
6631
|
// src/settings/paths.ts
|
|
6483
|
-
import { join as
|
|
6632
|
+
import { join as join6, posix as posix2, win32 as win322 } from "path";
|
|
6484
6633
|
function nonEmpty(value) {
|
|
6485
6634
|
return value === void 0 || value.length === 0 ? void 0 : value;
|
|
6486
6635
|
}
|
|
@@ -6513,7 +6662,7 @@ function resolveZanHome(env, platform, homedir2) {
|
|
|
6513
6662
|
}
|
|
6514
6663
|
if (platform === "darwin") {
|
|
6515
6664
|
return validateHomePath(
|
|
6516
|
-
|
|
6665
|
+
join6(readHomedir(homedir2), "Library", "Application Support", "zan"),
|
|
6517
6666
|
platform
|
|
6518
6667
|
);
|
|
6519
6668
|
}
|
|
@@ -7336,7 +7485,7 @@ function createRuntimeContext(input) {
|
|
|
7336
7485
|
walletService ??= new WalletService({
|
|
7337
7486
|
index: new AtomicJsonStore(
|
|
7338
7487
|
walletIndexSchema,
|
|
7339
|
-
|
|
7488
|
+
join7(home, "wallets.json"),
|
|
7340
7489
|
{ platform }
|
|
7341
7490
|
),
|
|
7342
7491
|
secrets: secretStore,
|
|
@@ -7652,4 +7801,3 @@ export {
|
|
|
7652
7801
|
isMainModule,
|
|
7653
7802
|
runCli
|
|
7654
7803
|
};
|
|
7655
|
-
//# sourceMappingURL=cli.js.map
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zan_team/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Unified ZAN command-line interface for developers, automation, and AI agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"zan": "./dist/cli.js"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
|
-
"dist",
|
|
10
|
+
"dist/cli.js",
|
|
11
11
|
"skills",
|
|
12
12
|
"README.md"
|
|
13
13
|
],
|