@aexhq/cli 0.19.0 → 0.21.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/dist/cli.mjs CHANGED
@@ -126,6 +126,34 @@ var PROVIDER_PUBLIC_SUPPORT = {
126
126
  runtimeEvidence: {
127
127
  managed: COMMON_EVIDENCE
128
128
  }
129
+ },
130
+ // Doubao (ByteDance) via the official Ark API — international BytePlus gateway.
131
+ // Wired + parser/routing-verified but not yet proven against a live BytePlus
132
+ // account, so `live-unverified`. Promote to `supported` (and swap COMMON_EVIDENCE
133
+ // for a DOUBAO_MANAGED_EVIDENCE pointer to live-sdk-doubao.test.ts) once the
134
+ // live run passes.
135
+ doubao: {
136
+ displayName: "Doubao",
137
+ status: "live-unverified",
138
+ docsAnchor: "doubao",
139
+ docs: COMMON_DOCS,
140
+ evidence: COMMON_EVIDENCE,
141
+ runtimeEvidence: {
142
+ managed: COMMON_EVIDENCE
143
+ }
144
+ },
145
+ // Doubao (ByteDance) via the official Ark API — China Volcengine gateway.
146
+ // Same wiring as `doubao`; additionally gated on CF Worker egress reaching the
147
+ // Beijing host (see apps/egress-probe). `live-unverified` until proven live.
148
+ "doubao-cn": {
149
+ displayName: "Doubao (China)",
150
+ status: "live-unverified",
151
+ docsAnchor: "doubao-cn",
152
+ docs: COMMON_DOCS,
153
+ evidence: COMMON_EVIDENCE,
154
+ runtimeEvidence: {
155
+ managed: COMMON_EVIDENCE
156
+ }
129
157
  }
130
158
  };
131
159
 
@@ -144,7 +172,21 @@ var MODEL_PROVIDER_IDS = {
144
172
  "gemini-2.0-flash": { gemini: "gemini-2.0-flash", openrouter: "google/gemini-2.0-flash-001" },
145
173
  "gemini-2.5-flash": { gemini: "gemini-2.5-flash" },
146
174
  "mistral-large-latest": { mistral: "mistral-large-latest" },
147
- "mistral-small-latest": { mistral: "mistral-small-latest" }
175
+ "mistral-small-latest": { mistral: "mistral-small-latest" },
176
+ // Doubao (ByteDance) via the official Ark API. Served by both the
177
+ // international BytePlus ModelArk gateway (`doubao`, the default) and the
178
+ // China Volcengine Ark gateway (`doubao-cn`). Ark accepts the API-format
179
+ // model NAME directly in the chat-completions `model` field (no `ep-…`
180
+ // inference-endpoint id). The native strings are the same Ark catalog ids on
181
+ // both gateways; BytePlus per-account availability is confirmed at live-verify
182
+ // (both providers ship `live-unverified` until then — provider-support.ts).
183
+ // pro — Doubao Seed 1.8 (flagship, 256K context).
184
+ // flash — Doubao Seed 1.6 Flash (fast/cheap, 256K context).
185
+ "doubao-seed-pro": { doubao: "doubao-seed-1-8-251228", "doubao-cn": "doubao-seed-1-8-251228" },
186
+ "doubao-seed-flash": {
187
+ doubao: "doubao-seed-1-6-flash-250828",
188
+ "doubao-cn": "doubao-seed-1-6-flash-250828"
189
+ }
148
190
  };
149
191
  var RUN_MODELS = Object.keys(MODEL_PROVIDER_IDS);
