@actionway/cli-dev 0.0.0-dev.32821683196.320940b928ff → 0.0.0-dev.32848766753.0e740c8908f1

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.
@@ -71,7 +71,7 @@ Right after a successful `actionway init`, run `actionway account wallet` once a
71
71
  - [Image Search](references/capabilities/image-search.md) (`web.image.search`) — Find visually similar or relevant existing images on the public web.
72
72
  - [Fetch URL](references/capabilities/fetch.md) (`web.fetch`) — Fetch a supported URL as text, Markdown, or bounded raw content.
73
73
  - [Search Stock Media](references/capabilities/stock-search.md) (`stock-media.search`) — Search one or more supported stock-media providers.
74
- - [Download Stock Media](references/capabilities/stock-download.md) (`stock-media.download`) — Download a selected stock-media result.
74
+ - [Download Stock Media](references/capabilities/stock-download.md) (`stock-media.download`) — Authorize a selected stock-media result for local download.
75
75
  - [Knowledge Search](references/capabilities/knowledge-search.md) (`knowledge.search`) — Search curated domain libraries for audio, visual, voice, writing, or meme references.
76
76
 
77
77
  **Live data**
@@ -7,6 +7,6 @@ Get standardized annual or quarterly company income statements.
7
7
 
8
8
  ## Indicative price
9
9
 
10
- free
10
+ $0.01
11
11
 
12
12
  Prices are indicative catalog values refreshed with each skill release. Before calling, Inspect the chosen variant: Inspect's input Schema and USD quote are authoritative.
@@ -7,6 +7,6 @@ Get the latest available market quote for one or more comma-separated symbols.
7
7
 
8
8
  ## Indicative price
9
9
 
10
- free
10
+ $0.01
11
11
 
12
12
  Prices are indicative catalog values refreshed with each skill release. Before calling, Inspect the chosen variant: Inspect's input Schema and USD quote are authoritative.
@@ -7,6 +7,6 @@ Search stocks and other market securities by name or symbol.
7
7
 
8
8
  ## Indicative price
9
9
 
10
- free
10
+ $0.01
11
11
 
12
12
  Prices are indicative catalog values refreshed with each skill release. Before calling, Inspect the chosen variant: Inspect's input Schema and USD quote are authoritative.
@@ -1,6 +1,6 @@
1
1
  # Download Stock Media (`stock-media.download`)
2
2
 
3
- Download a selected stock-media result.
3
+ Authorize a selected stock-media result for local download.
4
4
 
5
5
  - Users ask for it as: download a selected stock-media item; download stock image; download stock video.
6
6
  - Takes url, structured-data → returns image, video. Runs synchronously.
