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.
Files changed (57) hide show
  1. package/README.md +10 -4
  2. package/agent-skills/.claude-plugin/plugin.json +10 -0
  3. package/agent-skills/README.md +2 -0
  4. package/agent-skills/SKILL.md +18 -6
  5. package/agent-skills/evals/trigger-queries.json +70 -0
  6. package/agent-skills/package.json +3 -1
  7. package/agent-skills/packs/hive/SKILL.md +382 -0
  8. package/agent-skills/packs/hive/evals/evals.json +50 -0
  9. package/agent-skills/packs/hive/evals/triggers.json +15 -0
  10. package/agent-skills/packs/hive-build-onboarding/SKILL.md +1 -1
  11. package/agent-skills/packs/hive-cli/SKILL.md +2 -2
  12. package/agent-skills/packs/hive-mcp/SKILL.md +9 -5
  13. package/agent-skills/packs/hive-prediction-markets/SKILL.md +145 -0
  14. package/agent-skills/packs/hive-prediction-markets/evals/evals.json +29 -0
  15. package/agent-skills/packs/hive-prediction-markets/evals/triggers.json +14 -0
  16. package/agent-skills/packs/hive-query/SKILL.md +2 -1
  17. package/agent-skills/packs/hive-stateful-monitoring/SKILL.md +3 -3
  18. package/agent-skills/references/agents-routing.md +4 -1
  19. package/agent-skills/scripts/validate-agent-skills-package.mjs +2 -0
  20. package/agent-skills/skills.sh.json +9 -1
  21. package/build/{api-client-6AM3HVHQ.js → api-client-UGNFUZ2L.js} +12 -3
  22. package/build/{auth-4LPSQJXD.js → auth-5TLYP2DC.js} +1 -1
  23. package/build/call-args-NVOYX6DL.js +27 -0
  24. package/build/{chunk-G23ZAW36.js → chunk-2C5FBG7B.js} +3 -2
  25. package/build/{chunk-J2PXISXW.js → chunk-3SQPLZW6.js} +42810 -39335
  26. package/build/{chunk-S4HBVZ7O.js → chunk-3Z5VR53Z.js} +36 -7
  27. package/build/{chunk-GADPH72D.js → chunk-4QDGA6GP.js} +52 -1
  28. package/build/{chunk-2SPCKQBJ.js → chunk-5QAXJON7.js} +71 -0
  29. package/build/{chunk-GYVF75XB.js → chunk-FQNW6SZ6.js} +1 -1
  30. package/build/{chunk-LW2DHE32.js → chunk-L4KVJDA7.js} +1 -1
  31. package/build/chunk-POPAEM4E.js +474 -0
  32. package/build/{chunk-P7NLFSZQ.js → chunk-TWYGJEVN.js} +100 -9
  33. package/build/{chunk-32NRUWXA.js → chunk-UPWYFTTJ.js} +3 -3
  34. package/build/{chunk-KUF754NT.js → chunk-WII7MTYZ.js} +52 -12
  35. package/build/chunk-XN3T6YOG.js +32 -0
  36. package/build/chunk-XT6RURQV.js +394 -0
  37. package/build/{chunk-LP5ECG7A.js → chunk-ZDXMZPC6.js} +26 -2
  38. package/build/cli.js +120 -48
  39. package/build/{completion-YVSWWF6D.js → completion-ROZAH667.js} +1 -1
  40. package/build/{doctor-AM6QST7Z.js → doctor-44WSVNGJ.js} +42 -5
  41. package/build/{errors-EL6UMXNJ.js → errors-W3GXQN34.js} +7 -1
  42. package/build/feedback-FRRLZDAF.js +113 -0
  43. package/build/{init-all-54G3CVZA.js → init-all-LYRFE2YQ.js} +5 -5
  44. package/build/{mcpServer-NWOKFR7Q.js → mcpServer-43LTLURB.js} +2 -2
  45. package/build/monitor-worker.js +62 -10
  46. package/build/{namespace-PA2IDNRT.js → namespace-XMFFW47T.js} +1 -1
  47. package/build/{output-XGTE4EWJ.js → output-BBHBJI32.js} +5 -1
  48. package/build/release.json +4 -4
  49. package/build/routing-CP43PP5F.js +43 -0
  50. package/build/{serve-XRNMHIJX.js → serve-LTMDRKXS.js} +1 -1
  51. package/build/server.js +295 -41
  52. package/build/stdio.js +2 -2
  53. package/build/{tools-FNPMELSU.js → tools-VA7JXD3K.js} +81 -33
  54. package/build/{uninstall-P3JJZCXT.js → uninstall-3KJLHTNM.js} +26 -7
  55. package/build/{upgrade-ATIFZANV.js → upgrade-3NR3LAGU.js} +2 -2
  56. package/build/{watch-FG2C5Y2Z.js → watch-HJOTI32P.js} +5 -3
  57. 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-P7NLFSZQ.js";
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-LP5ECG7A.js";
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
- if (!resolveApiKey()) {
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 quotaRemaining = response.meta?.quota_remaining;
110
- if (typeof quotaRemaining === "number" && !resolveApiKey() && !shouldOutputJson()) {
111
- process.stderr.write(
112
- dim(
113
- `${quotaRemaining} free call${quotaRemaining === 1 ? "" : "s"} left today. Run \`hive auth login\` for a full key.`
114
- ) + "\n"
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
- const exitCode = response.error?.code === "TOOL_NOT_FOUND" || response.error?.code === "TOOL_RETIRED" ? 3 : response.error?.code === "PROVIDER_UNAVAILABLE" ? 5 : response.error?.code === "RATE_LIMITED" ? 6 : response.error?.code === "TIMEOUT" ? 124 : 4;
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(yellow("Evidence warning: response was truncated.\n"));
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?.next_action;
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,