150
192
  var PROVIDERS_BY_MODEL = (() => {
@@ -743,7 +785,9 @@ var RUN_PROVIDERS = [
743
785
  "openai",
744
786
  "gemini",
745
787
  "mistral",
746
- "openrouter"
788
+ "openrouter",
789
+ "doubao",
790
+ "doubao-cn"
747
791
  ];
748
792
  var DEFAULT_RUN_PROVIDER = "anthropic";
749
793
  var RUNTIME_KINDS = ["managed"];
@@ -794,7 +838,7 @@ function visitCustodyValue(input, path, findings) {
794
838
  }
795
839
  function scanStringValue(value, path, findings) {
796
840
  for (const pattern of forbiddenStringPatterns) {
797
- if (pattern.regex.test(value)) {
841
+ if (matchesForbiddenPattern(pattern, value)) {
798
842
  findings.push(Object.freeze({
799
843
  path,
800
844
  reason: pattern.reason,
@@ -803,11 +847,32 @@ function scanStringValue(value, path, findings) {
803
847
  }
804
848
  }
805
849
  }
850
+ function matchesForbiddenPattern(pattern, value) {
851
+ if (!pattern.accept) {
852
+ return pattern.regex.test(value);
853
+ }
854
+ const scan = pattern.regex.global ? pattern.regex : new RegExp(pattern.regex.source, `${pattern.regex.flags}g`);
855
+ scan.lastIndex = 0;
856
+ let match;
857
+ while ((match = scan.exec(value)) !== null) {
858
+ if (pattern.accept(match[0])) {
859
+ return true;
860
+ }
861
+ if (match.index === scan.lastIndex) {
862
+ scan.lastIndex++;
863
+ }
864
+ }
865
+ return false;
866
+ }
806
867
  var forbiddenStringPatterns = Object.freeze([
807
868
  { reason: "bearer_token", regex: /\bBearer\s+[A-Za-z0-9._~+/=-]{8,}/i },
808
869
  {
809
870
  reason: "provider_key",
810
- regex: /\b(?:sk-(?:ant|proj|live|test|deepseek|openai)|xox[baprs]-|AIza)[A-Za-z0-9_-]{8,}/i
871
+ // Prefixed provider keys (`sk-…`, Slack `xox*-…`, Google `AIza…`). The bare
872
+ // `sk-` body is intentionally generic so an unrecognised vendor's `sk-` key
873
+ // (e.g. DeepSeek `sk-<hex>`, OpenRouter `sk-or-…`) is still caught by shape,
874
+ // not left to the narrowed entropy catch-all below.
875
+ regex: /\b(?:sk-[A-Za-z0-9_-]{16,}|xox[baprs]-[A-Za-z0-9-]{8,}|AIza[A-Za-z0-9_-]{8,})/i
811
876
  },
812
877
  { reason: "signed_url", regex: /[?&](?:X-Amz-Signature|X-Amz-Credential|X-Amz-Algorithm|AWSAccessKeyId)=/i },
813
878
  { reason: "object_store_key", regex: /(^|[\s"'`])(?:runs|assets)\/[^?<#\s"'`]+/i },
@@ -816,8 +881,59 @@ var forbiddenStringPatterns = Object.freeze([
816
881
  reason: "private_resource_handle",
817
882
  regex: /\b(?:machine|session|agent|file|skill|env|resource|handle|token_hash|bearer_hash)[_:-][A-Za-z0-9][A-Za-z0-9_-]{7,}\b/i
818
883
  },
819
- { reason: "high_entropy_token", regex: /\b(?=[A-Za-z0-9_-]{40,}\b)(?=.*[A-Za-z])(?=.*\d)[A-Za-z0-9_-]{40,}\b/ }
884
+ {
885
+ reason: "high_entropy_token",
886
+ // Catch-all for an unrecognised opaque secret blob. The candidate run
887
+ // EXCLUDES `_` (so `SCREAMING_SNAKE` env names and `slug_with_words` URL
888
+ // segments split instead of fusing into a phantom 40-char run — the live
889
+ // false positive was `ted_season_2_peacock_official_discussion_thread` in
890
+ // web-search result text and a fetched URL), and the `accept` predicate
891
+ // vetoes content-addressed hashes (md5/sha1/sha256 digests — the platform's
892
+ // OWN asset filenames) and low-entropy / single-class runs so only genuine
893
+ // opaque secrets remain. Slash-bearing secrets (signed URLs, connection
894
+ // strings, `Bearer …`) are covered by the named patterns above.
895
+ regex: /\b[A-Za-z0-9-]{40,}\b/,
896
+ accept: isHighEntropySecretRun
897
+ }
820
898
  ]);
899
+ var CONTENT_HASH_RUN = /^(?:[0-9a-f]{32}|[0-9a-f]{40}|[0-9a-f]{64})$/i;
900
+ function isHighEntropySecretRun(run) {
901
+ if (CONTENT_HASH_RUN.test(run)) {
902
+ return false;
903
+ }
904
+ if (!/[A-Za-z]/.test(run) || !/\d/.test(run)) {
905
+ return false;
906
+ }
907
+ if (highEntropyCharClassCount(run) < 2) {
908
+ return false;
909
+ }
910
+ return highEntropyShannonBits(run) >= 3;
911
+ }
912
+ function highEntropyCharClassCount(value) {
913
+ let count = 0;
914
+ if (/[a-z]/.test(value))
915
+ count++;
916
+ if (/[A-Z]/.test(value))
917
+ count++;
918
+ if (/[0-9]/.test(value))
919
+ count++;
920
+ return count;
921
+ }
922
+ function highEntropyShannonBits(value) {
923
+ if (value.length === 0) {
924
+ return 0;
925
+ }
926
+ const counts = /* @__PURE__ */ new Map();
927
+ for (const char of value) {
928
+ counts.set(char, (counts.get(char) ?? 0) + 1);
929
+ }
930
+ let bits = 0;
931
+ for (const count of counts.values()) {
932
+ const p = count / value.length;
933
+ bits -= p * Math.log2(p);
934
+ }
935
+ return bits;
936
+ }
821
937
  function isForbiddenCustodyFieldName(key) {
822
938
  return /^(apiKey|secretValue|bearerHash|signedUrl|objectStoreKey|objectKey|vaultId|providerResponseBody|responseBody|privateResourceHandle|resourceHandle|rawBody)$/i.test(key);
823
939
  }
@@ -1246,11 +1362,13 @@ __export(operations_exports, {
1246
1362
  createAgentsMd: () => createAgentsMd,
1247
1363
  createFile: () => createFile,
1248
1364
  createOutputLink: () => createOutputLink,
1365
+ createSecret: () => createSecret,
1249
1366
  createSkillBundle: () => createSkillBundle,
1250
1367
  createSkillBundleDirect: () => createSkillBundleDirect,
1251
1368
  deleteAgentsMd: () => deleteAgentsMd,
1252
1369
  deleteFile: () => deleteFile,
1253
1370
  deleteRun: () => deleteRun,
1371
+ deleteSecret: () => deleteSecret,
1254
1372
  deleteSkill: () => deleteSkill,
1255
1373
  deleteWorkspaceAsset: () => deleteWorkspaceAsset,
1256
1374
  download: () => download,
@@ -1265,13 +1383,17 @@ __export(operations_exports, {
1265
1383
  getFile: () => getFile,
1266
1384
  getRun: () => getRun,
1267
1385
  getRunUnit: () => getRunUnit,
1386
+ getSecret: () => getSecret,
1268
1387
  getSkill: () => getSkill,
1269
1388
  listAgentsMd: () => listAgentsMd,
1270
1389
  listFiles: () => listFiles,
1271
1390
  listOutputs: () => listOutputs,
1272
1391
  listRunEvents: () => listRunEvents,
1392
+ listSecrets: () => listSecrets,
1273
1393
  listSkills: () => listSkills,
1274
1394
  resolveOutputFileSelector: () => resolveOutputFileSelector,
1395
+ revealSecret: () => revealSecret,
1396
+ rotateSecret: () => rotateSecret,
1275
1397
  submitRun: () => submitRun,
1276
1398
  submitRunMultipart: () => submitRunMultipart,
1277
1399
  uploadWorkspaceAsset: () => uploadWorkspaceAsset,
@@ -2380,6 +2502,44 @@ function unwrapFile(result) {
2380
2502
  }
2381
2503
  return result;
2382
2504
  }
2505
+ async function createSecret(http, args) {
2506
+ const result = await http.request("/api/secrets", {
2507
+ method: "POST",
2508
+ body: JSON.stringify({ name: args.name, value: args.value })
2509
+ });
2510
+ return unwrapSecret(result);
2511
+ }
2512
+ async function listSecrets(http) {
2513
+ const result = await http.request("/api/secrets");
2514
+ if (Array.isArray(result)) {
2515
+ return result;
2516
+ }
2517
+ return result.secrets;
2518
+ }
2519
+ async function getSecret(http, name) {
2520
+ const result = await http.request(`/api/secrets/${encodeURIComponent(name)}`);
2521
+ return unwrapSecret(result);
2522
+ }
2523
+ async function revealSecret(http, name) {
2524
+ return http.request(`/api/secrets/${encodeURIComponent(name)}/reveal`, {
2525
+ method: "POST"
2526
+ });
2527
+ }
2528
+ async function rotateSecret(http, args) {
2529
+ const result = await http.request(`/api/secrets/${encodeURIComponent(args.name)}/rotate`, { method: "POST", body: JSON.stringify({ value: args.value }) });
2530
+ return unwrapSecret(result);
2531
+ }
2532
+ async function deleteSecret(http, name) {
2533
+ await http.request(`/api/secrets/${encodeURIComponent(name)}`, {
2534
+ method: "DELETE"
2535
+ });
2536
+ }
2537
+ function unwrapSecret(result) {
2538
+ if (result && typeof result === "object" && "secret" in result) {
2539
+ return result.secret;
2540
+ }
2541
+ return result;
2542
+ }
2383
2543
  function unwrapSkill(result) {
2384
2544
  if (result && typeof result === "object" && "skill" in result) {
2385
2545
  return result.skill;
@@ -1 +1 @@
1
- 479aa815e56005b54f89791ddaac4e41b564ffc377e3077deb11258dba46aaf5 cli.mjs
1
+ d05e5e074b577553d20fa3680f834b7941fe0cb7692c0a743975fcf36c4ec9b5 cli.mjs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aexhq/cli",
3
- "version": "0.19.0",
3
+ "version": "0.21.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/aexhq/aex.git"
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "fflate": "^0.8.2",
30
- "@aexhq/contracts": "0.19.0"
30
+ "@aexhq/contracts": "0.21.0"
31
31
  },
32
32
  "devDependencies": {
33
33
  "esbuild": "^0.28.0"