package/dist/index.js CHANGED
@@ -11460,15 +11460,12 @@ function registerKnowledgeCommands(program2, getTransport2) {
11460
11460
 
11461
11461
  // ../cli-core/src/commands/stock-download.ts
11462
11462
  import { randomUUID as randomUUID3 } from "node:crypto";
11463
- import { mkdir, writeFile } from "node:fs/promises";
11463
+ import { mkdir, rename, rm, writeFile } from "node:fs/promises";
11464
11464
  import { dirname, extname, isAbsolute as isAbsolute2 } from "node:path";
11465
11465
  var DEFAULT_DOWNLOAD_DIR = "/workspace/.stock-media";
11466
11466
  var FETCH_TIMEOUT_MS = 6e4;
11467
11467
  var MAX_DOWNLOAD_BYTES = 200 * 1024 * 1024;
11468
11468
  var ASSET_ID_RE = /^([a-z0-9_-]+):([a-zA-Z0-9_.-]+)$/;
11469
- function stockDownloadAvailable() {
11470
- return false;
11471
- }
11472
11469
  var MIME_TO_EXT = /* @__PURE__ */ new Map([
11473
11470
  ["image/jpeg", "jpg"],
11474
11471
  ["image/jpg", "jpg"],
@@ -11579,7 +11576,7 @@ async function fetchBytes(url) {
11579
11576
  clearTimeout(timer);
11580
11577
  }
11581
11578
  }
11582
- function registerStockDownload(parent) {
11579
+ function registerStockDownload(parent, deps) {
11583
11580
  parent.command("download").description("Fetch a stock-media asset (CDN URL from search result) into /workspace and echo full metadata.").addHelpText(
11584
11581
  "after",
11585
11582
  [
@@ -11589,19 +11586,12 @@ function registerStockDownload(parent) {
11589
11586
  "so the local result retains its source and license metadata."
11590
11587
  ].join("\n")
11591
11588
  ).requiredOption("--asset-id <id>", "<provider>:<native_id> from a search result").requiredOption("--url <url>", "direct CDN URL from search result's download_url").option("--to <path>", `absolute path under /workspace (default: ${DEFAULT_DOWNLOAD_DIR}/<provider>-<id>.<ext>)`).option("--metadata-json <json>", "JSON-encoded metadata object from the search result; echoed back in output").action(async (opts) => {
11592
- if (!stockDownloadAvailable()) {
11593
- fail({
11594
- code: "E_CAPABILITY_NOT_AVAILABLE",
11595
- message: "stock download is deferred until Gateway command-level billing is available",
11596
- hint: "do not fetch the asset directly as a workaround; wait for the stage-two stock billing integration"
11597
- });
11598
- }
11599
11589
  const { provider, nativeId } = parseAssetId(String(opts.assetId));
11600
11590
  const url = String(opts.url);
11601
11591
  try {
11602
11592
  const parsedUrl = new URL(url);
11603
- if (parsedUrl.protocol !== "https:" && parsedUrl.protocol !== "http:") {
11604
- fail({ code: "E_SCHEMA", message: `--url must be http(s); got protocol ${parsedUrl.protocol}` });
11593
+ if (parsedUrl.protocol !== "https:") {
11594
+ fail({ code: "E_SCHEMA", message: `--url must use https; got protocol ${parsedUrl.protocol}` });
11605
11595
  }
11606
11596
  } catch (err) {
11607
11597
  if (err.name === "TypeError") {
@@ -11618,7 +11608,22 @@ function registerStockDownload(parent) {
11618
11608
  const defaultPath = `${DEFAULT_DOWNLOAD_DIR}/${provider}-${nativeId}.${ext}`;
11619
11609
  const destination = explicitDestination ?? validateDestination(void 0, defaultPath);
11620
11610
  await mkdir(dirname(destination), { recursive: true });
11621
- await writeFile(destination, buf);
11611
+ const temporary = `${destination}.actionway-${jobRef}.tmp`;
11612
+ await writeFile(temporary, buf, { flag: "wx" });
11613
+ try {
11614
+ const transport = deps.getTransport();
11615
+ const body = { provider, native_id: nativeId, url, destination, kind: contentType?.startsWith("video/") ? "video" : "image" };
11616
+ if (deps.projectToolCall) {
11617
+ const response = await transport.callTool({ toolRef: "stock-media.download", arguments: body, idempotencyKey: jobRef, confirmation: { kind: "typed-command" } }, { jobRef, retries: 1 });
11618
+ if (response.status !== "completed") throw new StockDownloadError("stock download authorization did not complete");
11619
+ } else {
11620
+ await transport.post("internal/stock/download", body, { jobRef, retries: 1 });
11621
+ }
11622
+ await rename(temporary, destination);
11623
+ } catch (error) {
11624
+ await rm(temporary, { force: true });
11625
+ throw error;
11626
+ }
11622
11627
  ok({
11623
11628
  job_ref: jobRef,
11624
11629
  asset_id: `${provider}:${nativeId}`,
@@ -11900,9 +11905,6 @@ var STOCK_DEFAULT_PROVIDER_ORDER = ["pexels", "pixabay", "openverse"];
11900
11905
  var STOCK_ORIENTATIONS = ["landscape", "portrait", "square"];
11901
11906
  var STOCK_TYPES = ["image", "video"];
11902
11907
  var STOCK_MODES = ["fallback", "fanout"];
11903
- function isStockSearchAvailable() {
11904
- return false;
11905
- }
11906
11908
  function parsePositiveInt(raw, flag, max) {
11907
11909
  const n = Number(raw);
11908
11910
  if (!Number.isFinite(n) || !Number.isInteger(n) || n < 1 || n > max) {
@@ -11938,88 +11940,15 @@ function parseProviders(csv, type) {
11938
11940
  }
11939
11941
  return enabled;
11940
11942
  }
11941
- function describeProviderFailure(provider, err) {
11942
- if (err instanceof TransportError) {
11943
- return {
11944
- provider,
11945
- ...err.status !== void 0 ? { status: err.status } : {},
11946
- reason: `${err.status ?? "transport"}: ${err.message}`
11947
- };
11948
- }
11949
- if (err instanceof Error) return { provider, reason: err.message };
11950
- return { provider, reason: String(err) };
11951
- }
11952
- function mergeResults(perProvider, limit) {
11953
- const merged = [];
11954
- const seen = /* @__PURE__ */ new Set();
11955
- const cursors = perProvider.map(() => 0);
11956
- let active = perProvider.filter((arr) => arr.length > 0).length;
11957
- while (merged.length < limit && active > 0) {
11958
- active = 0;
11959
- for (let i = 0; i < perProvider.length; i++) {
11960
- const arr = perProvider[i];
11961
- const cursor = cursors[i];
11962
- if (arr === void 0 || cursor === void 0 || cursor >= arr.length) continue;
11963
- const r = arr[cursor];
11964
- cursors[i] = cursor + 1;
11965
- if (r !== void 0 && !seen.has(r.asset_id)) {
11966
- seen.add(r.asset_id);
11967
- merged.push(r);
11968
- if (merged.length >= limit) break;
11969
- }
11970
- if (cursor + 1 < arr.length) active += 1;
11971
- }
11972
- }
11973
- return merged;
11974
- }
11975
- async function searchSequential(enabled, opts, limit, searchFn) {
11976
- const collected = [];
11977
- const seen = /* @__PURE__ */ new Set();
11978
- const queried = [];
11979
- const failed = [];
11980
- for (const name of enabled) {
11981
- queried.push(name);
11982
- try {
11983
- const results = await searchFn(name, opts);
11984
- for (const r of results) {
11985
- if (!seen.has(r.asset_id)) {
11986
- seen.add(r.asset_id);
11987
- collected.push(r);
11988
- if (collected.length >= limit) break;
11989
- }
11990
- }
11991
- } catch (err) {
11992
- failed.push(describeProviderFailure(name, err));
11993
- }
11994
- if (collected.length >= limit) break;
11995
- }
11996
- return { results: collected.slice(0, limit), queried, failed };
11997
- }
11998
- async function searchFanout(enabled, opts, limit, searchFn) {
11999
- const settled = await Promise.allSettled(enabled.map((n) => searchFn(n, opts)));
12000
- const perProviderResults = [];
12001
- const failed = [];
12002
- for (let i = 0; i < enabled.length; i++) {
12003
- const r = settled[i];
12004
- const name = enabled[i];
12005
- if (r !== void 0 && r.status === "fulfilled") {
12006
- perProviderResults.push(r.value);
12007
- } else {
12008
- perProviderResults.push([]);
12009
- if (r !== void 0 && name !== void 0) failed.push(describeProviderFailure(name, r.reason));
12010
- }
12011
- }
12012
- return { results: mergeResults(perProviderResults, limit), queried: [...enabled], failed };
12013
- }
12014
- function registerStockSearch(parent, getTransport2) {
11943
+ function registerStockSearch(parent, deps) {
12015
11944
  parent.command("search").description(
12016
11945
  "Sequential-fallback search across providers (Pexels -> Pixabay -> Openverse). Use --mode=fanout for parallel."
12017
11946
  ).addHelpText(
12018
11947
  "after",
12019
11948
  [
12020
11949
  "",
12021
- "Availability:",
12022
- " Stage one is fail-closed until Gateway command-level billing orchestration is available.",
11950
+ "Execution:",
11951
+ " Gateway orchestrates all selected providers and bills the search once.",
12023
11952
  "",
12024
11953
  "Modes:",
12025
11954
  " fallback (default) - calls Pexels -> Pixabay -> Openverse in order and stops once limit results are collected.",
@@ -12048,13 +11977,6 @@ function registerStockSearch(parent, getTransport2) {
12048
11977
  `search strategy: ${STOCK_MODES.join(" | ")} (default fallback saves API budget)`,
12049
11978
  "fallback"
12050
11979
  ).action(async (opts) => {
12051
- if (!isStockSearchAvailable()) {
12052
- fail({
12053
- code: "E_CAPABILITY_NOT_AVAILABLE",
12054
- message: "stock search is not available in migration stage one",
12055
- hint: "Gateway command-level stock billing/orchestration is required before this command can be enabled."
12056
- });
12057
- }
12058
11980
  const type = String(opts.type);
12059
11981
  if (!STOCK_TYPES.includes(type)) {
12060
11982
  fail({ code: "E_SCHEMA", message: `--type must be image|video; got ${String(opts.type)}` });
@@ -12071,42 +11993,35 @@ function registerStockSearch(parent, getTransport2) {
12071
11993
  }
12072
11994
  const limit = typeof opts.limit === "number" ? opts.limit : 10;
12073
11995
  const enabled = parseProviders(opts.providers !== void 0 ? String(opts.providers) : void 0, type);
12074
- const perProviderLimit = mode === "fanout" ? Math.max(1, Math.ceil(limit * 1.5 / enabled.length)) : limit;
12075
11996
  const searchOpts = {
12076
11997
  query: String(opts.query),
12077
11998
  type,
12078
11999
  ...opts.orientation !== void 0 ? { orientation: String(opts.orientation) } : {},
12079
12000
  ...typeof opts.minWidth === "number" ? { minWidth: opts.minWidth } : {},
12080
12001
  ...typeof opts.durationMin === "number" ? { durationMin: opts.durationMin } : {},
12081
- ...typeof opts.durationMax === "number" ? { durationMax: opts.durationMax } : {},
12082
- perProviderLimit
12002
+ ...typeof opts.durationMax === "number" ? { durationMax: opts.durationMax } : {}
12083
12003
  };
12084
12004
  const jobRef = randomUUID4();
12085
12005
  try {
12086
- const transport = getTransport2();
12087
- const searchFn = (name, o) => {
12088
- const provider = ALL_PROVIDERS[name];
12089
- if (!provider) throw new Error(`unknown stock provider: ${name}`);
12090
- return provider.search(o, transport);
12091
- };
12092
- const { results, queried, failed } = mode === "fanout" ? await searchFanout(enabled, searchOpts, limit, searchFn) : await searchSequential(enabled, searchOpts, limit, searchFn);
12093
- if (results.length === 0 && failed.length > 0 && failed.length === queried.length) {
12094
- fail({
12095
- code: "E_BACKEND",
12096
- message: `all stock-media providers failed for "${String(opts.query)}"`,
12097
- hint: "check gateway provider routes / quota; see providers_failed for per-provider reason.",
12098
- extra: { job_ref: jobRef, mode, providers_queried: queried, providers_failed: failed }
12099
- });
12100
- }
12101
- ok({
12102
- job_ref: jobRef,
12006
+ const transport = deps.getTransport();
12007
+ const body = {
12103
12008
  query: searchOpts.query,
12104
12009
  type,
12105
12010
  mode,
12106
- results,
12107
- providers_queried: queried,
12108
- providers_failed: failed
12109
- });
12011
+ limit,
12012
+ providers: enabled,
12013
+ ...searchOpts.orientation ? { orientation: searchOpts.orientation } : {},
12014
+ ...searchOpts.minWidth !== void 0 ? { min_width: searchOpts.minWidth } : {},
12015
+ ...searchOpts.durationMin !== void 0 ? { duration_min: searchOpts.durationMin } : {},
12016
+ ...searchOpts.durationMax !== void 0 ? { duration_max: searchOpts.durationMax } : {}
12017
+ };
12018
+ if (deps.projectToolCall) {
12019
+ const response2 = await transport.callTool({ toolRef: "stock-media.search", arguments: body, idempotencyKey: jobRef, confirmation: { kind: "typed-command" } }, { jobRef, retries: 1 });
12020
+ if (response2.status !== "completed") return ok({ ...response2, job_ref: jobRef });
12021
+ return ok({ job_ref: jobRef, ...response2.result });
12022
+ }
12023
+ const response = await transport.post("internal/stock/search", body, { jobRef, retries: 1 });
12024
+ ok({ job_ref: jobRef, ...response });
12110
12025
  } catch (err) {
12111
12026
  if (err instanceof TransportError) {
12112
12027
  fail({ code: err.code, message: err.message, extra: { ...err.extra ?? {}, job_ref: jobRef } });
@@ -12121,10 +12036,11 @@ function registerStockSearch(parent, getTransport2) {
12121
12036
  }
12122
12037
 
12123
12038
  // ../cli-core/src/commands/stock.ts
12124
- function registerStockCommands(program2, getTransport2) {
12039
+ function registerStockCommands(program2, depsOrTransport) {
12040
+ const deps = typeof depsOrTransport === "function" ? { getTransport: depsOrTransport } : depsOrTransport;
12125
12041
  const stock = program2.command("stock").description("Search and download public stock media (Pexels / Pixabay / Openverse) for b-roll.");
12126
- registerStockSearch(stock, getTransport2);
12127
- registerStockDownload(stock);
12042
+ registerStockSearch(stock, deps);
12043
+ registerStockDownload(stock, deps);
12128
12044
  }
12129
12045
 
12130
12046
  // ../../node_modules/.pnpm/commander@12.1.0/node_modules/commander/esm.mjs
@@ -13993,7 +13909,7 @@ function buildProgram() {
13993
13909
  registerPollCommand(program2, getTransport2);
13994
13910
  registerKnowledgeCommands(program2, getTransport2);
13995
13911
  registerAssetCommands(program2, getTransport2);
13996
- registerStockCommands(program2, getTransport2);
13912
+ registerStockCommands(program2, actionDeps);
13997
13913
  return program2;
13998
13914
  }
13999
13915
  var invokedAsBin = isDirectExecution(import.meta.url);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@actionway/cli-dev",
3
- "version": "0.0.0-dev.32821683196.320940b928ff",
3
+ "version": "0.0.0-dev.32848766753.0e740c8908f1",
4
4
  "description": "Actionway development CLI for dev.actionway.ai",
5
5
  "type": "module",
6
6
  "bin": {
@@ -19,8 +19,8 @@
19
19
  "tsx": "^4.20.0",
20
20
  "typescript": "7.0.2",
21
21
  "vitest": "^3.2.7",
22
- "@actionway/contracts": "0.1.0",
23
- "@actionway/cli-core": "0.1.0"
22
+ "@actionway/cli-core": "0.1.0",
23
+ "@actionway/contracts": "0.1.0"
24
24
  },
25
25
  "engines": {
26
26
  "node": ">=20"
@@ -36,9 +36,9 @@
36
36
  },
37
37
  "actionway": {
38
38
  "channel": "development",
39
- "source_sha": "320940b928ff5d1dd7f858e5b4f5200ed2449c9f",
40
- "run_id": 32821683196,
41
- "run_url": "https://github.com/PawLogic/actionway/actions/runs/32821683196",
39
+ "source_sha": "0e740c8908f1097143ccd81e75990c6ab3bb9428",
40
+ "run_id": 32848766753,
41
+ "run_url": "https://github.com/PawLogic/actionway/actions/runs/32848766753",
42
42
  "gateway_url": "https://dev.actionway.ai"
43
43
  }
44
44
  }