getagenthook 0.2.1 → 1.0.1
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 +29 -3
- package/dist/cli.js +4 -2
- package/dist/commands/run.js +27 -34
- package/dist/commands/tools.js +7 -4
- package/dist/flags.js +38 -0
- package/dist/http.js +2 -1
- package/dist/main.js +0 -0
- package/dist/schema-snapshot.js +30 -4
- package/dist/schemas.js +21 -5
- package/dist/validate.js +16 -60
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# agenthook
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/getagenthook)
|
|
4
|
+
|
|
3
5
|
CLI for the AgentHook hosted media-generation API. Built for agents:
|
|
4
6
|
progress goes to stderr, output URLs go to stdout, exit codes are meaningful.
|
|
5
7
|
|
|
@@ -10,7 +12,7 @@ agenthook login --key <your-api-key>
|
|
|
10
12
|
agenthook tools
|
|
11
13
|
agenthook run make_video --prompt "A barista holds a latte and says: try our new oat flat white" --quality pro --aspect-ratio 9:16 --captions
|
|
12
14
|
agenthook run make_image --prompt "studio shot of a ceramic mug" --count 2
|
|
13
|
-
agenthook run caption_video --video-url https://…/video.mp4 --style
|
|
15
|
+
agenthook run caption_video --video-url https://…/video.mp4 --style chunk
|
|
14
16
|
agenthook list --search "flat white"
|
|
15
17
|
agenthook balance
|
|
16
18
|
agenthook history
|
|
@@ -18,7 +20,7 @@ agenthook history
|
|
|
18
20
|
|
|
19
21
|
- Credentials live at `~/.agenthook/credentials.json` (chmod 600).
|
|
20
22
|
- API base: `--api-url` flag > `AGENTHOOK_API_URL` env > stored value >
|
|
21
|
-
`https://
|
|
23
|
+
`https://getagenthook.com`; all requests hit `<base>/api/v1/…`.
|
|
22
24
|
- Reference images (`--ref`, repeatable) require `--owns-references`: you attest
|
|
23
25
|
you own, or have the rights to use, the likeness of every person appearing in
|
|
24
26
|
the referenced images.
|
|
@@ -27,4 +29,28 @@ agenthook history
|
|
|
27
29
|
submitted: consent, prompt length caps, enum values, ranges, and
|
|
28
30
|
`nano-banana-2` (edit-only) without references.
|
|
29
31
|
|
|
30
|
-
|
|
32
|
+
## MCP server
|
|
33
|
+
|
|
34
|
+
If your agent speaks MCP, it can call AgentHook directly instead of going through
|
|
35
|
+
the CLI. The server ships as `@getagenthook/mcp` and runs over `npx`. Add this to
|
|
36
|
+
your MCP client config (Claude Code, Cursor, and similar):
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"mcpServers": {
|
|
41
|
+
"agenthook": {
|
|
42
|
+
"command": "npx",
|
|
43
|
+
"args": ["-y", "@getagenthook/mcp"],
|
|
44
|
+
"env": { "AGENTHOOK_API_KEY": "ah_your_key" }
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
It exposes `make_video`, `make_image`, `caption_video`, and `create_influencer`,
|
|
51
|
+
plus `get_run`. The generation tools return a `run_id`; pass it to `get_run` to
|
|
52
|
+
fetch the finished URL once the job is done.
|
|
53
|
+
|
|
54
|
+
## Develop
|
|
55
|
+
|
|
56
|
+
`npm run build` (emits `dist/`), `npx vitest run`, `npx tsc --noEmit`.
|
package/dist/cli.js
CHANGED
|
@@ -33,8 +33,10 @@ Commands:
|
|
|
33
33
|
Run flags:
|
|
34
34
|
--prompt <text> --ref <url> (repeatable) --owns-references --model <m>
|
|
35
35
|
--quality <standard|pro> --duration <s> --aspect-ratio <r> --no-audio
|
|
36
|
-
--captions --caption-style <
|
|
37
|
-
--
|
|
36
|
+
--captions --caption-style <chunk|highlight|subtitle> --caption-size <small|medium|large>
|
|
37
|
+
--caption-placement <top|center|bottom> --enhance-prompt
|
|
38
|
+
--video-url <url> --style <chunk|highlight|subtitle> --size <small|medium|large>
|
|
39
|
+
--placement <top|center|bottom> --count <n> --resolution <1k|2k|4k>
|
|
38
40
|
--dry-run price + validate against the server without spending credits
|
|
39
41
|
|
|
40
42
|
Auth: pass --key, set AGENTHOOK_API_KEY, or run auth:login (precedence: flag > env > file).
|
package/dist/commands/run.js
CHANGED
|
@@ -38,36 +38,12 @@ const crypto = __importStar(require("node:crypto"));
|
|
|
38
38
|
const args_1 = require("../args");
|
|
39
39
|
const config_1 = require("../config");
|
|
40
40
|
const exit_1 = require("../exit");
|
|
41
|
+
const flags_1 = require("../flags");
|
|
41
42
|
const http_1 = require("../http");
|
|
42
43
|
const jobs_1 = require("../jobs");
|
|
43
44
|
const schemas_1 = require("../schemas");
|
|
44
45
|
const types_1 = require("../types");
|
|
45
46
|
const validate_1 = require("../validate");
|
|
46
|
-
const RUN_FLAGS = {
|
|
47
|
-
"api-url": "string",
|
|
48
|
-
key: "string",
|
|
49
|
-
json: "boolean",
|
|
50
|
-
"dry-run": "boolean",
|
|
51
|
-
prompt: "string",
|
|
52
|
-
ref: "array",
|
|
53
|
-
"owns-references": "boolean",
|
|
54
|
-
model: "string",
|
|
55
|
-
quality: "string",
|
|
56
|
-
duration: "number",
|
|
57
|
-
"aspect-ratio": "string",
|
|
58
|
-
"no-audio": "boolean",
|
|
59
|
-
captions: "boolean",
|
|
60
|
-
"caption-style": "string",
|
|
61
|
-
"enhance-prompt": "boolean",
|
|
62
|
-
"video-url": "string",
|
|
63
|
-
style: "string",
|
|
64
|
-
count: "number",
|
|
65
|
-
resolution: "string",
|
|
66
|
-
language: "string",
|
|
67
|
-
name: "string",
|
|
68
|
-
slug: "string",
|
|
69
|
-
influencer: "string",
|
|
70
|
-
};
|
|
71
47
|
// Poll cadence: 5s (spec); overridable for tests. Every watcher gets a
|
|
72
48
|
// give-up (donor rule): a wall-clock deadline + bounded consecutive misses.
|
|
73
49
|
const pollIntervalMs = () => Number(process.env.AGENTHOOK_POLL_MS || 5000);
|
|
@@ -77,7 +53,14 @@ const MAX_POLL_MISSES = 5;
|
|
|
77
53
|
// submit must never double-charge; the server dedupes on the key).
|
|
78
54
|
const SUBMIT_RETRIES = 1;
|
|
79
55
|
async function run(argv) {
|
|
80
|
-
|
|
56
|
+
// Flags are DERIVED from the live tool schema (so a new API param is a usable
|
|
57
|
+
// flag without a CLI upgrade), and the schema source is per-api-url — so the
|
|
58
|
+
// api-url is pulled from argv BEFORE the full parse, the schema is resolved,
|
|
59
|
+
// then the flag spec is built to parse against.
|
|
60
|
+
const apiUrl = (0, config_1.resolveApiUrl)(preScanApiUrl(argv));
|
|
61
|
+
const schemas = await (0, schemas_1.resolveRunSchemas)(apiUrl);
|
|
62
|
+
const { spec, paramForFlag, flagFor } = (0, flags_1.deriveRunFlags)(schemas);
|
|
63
|
+
const { positionals, flags, errors } = (0, args_1.parseArgs)(argv, spec);
|
|
81
64
|
if (errors.length) {
|
|
82
65
|
errors.forEach((e) => console.error(e));
|
|
83
66
|
return exit_1.EXIT.GENERIC;
|
|
@@ -88,19 +71,16 @@ async function run(argv) {
|
|
|
88
71
|
console.error("Usage: agenthook run <tool> [flags] — see `agenthook tools`");
|
|
89
72
|
return exit_1.EXIT.GENERIC;
|
|
90
73
|
}
|
|
91
|
-
const apiUrl = (0, config_1.resolveApiUrl)(flags["api-url"]);
|
|
92
74
|
const key = (0, config_1.resolveApiKey)(flags["key"]);
|
|
93
75
|
if (!key) {
|
|
94
76
|
emitError(asJson, "Not logged in — run `agenthook auth:login` first.", exit_1.EXIT.AUTH);
|
|
95
77
|
return exit_1.EXIT.AUTH;
|
|
96
78
|
}
|
|
97
|
-
// Deterministic pre-validation BEFORE
|
|
98
|
-
//
|
|
99
|
-
//
|
|
100
|
-
|
|
101
|
-
const
|
|
102
|
-
const input = (0, validate_1.buildToolInput)(flags);
|
|
103
|
-
const problems = (0, validate_1.preValidate)(tool, input, schemas);
|
|
79
|
+
// Deterministic pre-validation BEFORE the run is submitted (spec §3): every
|
|
80
|
+
// locally-checkable rule the server would 400 on. The server re-validates
|
|
81
|
+
// authoritatively on submit.
|
|
82
|
+
const input = (0, validate_1.buildToolInput)(flags, paramForFlag);
|
|
83
|
+
const problems = (0, validate_1.preValidate)(tool, input, schemas, flagFor);
|
|
104
84
|
if (problems.length) {
|
|
105
85
|
if (asJson)
|
|
106
86
|
emitError(true, problems.join("; "), exit_1.EXIT.VALIDATION);
|
|
@@ -231,6 +211,19 @@ async function submitWithRetry(apiUrl, tool, input, key, idempotencyKey) {
|
|
|
231
211
|
}
|
|
232
212
|
}
|
|
233
213
|
}
|
|
214
|
+
/** Pull --api-url out of raw argv before the flag spec exists (spec derivation
|
|
215
|
+
* needs the schema, fetched per api-url). Mirrors parseArgs' two forms; full
|
|
216
|
+
* precedence (flag > env > file > default) is applied by resolveApiUrl. */
|
|
217
|
+
function preScanApiUrl(argv) {
|
|
218
|
+
for (let i = 0; i < argv.length; i++) {
|
|
219
|
+
const a = argv[i];
|
|
220
|
+
if (a === "--api-url")
|
|
221
|
+
return argv[i + 1];
|
|
222
|
+
if (a.startsWith("--api-url="))
|
|
223
|
+
return a.slice("--api-url=".length);
|
|
224
|
+
}
|
|
225
|
+
return undefined;
|
|
226
|
+
}
|
|
234
227
|
const topUpUrl = (apiUrl) => `${apiUrl}/credits`;
|
|
235
228
|
/** Machine JSON to stdout (one object per line, ndjson). */
|
|
236
229
|
function emit(obj) {
|
package/dist/commands/tools.js
CHANGED
|
@@ -4,9 +4,9 @@ exports.tools = tools;
|
|
|
4
4
|
const args_1 = require("../args");
|
|
5
5
|
const config_1 = require("../config");
|
|
6
6
|
const exit_1 = require("../exit");
|
|
7
|
+
const flags_1 = require("../flags");
|
|
7
8
|
const json_error_1 = require("../json-error");
|
|
8
9
|
const schemas_1 = require("../schemas");
|
|
9
|
-
const validate_1 = require("../validate");
|
|
10
10
|
async function tools(argv) {
|
|
11
11
|
const { flags, errors } = (0, args_1.parseArgs)(argv, { "api-url": "string", key: "string", json: "boolean" });
|
|
12
12
|
if (errors.length) {
|
|
@@ -22,10 +22,13 @@ async function tools(argv) {
|
|
|
22
22
|
console.log(JSON.stringify({ tools: schemas }));
|
|
23
23
|
return exit_1.EXIT.OK;
|
|
24
24
|
}
|
|
25
|
+
// Same derivation `run` parses against — the flag spelling shown here is
|
|
26
|
+
// exactly the one that will work.
|
|
27
|
+
const { flagFor } = (0, flags_1.deriveRunFlags)(schemas);
|
|
25
28
|
for (const tool of schemas) {
|
|
26
29
|
console.log(`${tool.name} — ${tool.description}`);
|
|
27
30
|
for (const [name, spec] of Object.entries(tool.params)) {
|
|
28
|
-
console.log(` ${renderParam(name, spec)}`);
|
|
31
|
+
console.log(` ${renderParam(name, spec, flagFor)}`);
|
|
29
32
|
}
|
|
30
33
|
console.log("");
|
|
31
34
|
}
|
|
@@ -33,8 +36,8 @@ async function tools(argv) {
|
|
|
33
36
|
return exit_1.EXIT.OK;
|
|
34
37
|
});
|
|
35
38
|
}
|
|
36
|
-
function renderParam(name, spec) {
|
|
37
|
-
const flagName =
|
|
39
|
+
function renderParam(name, spec, flagFor) {
|
|
40
|
+
const flagName = flagFor[name] ?? `--${name.replace(/_/g, "-")}`;
|
|
38
41
|
const hint = spec.type === "boolean"
|
|
39
42
|
? ""
|
|
40
43
|
: spec.enum
|
package/dist/flags.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FLAG_ALIAS = exports.CLI_FLAGS = void 0;
|
|
4
|
+
exports.deriveRunFlags = deriveRunFlags;
|
|
5
|
+
/** Flags that are NOT tool params and must always parse (any command shape). */
|
|
6
|
+
exports.CLI_FLAGS = {
|
|
7
|
+
"api-url": "string",
|
|
8
|
+
key: "string",
|
|
9
|
+
json: "boolean",
|
|
10
|
+
"dry-run": "boolean",
|
|
11
|
+
};
|
|
12
|
+
/** The two places the CLI flag intentionally differs from a mechanical
|
|
13
|
+
* snake→kebab of the param name (everything else is derived). */
|
|
14
|
+
exports.FLAG_ALIAS = {
|
|
15
|
+
reference_images: { flag: "ref" },
|
|
16
|
+
audio: { flag: "no-audio", invertBoolean: true }, // --no-audio sets audio:false
|
|
17
|
+
};
|
|
18
|
+
const FLAG_TYPES = ["string", "number", "boolean", "array"];
|
|
19
|
+
/** Union every tool's params into the run flag spec + flag⇄param maps. Params
|
|
20
|
+
* repeat across tools (same flag name each time) — the union is idempotent. */
|
|
21
|
+
function deriveRunFlags(schemas) {
|
|
22
|
+
const spec = { ...exports.CLI_FLAGS };
|
|
23
|
+
const paramForFlag = {};
|
|
24
|
+
const flagFor = {};
|
|
25
|
+
for (const schema of schemas) {
|
|
26
|
+
for (const [param, p] of Object.entries(schema.params)) {
|
|
27
|
+
const alias = exports.FLAG_ALIAS[param];
|
|
28
|
+
const flag = alias?.flag ?? param.replace(/_/g, "-");
|
|
29
|
+
let type = FLAG_TYPES.includes(p.type) ? p.type : "string";
|
|
30
|
+
if (alias?.invertBoolean)
|
|
31
|
+
type = "boolean";
|
|
32
|
+
spec[flag] = type;
|
|
33
|
+
paramForFlag[flag] = { param, invert: alias?.invertBoolean };
|
|
34
|
+
flagFor[param] = "--" + flag;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return { spec, paramForFlag, flagFor };
|
|
38
|
+
}
|
package/dist/http.js
CHANGED
|
@@ -5,6 +5,7 @@ exports.timeoutSignal = timeoutSignal;
|
|
|
5
5
|
exports.api = api;
|
|
6
6
|
exports.describeApiError = describeApiError;
|
|
7
7
|
const config_1 = require("./config");
|
|
8
|
+
const version_1 = require("./version");
|
|
8
9
|
// Timeout policy mirrors the frozen packages/core/net.ts (DEFAULT_TIMEOUT_MS +
|
|
9
10
|
// AbortSignal.timeout). Duplicated here because the published CLI cannot
|
|
10
11
|
// runtime-import workspace TypeScript; test/parity.test.ts pins the value.
|
|
@@ -36,7 +37,7 @@ async function api(apiUrl, pathname, opts = {}) {
|
|
|
36
37
|
if (v !== undefined && v !== "")
|
|
37
38
|
url.searchParams.set(k, v);
|
|
38
39
|
}
|
|
39
|
-
const headers = { ...opts.headers };
|
|
40
|
+
const headers = { "user-agent": `agenthook-cli/${version_1.VERSION}`, ...opts.headers };
|
|
40
41
|
if (opts.key)
|
|
41
42
|
headers.authorization = `Bearer ${opts.key}`;
|
|
42
43
|
if (opts.body !== undefined)
|
package/dist/main.js
CHANGED
|
File without changes
|
package/dist/schema-snapshot.js
CHANGED
|
@@ -26,8 +26,23 @@ exports.TOOLS_SNAPSHOT = [
|
|
|
26
26
|
default: "9:16",
|
|
27
27
|
},
|
|
28
28
|
audio: { type: "boolean", default: true },
|
|
29
|
-
captions: {
|
|
30
|
-
|
|
29
|
+
captions: {
|
|
30
|
+
type: "boolean",
|
|
31
|
+
default: false,
|
|
32
|
+
description: "Burn spoken-word captions into the video. When true the run returns two files: output[0] is captioned, output[1] is the original uncaptioned video.",
|
|
33
|
+
},
|
|
34
|
+
caption_style: {
|
|
35
|
+
type: "string",
|
|
36
|
+
enum: ["chunk", "highlight", "subtitle"],
|
|
37
|
+
default: "chunk",
|
|
38
|
+
description: "Caption look. chunk = 2–4 words per line, centered, bold with a heavy outline (the standard TikTok/Reels style). highlight = the same block with the active word lit in colour (the Hormozi/retention style). subtitle = one clean line at the bottom (cinematic / YouTube).",
|
|
39
|
+
},
|
|
40
|
+
caption_size: { type: "string", enum: ["small", "medium", "large"], default: "medium", description: "Caption text size." },
|
|
41
|
+
caption_placement: {
|
|
42
|
+
type: "string",
|
|
43
|
+
enum: ["top", "center", "bottom"],
|
|
44
|
+
description: "Where captions sit. Defaults per style: chunk/highlight → center, subtitle → bottom.",
|
|
45
|
+
},
|
|
31
46
|
enhance_prompt: { type: "boolean", default: false },
|
|
32
47
|
influencer: {
|
|
33
48
|
type: "string",
|
|
@@ -62,10 +77,21 @@ exports.TOOLS_SNAPSHOT = [
|
|
|
62
77
|
},
|
|
63
78
|
{
|
|
64
79
|
name: "caption_video",
|
|
65
|
-
description: "Burn styled
|
|
80
|
+
description: "Burn styled captions into an existing video. Returns two files: output[0] is the captioned video, output[1] is the original uncaptioned video — so you can re-caption with a different style without regenerating. (A speechless video returns just the original.)",
|
|
66
81
|
params: {
|
|
67
82
|
video_url: { type: "string", required: true },
|
|
68
|
-
style: {
|
|
83
|
+
style: {
|
|
84
|
+
type: "string",
|
|
85
|
+
enum: ["chunk", "highlight", "subtitle"],
|
|
86
|
+
default: "chunk",
|
|
87
|
+
description: "Caption look. chunk = bold centered word blocks (standard TikTok/Reels). highlight = active word lit in colour (Hormozi/retention). subtitle = clean bottom line (cinematic / YouTube).",
|
|
88
|
+
},
|
|
89
|
+
size: { type: "string", enum: ["small", "medium", "large"], default: "medium", description: "Caption text size." },
|
|
90
|
+
placement: {
|
|
91
|
+
type: "string",
|
|
92
|
+
enum: ["top", "center", "bottom"],
|
|
93
|
+
description: "Where captions sit. Defaults per style: chunk/highlight → center, subtitle → bottom.",
|
|
94
|
+
},
|
|
69
95
|
language: { type: "string", default: "auto" },
|
|
70
96
|
},
|
|
71
97
|
},
|
package/dist/schemas.js
CHANGED
|
@@ -36,12 +36,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.TOOLS_CACHE_TTL_MS = void 0;
|
|
37
37
|
exports.toolsCachePath = toolsCachePath;
|
|
38
38
|
exports.getLocalToolSchemas = getLocalToolSchemas;
|
|
39
|
+
exports.resolveRunSchemas = resolveRunSchemas;
|
|
39
40
|
exports.getToolSchemas = getToolSchemas;
|
|
40
|
-
// Tool-schema source
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
//
|
|
41
|
+
// Tool-schema source. GET /v1/tools is the single live schema source, and
|
|
42
|
+
// `run` DERIVES its flags from it (a new API param is a usable flag with no CLI
|
|
43
|
+
// upgrade) via resolveRunSchemas: the cached fetch when fresh, a live keyless
|
|
44
|
+
// fetch on miss (public endpoint), and the bundled snapshot as the offline
|
|
45
|
+
// fallback — so it stays current online and still works offline. (This relaxes
|
|
46
|
+
// the original spec §3 "no network before submit" guarantee to a cached,
|
|
47
|
+
// at-most-hourly, keyless fetch — the cost of never-stale flags.)
|
|
45
48
|
const fs = __importStar(require("node:fs"));
|
|
46
49
|
const path = __importStar(require("node:path"));
|
|
47
50
|
const config_1 = require("./config");
|
|
@@ -72,6 +75,19 @@ function writeCache(cache) {
|
|
|
72
75
|
function getLocalToolSchemas(apiUrl) {
|
|
73
76
|
return readCache()[apiUrl]?.tools ?? schema_snapshot_1.TOOLS_SNAPSHOT;
|
|
74
77
|
}
|
|
78
|
+
/** Schema source for `run`'s flag derivation + pre-validation. Live-and-cached
|
|
79
|
+
* (GET /v1/tools is PUBLIC — no key) so a new tool param becomes a usable flag
|
|
80
|
+
* without a CLI upgrade; falls back to the last cache, then the bundled
|
|
81
|
+
* snapshot, so it never throws (offline / fresh install still work). The server
|
|
82
|
+
* re-validates authoritatively on submit. */
|
|
83
|
+
async function resolveRunSchemas(apiUrl) {
|
|
84
|
+
try {
|
|
85
|
+
return await getToolSchemas(apiUrl);
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return getLocalToolSchemas(apiUrl);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
75
91
|
/** Cached-first schema load. `fresh: true` (the `tools` command) always
|
|
76
92
|
* refetches; otherwise a fresh cache entry short-circuits the network, and a
|
|
77
93
|
* stale one is the fallback when the API is unreachable (the server re-checks
|
package/dist/validate.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.OWNS_REFERENCES_CONSENT = exports.PROMPT_CAPS = void 0;
|
|
4
4
|
exports.buildToolInput = buildToolInput;
|
|
5
5
|
exports.preValidate = preValidate;
|
|
6
6
|
// Per-model prompt caps, mirroring packages/core/models.ts promptMax (frozen).
|
|
@@ -13,69 +13,25 @@ exports.PROMPT_CAPS = {
|
|
|
13
13
|
};
|
|
14
14
|
exports.OWNS_REFERENCES_CONSENT = "By passing --owns-references you attest that you own, or have the rights to use, " +
|
|
15
15
|
"the likeness of every person appearing in the referenced images.";
|
|
16
|
-
/** CLI
|
|
17
|
-
*
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
model: "--model",
|
|
23
|
-
quality: "--quality",
|
|
24
|
-
duration: "--duration",
|
|
25
|
-
aspect_ratio: "--aspect-ratio",
|
|
26
|
-
audio: "--no-audio",
|
|
27
|
-
captions: "--captions",
|
|
28
|
-
caption_style: "--caption-style",
|
|
29
|
-
enhance_prompt: "--enhance-prompt",
|
|
30
|
-
video_url: "--video-url",
|
|
31
|
-
style: "--style",
|
|
32
|
-
count: "--count",
|
|
33
|
-
resolution: "--resolution",
|
|
34
|
-
language: "--language",
|
|
35
|
-
name: "--name",
|
|
36
|
-
slug: "--slug",
|
|
37
|
-
influencer: "--influencer",
|
|
38
|
-
};
|
|
39
|
-
/** Map parsed CLI flags onto the tool-input body the API expects. Only flags
|
|
40
|
-
* the user actually passed are included, so server defaults stay in charge. */
|
|
41
|
-
function buildToolInput(flags) {
|
|
16
|
+
/** Map parsed CLI flags onto the tool-input body the API expects, using the
|
|
17
|
+
* flag→param map derived from the tool schema (see flags.ts). Only flags the
|
|
18
|
+
* user actually passed are present in `flags`, so server defaults stay in
|
|
19
|
+
* charge; a global CLI flag (api-url/key/json/dry-run) has no param and is
|
|
20
|
+
* skipped. The one non-direct case is `--no-audio` inverting to audio:false. */
|
|
21
|
+
function buildToolInput(flags, paramForFlag) {
|
|
42
22
|
const input = {};
|
|
43
|
-
const
|
|
44
|
-
[
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
[
|
|
48
|
-
["aspect-ratio", "aspect_ratio"],
|
|
49
|
-
["caption-style", "caption_style"],
|
|
50
|
-
["video-url", "video_url"],
|
|
51
|
-
["style", "style"],
|
|
52
|
-
["count", "count"],
|
|
53
|
-
["resolution", "resolution"],
|
|
54
|
-
["language", "language"],
|
|
55
|
-
["name", "name"],
|
|
56
|
-
["slug", "slug"],
|
|
57
|
-
["influencer", "influencer"],
|
|
58
|
-
];
|
|
59
|
-
for (const [flag, param] of direct) {
|
|
60
|
-
if (flags[flag] !== undefined)
|
|
61
|
-
input[param] = flags[flag];
|
|
23
|
+
for (const [flag, value] of Object.entries(flags)) {
|
|
24
|
+
const mapping = paramForFlag[flag];
|
|
25
|
+
if (!mapping)
|
|
26
|
+
continue; // a global CLI flag, not a tool param
|
|
27
|
+
input[mapping.param] = mapping.invert ? !value : value;
|
|
62
28
|
}
|
|
63
|
-
const refs = flags["ref"];
|
|
64
|
-
if (refs?.length)
|
|
65
|
-
input.reference_images = refs;
|
|
66
|
-
if (flags["owns-references"])
|
|
67
|
-
input.owns_references = true;
|
|
68
|
-
if (flags["no-audio"])
|
|
69
|
-
input.audio = false;
|
|
70
|
-
if (flags["captions"])
|
|
71
|
-
input.captions = true;
|
|
72
|
-
if (flags["enhance-prompt"])
|
|
73
|
-
input.enhance_prompt = true;
|
|
74
29
|
return input;
|
|
75
30
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
function preValidate(tool, input, schemas) {
|
|
31
|
+
/** Returns human-readable problems (empty array = locally valid). `flagFor`
|
|
32
|
+
* (derived from the schema) supplies the CLI flag spelling for messages. */
|
|
33
|
+
function preValidate(tool, input, schemas, flagFor) {
|
|
34
|
+
const flag = (param) => flagFor[param] ?? "--" + param.replace(/_/g, "-");
|
|
79
35
|
const schema = schemas.find((s) => s.name === tool);
|
|
80
36
|
if (!schema) {
|
|
81
37
|
return [`Unknown tool "${tool}". Available tools: ${schemas.map((s) => s.name).join(", ")}`];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "getagenthook",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "CLI for the AgentHook hosted media-generation API — generate video, images, and captions from your terminal or agent.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://getagenthook.com",
|