hive-intelligence 1.6.7 → 1.7.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 +10 -4
- package/agent-skills/.claude-plugin/plugin.json +10 -0
- package/agent-skills/README.md +2 -0
- package/agent-skills/SKILL.md +18 -6
- package/agent-skills/evals/trigger-queries.json +70 -0
- package/agent-skills/package.json +3 -1
- package/agent-skills/packs/hive/SKILL.md +382 -0
- package/agent-skills/packs/hive/evals/evals.json +50 -0
- package/agent-skills/packs/hive/evals/triggers.json +15 -0
- package/agent-skills/packs/hive-build-onboarding/SKILL.md +1 -1
- package/agent-skills/packs/hive-cli/SKILL.md +2 -2
- package/agent-skills/packs/hive-mcp/SKILL.md +9 -5
- package/agent-skills/packs/hive-prediction-markets/SKILL.md +145 -0
- package/agent-skills/packs/hive-prediction-markets/evals/evals.json +29 -0
- package/agent-skills/packs/hive-prediction-markets/evals/triggers.json +14 -0
- package/agent-skills/packs/hive-query/SKILL.md +2 -1
- package/agent-skills/packs/hive-stateful-monitoring/SKILL.md +3 -3
- package/agent-skills/references/agents-routing.md +4 -1
- package/agent-skills/scripts/validate-agent-skills-package.mjs +2 -0
- package/agent-skills/skills.sh.json +9 -1
- package/build/{api-client-6AM3HVHQ.js → api-client-UGNFUZ2L.js} +12 -3
- package/build/{auth-4LPSQJXD.js → auth-5TLYP2DC.js} +1 -1
- package/build/call-args-NVOYX6DL.js +27 -0
- package/build/{chunk-G23ZAW36.js → chunk-2C5FBG7B.js} +3 -2
- package/build/{chunk-J2PXISXW.js → chunk-3SQPLZW6.js} +42810 -39335
- package/build/{chunk-S4HBVZ7O.js → chunk-3Z5VR53Z.js} +36 -7
- package/build/{chunk-GADPH72D.js → chunk-4QDGA6GP.js} +52 -1
- package/build/{chunk-2SPCKQBJ.js → chunk-5QAXJON7.js} +71 -0
- package/build/{chunk-GYVF75XB.js → chunk-FQNW6SZ6.js} +1 -1
- package/build/{chunk-LW2DHE32.js → chunk-L4KVJDA7.js} +1 -1
- package/build/chunk-POPAEM4E.js +474 -0
- package/build/{chunk-P7NLFSZQ.js → chunk-TWYGJEVN.js} +100 -9
- package/build/{chunk-32NRUWXA.js → chunk-UPWYFTTJ.js} +3 -3
- package/build/{chunk-KUF754NT.js → chunk-WII7MTYZ.js} +52 -12
- package/build/chunk-XN3T6YOG.js +32 -0
- package/build/chunk-XT6RURQV.js +394 -0
- package/build/{chunk-LP5ECG7A.js → chunk-ZDXMZPC6.js} +26 -2
- package/build/cli.js +120 -48
- package/build/{completion-YVSWWF6D.js → completion-ROZAH667.js} +1 -1
- package/build/{doctor-AM6QST7Z.js → doctor-44WSVNGJ.js} +42 -5
- package/build/{errors-EL6UMXNJ.js → errors-W3GXQN34.js} +7 -1
- package/build/feedback-FRRLZDAF.js +113 -0
- package/build/{init-all-54G3CVZA.js → init-all-LYRFE2YQ.js} +5 -5
- package/build/{mcpServer-NWOKFR7Q.js → mcpServer-43LTLURB.js} +2 -2
- package/build/monitor-worker.js +62 -10
- package/build/{namespace-PA2IDNRT.js → namespace-XMFFW47T.js} +1 -1
- package/build/{output-XGTE4EWJ.js → output-BBHBJI32.js} +5 -1
- package/build/release.json +4 -4
- package/build/routing-CP43PP5F.js +43 -0
- package/build/{serve-XRNMHIJX.js → serve-LTMDRKXS.js} +1 -1
- package/build/server.js +295 -41
- package/build/stdio.js +2 -2
- package/build/{tools-FNPMELSU.js → tools-VA7JXD3K.js} +81 -33
- package/build/{uninstall-P3JJZCXT.js → uninstall-3KJLHTNM.js} +26 -7
- package/build/{upgrade-ATIFZANV.js → upgrade-3NR3LAGU.js} +2 -2
- package/build/{watch-FG2C5Y2Z.js → watch-HJOTI32P.js} +5 -3
- package/package.json +1 -1
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
saveLastReceipt
|
|
4
|
+
} from "./chunk-XN3T6YOG.js";
|
|
2
5
|
import {
|
|
3
6
|
executeRemoteTool
|
|
4
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-TWYGJEVN.js";
|
|
5
8
|
import {
|
|
6
9
|
trackCommand
|
|
7
10
|
} from "./chunk-RU6QOFHH.js";
|
|
11
|
+
import {
|
|
12
|
+
ExitCode
|
|
13
|
+
} from "./chunk-3Z5VR53Z.js";
|
|
8
14
|
import {
|
|
9
15
|
debug,
|
|
10
16
|
dim,
|
|
17
|
+
isQuiet,
|
|
11
18
|
shouldOutputJson,
|
|
12
19
|
writeOutput
|
|
13
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-ZDXMZPC6.js";
|
|
14
21
|
import {
|
|
15
22
|
resolveApiKey
|
|
16
23
|
} from "./chunk-6PC3HUAK.js";
|
|
@@ -79,8 +86,38 @@ function remapForKeylessHero(toolName, args) {
|
|
|
79
86
|
}
|
|
80
87
|
|
|
81
88
|
// src/cli/execute.ts
|
|
89
|
+
var EXIT_CODE_BY_ERROR = {
|
|
90
|
+
TOOL_NOT_FOUND: ExitCode.TOOL_NOT_FOUND,
|
|
91
|
+
TOOL_RETIRED: ExitCode.TOOL_NOT_FOUND,
|
|
92
|
+
PROVIDER_UNAVAILABLE: ExitCode.AUTH_FAILURE,
|
|
93
|
+
RATE_LIMITED: ExitCode.RATE_LIMITED,
|
|
94
|
+
TIMEOUT: ExitCode.TIMEOUT,
|
|
95
|
+
// Cap lane (exit 6): the call is outside what this credential can do
|
|
96
|
+
// today; the human message carries the reset time.
|
|
97
|
+
ANON_QUOTA_EXCEEDED: ExitCode.RATE_LIMITED,
|
|
98
|
+
ANON_GLOBAL_CAP_EXCEEDED: ExitCode.RATE_LIMITED,
|
|
99
|
+
ANON_AUTH_REQUIRED: ExitCode.RATE_LIMITED,
|
|
100
|
+
QUOTA_EXCEEDED: ExitCode.RATE_LIMITED,
|
|
101
|
+
FEEDBACK_RATE_LIMITED: ExitCode.RATE_LIMITED,
|
|
102
|
+
// Account state, not a cap: no reset time, retrying cannot help.
|
|
103
|
+
NO_WALLET: ExitCode.API_ERROR
|
|
104
|
+
};
|
|
105
|
+
function exitCodeForError(code) {
|
|
106
|
+
return code && EXIT_CODE_BY_ERROR[code] || ExitCode.API_ERROR;
|
|
107
|
+
}
|
|
108
|
+
function creditFooter(meta, keyed) {
|
|
109
|
+
if (!meta) return null;
|
|
110
|
+
if (keyed) {
|
|
111
|
+
if (typeof meta.credits_used !== "number") return null;
|
|
112
|
+
const remaining = meta.credits_remaining === null ? "unlimited" : typeof meta.credits_remaining === "number" ? String(meta.credits_remaining) : null;
|
|
113
|
+
return remaining === null ? `credits: used ${meta.credits_used}` : `credits: used ${meta.credits_used}, remaining ${remaining}`;
|
|
114
|
+
}
|
|
115
|
+
if (typeof meta.quota_remaining !== "number") return null;
|
|
116
|
+
return `free calls left today: ${meta.quota_remaining} (run \`hive auth login\` for a full key)`;
|
|
117
|
+
}
|
|
82
118
|
async function executeTool(toolName, args, timeoutMs = 3e4) {
|
|
83
|
-
|
|
119
|
+
const keyed = Boolean(resolveApiKey());
|
|
120
|
+
if (!keyed) {
|
|
84
121
|
const remap = remapForKeylessHero(toolName, args);
|
|
85
122
|
if (remap) {
|
|
86
123
|
debug(remap.note);
|
|
@@ -106,17 +143,20 @@ async function executeTool(toolName, args, timeoutMs = 3e4) {
|
|
|
106
143
|
response.ok ? void 0 : response.error?.code
|
|
107
144
|
);
|
|
108
145
|
await writeOutput(response);
|
|
109
|
-
const
|
|
110
|
-
if (typeof
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
);
|
|
146
|
+
const receiptId = response.meta?.receipt_id;
|
|
147
|
+
if (response.ok && typeof receiptId === "string" && receiptId) {
|
|
148
|
+
saveLastReceipt({
|
|
149
|
+
receipt_id: receiptId,
|
|
150
|
+
tool: toolName,
|
|
151
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
const footer = creditFooter(response.meta, keyed);
|
|
155
|
+
if (footer && !shouldOutputJson() && !isQuiet()) {
|
|
156
|
+
process.stderr.write(dim(footer) + "\n");
|
|
116
157
|
}
|
|
117
158
|
if (!response.ok) {
|
|
118
|
-
|
|
119
|
-
process.exit(exitCode);
|
|
159
|
+
process.exit(exitCodeForError(response.error?.code));
|
|
120
160
|
}
|
|
121
161
|
}
|
|
122
162
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
ensureConfigDir,
|
|
4
|
+
getConfigDir,
|
|
5
|
+
readJsonFile,
|
|
6
|
+
writeJsonFile
|
|
7
|
+
} from "./chunk-6PC3HUAK.js";
|
|
8
|
+
|
|
9
|
+
// src/cli/last-receipt.ts
|
|
10
|
+
import { join } from "path";
|
|
11
|
+
function lastReceiptPath() {
|
|
12
|
+
return join(getConfigDir(), "last-receipt.json");
|
|
13
|
+
}
|
|
14
|
+
function saveLastReceipt(receipt) {
|
|
15
|
+
try {
|
|
16
|
+
ensureConfigDir();
|
|
17
|
+
writeJsonFile(lastReceiptPath(), receipt);
|
|
18
|
+
} catch {
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function readLastReceipt() {
|
|
22
|
+
const stored = readJsonFile(lastReceiptPath());
|
|
23
|
+
if (!stored || typeof stored.receipt_id !== "string" || typeof stored.tool !== "string" || typeof stored.at !== "string") {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
return { receipt_id: stored.receipt_id, tool: stored.tool, at: stored.at };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export {
|
|
30
|
+
saveLastReceipt,
|
|
31
|
+
readLastReceipt
|
|
32
|
+
};
|
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
CliError
|
|
4
|
+
} from "./chunk-3Z5VR53Z.js";
|
|
5
|
+
|
|
6
|
+
// src/cli/call-args.ts
|
|
7
|
+
var BOOLEAN_LITERALS = /* @__PURE__ */ new Set(["true", "false", "1", "0", "yes", "no"]);
|
|
8
|
+
function parseBooleanLiteral(value) {
|
|
9
|
+
const lower = value.toLowerCase();
|
|
10
|
+
if (!BOOLEAN_LITERALS.has(lower)) return null;
|
|
11
|
+
return lower === "true" || lower === "1" || lower === "yes";
|
|
12
|
+
}
|
|
13
|
+
function isFlagToken(token) {
|
|
14
|
+
return token.startsWith("--") && token.length > 2;
|
|
15
|
+
}
|
|
16
|
+
function parseFlagTokens(tokens, isBooleanFlag = () => false) {
|
|
17
|
+
const positionals = [];
|
|
18
|
+
const flags = [];
|
|
19
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
20
|
+
const token = tokens[i];
|
|
21
|
+
if (token === "--") {
|
|
22
|
+
positionals.push(...tokens.slice(i + 1));
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
if (!isFlagToken(token)) {
|
|
26
|
+
positionals.push(token);
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
const body = token.slice(2);
|
|
30
|
+
const eq = body.indexOf("=");
|
|
31
|
+
if (eq >= 0) {
|
|
32
|
+
const rawName = body.slice(0, eq);
|
|
33
|
+
const negated2 = rawName.startsWith("no-") && rawName.length > 3;
|
|
34
|
+
flags.push({
|
|
35
|
+
name: negated2 ? rawName.slice(3) : rawName,
|
|
36
|
+
value: body.slice(eq + 1),
|
|
37
|
+
negated: negated2,
|
|
38
|
+
raw: token
|
|
39
|
+
});
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const negated = body.startsWith("no-") && body.length > 3;
|
|
43
|
+
const name = negated ? body.slice(3) : body;
|
|
44
|
+
const next = tokens[i + 1];
|
|
45
|
+
let value;
|
|
46
|
+
if (next !== void 0 && next !== "--" && !isFlagToken(next)) {
|
|
47
|
+
if (negated) {
|
|
48
|
+
} else if (isBooleanFlag(name)) {
|
|
49
|
+
if (parseBooleanLiteral(next) !== null) {
|
|
50
|
+
value = next;
|
|
51
|
+
i++;
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
value = next;
|
|
55
|
+
i++;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
flags.push({ name, value, negated, raw: token });
|
|
59
|
+
}
|
|
60
|
+
return { positionals, flags };
|
|
61
|
+
}
|
|
62
|
+
function canonicalParamName(name) {
|
|
63
|
+
return name.toLowerCase().replace(/[-_]/g, "");
|
|
64
|
+
}
|
|
65
|
+
var ALWAYS_RESERVED_OPTIONS = [
|
|
66
|
+
"--help",
|
|
67
|
+
"--version",
|
|
68
|
+
"--profile",
|
|
69
|
+
"--args"
|
|
70
|
+
];
|
|
71
|
+
function reservedOptionNames(longFlags) {
|
|
72
|
+
const names = /* @__PURE__ */ new Set();
|
|
73
|
+
for (const flag of [...longFlags, ...ALWAYS_RESERVED_OPTIONS]) {
|
|
74
|
+
const name = flag.replace(/^--/, "");
|
|
75
|
+
names.add(name);
|
|
76
|
+
if (name.startsWith("no-")) names.add(name.slice(3));
|
|
77
|
+
}
|
|
78
|
+
return names;
|
|
79
|
+
}
|
|
80
|
+
function firstType(schema) {
|
|
81
|
+
if (!schema) return void 0;
|
|
82
|
+
if (Array.isArray(schema.type)) {
|
|
83
|
+
return schema.type.find((t) => t !== "null") ?? void 0;
|
|
84
|
+
}
|
|
85
|
+
return schema.type;
|
|
86
|
+
}
|
|
87
|
+
function isNestedSchema(schema) {
|
|
88
|
+
if (!schema) return false;
|
|
89
|
+
if (schema.$ref || schema.oneOf || schema.anyOf || schema.allOf) return true;
|
|
90
|
+
const type = firstType(schema);
|
|
91
|
+
if (type === "object" && schema.properties) return true;
|
|
92
|
+
if (type === "array" && schema.items) {
|
|
93
|
+
const itemType = firstType(schema.items);
|
|
94
|
+
return itemType === "object" || isNestedSchema(schema.items);
|
|
95
|
+
}
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
function buildResolver(schema) {
|
|
99
|
+
const properties = schema?.properties ?? {};
|
|
100
|
+
const required = new Set(schema?.required ?? []);
|
|
101
|
+
const byCanonical = /* @__PURE__ */ new Map();
|
|
102
|
+
for (const prop of Object.keys(properties)) {
|
|
103
|
+
const key = canonicalParamName(prop);
|
|
104
|
+
byCanonical.set(key, [...byCanonical.get(key) ?? [], prop]);
|
|
105
|
+
}
|
|
106
|
+
const resolve = (name) => {
|
|
107
|
+
if (name in properties) return name;
|
|
108
|
+
const candidates = byCanonical.get(canonicalParamName(name)) ?? [];
|
|
109
|
+
return candidates.length === 1 ? candidates[0] : null;
|
|
110
|
+
};
|
|
111
|
+
return {
|
|
112
|
+
resolve,
|
|
113
|
+
isBoolean: (name) => {
|
|
114
|
+
const prop = resolve(name);
|
|
115
|
+
return prop !== null && firstType(properties[prop]) === "boolean";
|
|
116
|
+
},
|
|
117
|
+
properties,
|
|
118
|
+
required
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function coerceScalar(raw, type, flag) {
|
|
122
|
+
switch (type) {
|
|
123
|
+
case "integer": {
|
|
124
|
+
if (!/^-?\d+$/.test(raw.trim())) {
|
|
125
|
+
throw new CliError(
|
|
126
|
+
"VALIDATION_ERROR",
|
|
127
|
+
`${flag} expects an integer, got '${raw}'`
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
return Number.parseInt(raw, 10);
|
|
131
|
+
}
|
|
132
|
+
case "number": {
|
|
133
|
+
const numeric = Number(raw);
|
|
134
|
+
if (raw.trim() === "" || !Number.isFinite(numeric)) {
|
|
135
|
+
throw new CliError(
|
|
136
|
+
"VALIDATION_ERROR",
|
|
137
|
+
`${flag} expects a number, got '${raw}'`
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
return numeric;
|
|
141
|
+
}
|
|
142
|
+
case "boolean": {
|
|
143
|
+
const parsed = parseBooleanLiteral(raw);
|
|
144
|
+
if (parsed === null) {
|
|
145
|
+
throw new CliError(
|
|
146
|
+
"VALIDATION_ERROR",
|
|
147
|
+
`${flag} expects true or false, got '${raw}'`
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
return parsed;
|
|
151
|
+
}
|
|
152
|
+
case "string":
|
|
153
|
+
return raw;
|
|
154
|
+
default: {
|
|
155
|
+
const trimmed = raw.trim();
|
|
156
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
157
|
+
try {
|
|
158
|
+
return JSON.parse(trimmed);
|
|
159
|
+
} catch {
|
|
160
|
+
return raw;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return raw;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function coerceArrayValue(raw, itemType, flag) {
|
|
168
|
+
const trimmed = raw.trim();
|
|
169
|
+
if (trimmed.startsWith("[")) {
|
|
170
|
+
let parsed;
|
|
171
|
+
try {
|
|
172
|
+
parsed = JSON.parse(trimmed);
|
|
173
|
+
} catch {
|
|
174
|
+
throw new CliError(
|
|
175
|
+
"VALIDATION_ERROR",
|
|
176
|
+
`${flag} looks like a JSON array but did not parse`
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
if (!Array.isArray(parsed)) {
|
|
180
|
+
throw new CliError("VALIDATION_ERROR", `${flag} expects a JSON array`);
|
|
181
|
+
}
|
|
182
|
+
return parsed;
|
|
183
|
+
}
|
|
184
|
+
return raw.split(",").map((part) => part.trim()).filter((part) => part !== "").map((part) => coerceScalar(part, itemType ?? "string", flag));
|
|
185
|
+
}
|
|
186
|
+
function coerceObjectValue(raw, flag) {
|
|
187
|
+
let parsed;
|
|
188
|
+
try {
|
|
189
|
+
parsed = JSON.parse(raw);
|
|
190
|
+
} catch {
|
|
191
|
+
throw new CliError(
|
|
192
|
+
"VALIDATION_ERROR",
|
|
193
|
+
`${flag} expects a JSON object, got '${raw}'`
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
197
|
+
throw new CliError("VALIDATION_ERROR", `${flag} expects a JSON object`);
|
|
198
|
+
}
|
|
199
|
+
return parsed;
|
|
200
|
+
}
|
|
201
|
+
function acceptedFieldsSuggestion(toolName, properties, reservedNames) {
|
|
202
|
+
const names = Object.keys(properties);
|
|
203
|
+
const reservedCanonical = new Set([...reservedNames].map(canonicalParamName));
|
|
204
|
+
const viaArgs = names.filter(
|
|
205
|
+
(n) => reservedCanonical.has(canonicalParamName(n))
|
|
206
|
+
);
|
|
207
|
+
const accepted = names.length ? `Accepted parameters for ${toolName}: ${names.join(", ")}.` : `${toolName} takes no parameters.`;
|
|
208
|
+
const argsNote = viaArgs.length ? ` ${viaArgs.join(", ")} share a name with a CLI option and go through --args '<json>'.` : "";
|
|
209
|
+
return `${accepted}${argsNote} Run: hive tools info ${toolName} (or hive tools refresh if the catalog is stale)`;
|
|
210
|
+
}
|
|
211
|
+
function coerceFlagsToArgs(flags, schema, options) {
|
|
212
|
+
const resolver = buildResolver(schema);
|
|
213
|
+
const args = {};
|
|
214
|
+
const arrays = /* @__PURE__ */ new Map();
|
|
215
|
+
const reservedCanonical = new Set(
|
|
216
|
+
[...options.reservedNames].map(canonicalParamName)
|
|
217
|
+
);
|
|
218
|
+
const suggestion = () => acceptedFieldsSuggestion(
|
|
219
|
+
options.toolName,
|
|
220
|
+
resolver.properties,
|
|
221
|
+
options.reservedNames
|
|
222
|
+
);
|
|
223
|
+
for (const flag of flags) {
|
|
224
|
+
const typedName = flag.name;
|
|
225
|
+
if (reservedCanonical.has(canonicalParamName(typedName))) {
|
|
226
|
+
throw new CliError(
|
|
227
|
+
"VALIDATION_ERROR",
|
|
228
|
+
`--${typedName} is reserved for the CLI; pass '${typedName}' through --args '<json>'`,
|
|
229
|
+
suggestion()
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
if (!schema) {
|
|
233
|
+
args[typedName] = flag.negated ? false : flag.value ?? true;
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
const prop = resolver.resolve(typedName);
|
|
237
|
+
if (prop === null) {
|
|
238
|
+
throw new CliError(
|
|
239
|
+
"VALIDATION_ERROR",
|
|
240
|
+
`Unknown parameter '${typedName}' for ${options.toolName}`,
|
|
241
|
+
suggestion()
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
const propSchema = resolver.properties[prop];
|
|
245
|
+
const type = firstType(propSchema);
|
|
246
|
+
const flagLabel = `--${typedName}`;
|
|
247
|
+
if (flag.negated) {
|
|
248
|
+
if (type !== "boolean") {
|
|
249
|
+
throw new CliError(
|
|
250
|
+
"VALIDATION_ERROR",
|
|
251
|
+
`--no-${typedName} only applies to boolean parameters; '${prop}' is ${type ?? "untyped"}`,
|
|
252
|
+
suggestion()
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
args[prop] = false;
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
if (type === "boolean") {
|
|
259
|
+
args[prop] = flag.value === void 0 ? true : coerceScalar(flag.value, "boolean", flagLabel);
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
if (flag.value === void 0) {
|
|
263
|
+
throw new CliError(
|
|
264
|
+
"VALIDATION_ERROR",
|
|
265
|
+
`${flagLabel} expects a value`,
|
|
266
|
+
suggestion()
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
if (type === "array") {
|
|
270
|
+
const items = coerceArrayValue(
|
|
271
|
+
flag.value,
|
|
272
|
+
firstType(propSchema.items),
|
|
273
|
+
flagLabel
|
|
274
|
+
);
|
|
275
|
+
const collected = [...arrays.get(prop) ?? [], ...items];
|
|
276
|
+
arrays.set(prop, collected);
|
|
277
|
+
args[prop] = collected;
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
if (type === "object") {
|
|
281
|
+
args[prop] = coerceObjectValue(flag.value, flagLabel);
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
args[prop] = coerceScalar(flag.value, type, flagLabel);
|
|
285
|
+
}
|
|
286
|
+
return args;
|
|
287
|
+
}
|
|
288
|
+
function parseArgsJson(raw, source) {
|
|
289
|
+
let parsed;
|
|
290
|
+
try {
|
|
291
|
+
parsed = JSON.parse(raw);
|
|
292
|
+
} catch (err) {
|
|
293
|
+
throw new CliError(
|
|
294
|
+
"VALIDATION_ERROR",
|
|
295
|
+
`Invalid JSON in ${source}: ${err instanceof Error ? err.message : String(err)}`,
|
|
296
|
+
`Pass a JSON object, e.g. --args '{"ids":"bitcoin"}'`
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
300
|
+
throw new CliError(
|
|
301
|
+
"VALIDATION_ERROR",
|
|
302
|
+
`${source} must be a JSON object`,
|
|
303
|
+
`Pass a JSON object, e.g. --args '{"ids":"bitcoin"}'`
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
return parsed;
|
|
307
|
+
}
|
|
308
|
+
async function planToolCall(input) {
|
|
309
|
+
const untyped = parseFlagTokens(input.tokens);
|
|
310
|
+
const toolName = untyped.positionals[0];
|
|
311
|
+
if (!toolName) {
|
|
312
|
+
throw new CliError(
|
|
313
|
+
"INVALID_ARGS",
|
|
314
|
+
"Missing tool name",
|
|
315
|
+
"Usage: hive tools call <name> [--<param> <value>...] [--args '<json>']"
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
let args = {};
|
|
319
|
+
if (input.argsJson !== void 0) {
|
|
320
|
+
args = parseArgsJson(input.argsJson, "--args");
|
|
321
|
+
} else if (input.stdinJson !== void 0 && input.stdinJson.trim() !== "") {
|
|
322
|
+
args = parseArgsJson(input.stdinJson, "stdin");
|
|
323
|
+
}
|
|
324
|
+
if (untyped.flags.length === 0) {
|
|
325
|
+
if (untyped.positionals.length > 1) {
|
|
326
|
+
throw new CliError(
|
|
327
|
+
"INVALID_ARGS",
|
|
328
|
+
`Unexpected argument '${untyped.positionals[1]}'`,
|
|
329
|
+
"Tool parameters are passed as --<param> <value> or --args '<json>'"
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
return { toolName, args };
|
|
333
|
+
}
|
|
334
|
+
const schema = await input.lookupSchema(toolName);
|
|
335
|
+
const resolver = buildResolver(schema);
|
|
336
|
+
const typed = parseFlagTokens(
|
|
337
|
+
input.tokens,
|
|
338
|
+
(name) => resolver.isBoolean(name)
|
|
339
|
+
);
|
|
340
|
+
if (typed.positionals.length > 1) {
|
|
341
|
+
throw new CliError(
|
|
342
|
+
"INVALID_ARGS",
|
|
343
|
+
`Unexpected argument '${typed.positionals[1]}'`,
|
|
344
|
+
"Tool parameters are passed as --<param> <value> or --args '<json>'"
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
const flagArgs = coerceFlagsToArgs(typed.flags, schema, {
|
|
348
|
+
reservedNames: input.reservedNames,
|
|
349
|
+
toolName
|
|
350
|
+
});
|
|
351
|
+
return { toolName, args: { ...args, ...flagArgs } };
|
|
352
|
+
}
|
|
353
|
+
function firstSentence(text, max = 60) {
|
|
354
|
+
if (!text) return "";
|
|
355
|
+
const oneLine = text.replace(/\s+/g, " ").trim();
|
|
356
|
+
const match = oneLine.match(/^(.*?[.!?])(?:\s|$)/);
|
|
357
|
+
const sentence = (match ? match[1] : oneLine).trim();
|
|
358
|
+
return sentence.length > max ? `${sentence.slice(0, max - 3)}...` : sentence;
|
|
359
|
+
}
|
|
360
|
+
function describeType(schema) {
|
|
361
|
+
if (isNestedSchema(schema)) return "json";
|
|
362
|
+
const type = firstType(schema);
|
|
363
|
+
if (type === "array") {
|
|
364
|
+
const itemType = firstType(schema.items) ?? "string";
|
|
365
|
+
return `array<${itemType}>`;
|
|
366
|
+
}
|
|
367
|
+
return type ?? "any";
|
|
368
|
+
}
|
|
369
|
+
function describeParameters(schema) {
|
|
370
|
+
const properties = schema?.properties ?? {};
|
|
371
|
+
const required = new Set(schema?.required ?? []);
|
|
372
|
+
return Object.entries(properties).map(([name, prop]) => ({
|
|
373
|
+
name,
|
|
374
|
+
type: describeType(prop),
|
|
375
|
+
required: required.has(name),
|
|
376
|
+
enumValues: Array.isArray(prop.enum) ? prop.enum.map(String) : [],
|
|
377
|
+
defaultValue: prop.default === void 0 ? "" : typeof prop.default === "string" ? prop.default : JSON.stringify(prop.default),
|
|
378
|
+
description: firstSentence(prop.description),
|
|
379
|
+
...isNestedSchema(prop) ? { nested: prop } : {}
|
|
380
|
+
}));
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
export {
|
|
384
|
+
parseFlagTokens,
|
|
385
|
+
canonicalParamName,
|
|
386
|
+
ALWAYS_RESERVED_OPTIONS,
|
|
387
|
+
reservedOptionNames,
|
|
388
|
+
isNestedSchema,
|
|
389
|
+
coerceFlagsToArgs,
|
|
390
|
+
parseArgsJson,
|
|
391
|
+
planToolCall,
|
|
392
|
+
firstSentence,
|
|
393
|
+
describeParameters
|
|
394
|
+
};
|
|
@@ -119,6 +119,9 @@ function shouldOutputJson() {
|
|
|
119
119
|
if (globalOpts.pretty) return false;
|
|
120
120
|
return !process.stdout.isTTY;
|
|
121
121
|
}
|
|
122
|
+
function isQuiet() {
|
|
123
|
+
return Boolean(globalOpts.quiet);
|
|
124
|
+
}
|
|
122
125
|
function colorEnabled() {
|
|
123
126
|
if (globalOpts.noColor) return false;
|
|
124
127
|
if (process.env.NO_COLOR) return false;
|
|
@@ -140,6 +143,20 @@ function dim(s) {
|
|
|
140
143
|
function bold(s) {
|
|
141
144
|
return colorEnabled() ? `\x1B[1m${s}\x1B[0m` : s;
|
|
142
145
|
}
|
|
146
|
+
function formatDuration(totalSeconds) {
|
|
147
|
+
const seconds = Math.max(0, Math.round(totalSeconds));
|
|
148
|
+
const hours = Math.floor(seconds / 3600);
|
|
149
|
+
const minutes = Math.floor(seconds % 3600 / 60);
|
|
150
|
+
const rest = seconds % 60;
|
|
151
|
+
if (hours > 0) return `${hours}h ${minutes}m`;
|
|
152
|
+
if (minutes > 0) return `${minutes}m ${rest}s`;
|
|
153
|
+
return `${rest}s`;
|
|
154
|
+
}
|
|
155
|
+
function describeReset(meta) {
|
|
156
|
+
if (!meta.reset_at) return null;
|
|
157
|
+
const relative = typeof meta.retry_after_seconds === "number" ? ` (in ${formatDuration(meta.retry_after_seconds)})` : "";
|
|
158
|
+
return `Resets: ${meta.reset_at}${relative}`;
|
|
159
|
+
}
|
|
143
160
|
function successEnvelope(data, meta) {
|
|
144
161
|
return { ok: true, data, meta };
|
|
145
162
|
}
|
|
@@ -219,7 +236,9 @@ async function writeOutput(envelope) {
|
|
|
219
236
|
`));
|
|
220
237
|
}
|
|
221
238
|
if (envelope.meta.truncated) {
|
|
222
|
-
process.stderr.write(
|
|
239
|
+
process.stderr.write(
|
|
240
|
+
yellow("Evidence warning: response was truncated.\n")
|
|
241
|
+
);
|
|
223
242
|
}
|
|
224
243
|
for (const warning of envelope.meta.warnings ?? []) {
|
|
225
244
|
process.stderr.write(yellow(`Evidence warning: ${warning}
|
|
@@ -247,11 +266,14 @@ async function writeOutput(envelope) {
|
|
|
247
266
|
`)
|
|
248
267
|
);
|
|
249
268
|
}
|
|
250
|
-
const nextAction = envelope.meta
|
|
269
|
+
const nextAction = envelope.meta.next_action;
|
|
251
270
|
if (typeof nextAction === "string" && nextAction.trim()) {
|
|
252
271
|
process.stderr.write(yellow(` Next: ${nextAction}
|
|
253
272
|
`));
|
|
254
273
|
}
|
|
274
|
+
const reset = describeReset(envelope.meta);
|
|
275
|
+
if (reset) process.stderr.write(yellow(` ${reset}
|
|
276
|
+
`));
|
|
255
277
|
}
|
|
256
278
|
}
|
|
257
279
|
async function outputSuccess(data, meta) {
|
|
@@ -289,12 +311,14 @@ function formatCsv(data) {
|
|
|
289
311
|
export {
|
|
290
312
|
setOutputOptions,
|
|
291
313
|
shouldOutputJson,
|
|
314
|
+
isQuiet,
|
|
292
315
|
colorEnabled,
|
|
293
316
|
red,
|
|
294
317
|
green,
|
|
295
318
|
yellow,
|
|
296
319
|
dim,
|
|
297
320
|
bold,
|
|
321
|
+
describeReset,
|
|
298
322
|
successEnvelope,
|
|
299
323
|
errorEnvelope,
|
|
300
324
|
writeOutput,
|