wity-cli 0.1.0 → 0.1.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/dist/cli.mjs +20 -10
- package/dist/{mcp-DnqXX8ba.mjs → mcp-CWnSbpgj.mjs} +2 -2
- package/dist/{package-7FOUqcPO.mjs → package-m9GoQGcx.mjs} +1 -1
- package/dist/{playground-Cn7EIrd7.mjs → playground-pvc9-JRy.mjs} +2 -2
- package/dist/{questions-eZ01WB1q.mjs → questions-Djd7w1yM.mjs} +2 -2
- package/dist/{send-CGXuVi9Z.mjs → send-xVjyr_dj.mjs} +25 -4
- package/package.json +3 -3
package/dist/cli.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as version } from "./package-
|
|
3
|
-
import { C as
|
|
4
|
-
import { a as scoreQuestion, c as codeLangs, d as printCode, f as systemOneTs, i as pickField, l as curl, n as choiceQuestion, o as renderAnswer, r as noulQuestion, s as renderFooter, t as ask, u as generateTs } from "./questions-
|
|
2
|
+
import { t as version } from "./package-m9GoQGcx.mjs";
|
|
3
|
+
import { A as spinner, C as cleanBlock, D as painter, E as ms, I as resolveBaseURL, L as CliError, M as writeJson, N as KEYS_PAGE, R as EXIT, S as clean, _ as checkKey, a as checkStateLength, b as refusedHint, d as readStdin, f as findKey, g as checkHealth, h as openStore, i as askFileSchema, k as shouldColor, l as readHidden, m as moveKey, n as sendGenerate, o as describeIssues, p as keyPrefix, r as sendSystemOne, u as readState, w as cost } from "./send-xVjyr_dj.mjs";
|
|
4
|
+
import { a as scoreQuestion, c as codeLangs, d as printCode, f as systemOneTs, i as pickField, l as curl, n as choiceQuestion, o as renderAnswer, r as noulQuestion, s as renderFooter, t as ask, u as generateTs } from "./questions-Djd7w1yM.mjs";
|
|
5
5
|
import { Command, CommanderError, InvalidArgumentError, Option } from "commander";
|
|
6
6
|
import { readFile, stat } from "node:fs/promises";
|
|
7
7
|
import { parse } from "yaml";
|
|
@@ -21,7 +21,7 @@ const envWarning = (ctx, text) => {
|
|
|
21
21
|
if (ctx.io.env.WITY_API_KEY?.trim()) ctx.io.stderr.write(` ${ctx.err("yellow", "▲")} ${text}\n\n`);
|
|
22
22
|
};
|
|
23
23
|
/** Shown only when it isn't the usual address, so people notice they're pointed somewhere else. */
|
|
24
|
-
const addressLine = (ctx) => ctx.baseURL === "https://wity
|
|
24
|
+
const addressLine = (ctx) => ctx.baseURL === "https://api.wity.alphanimble.com" ? "" : ` ${ctx.err("dim", "API".padEnd(9))} ${ctx.baseURL}\n`;
|
|
25
25
|
const when = (iso) => new Date(iso).toLocaleString("en-GB", {
|
|
26
26
|
dateStyle: "medium",
|
|
27
27
|
timeStyle: "short"
|
|
@@ -77,7 +77,7 @@ const removeKey = async (ctx) => {
|
|
|
77
77
|
const p = ctx.err;
|
|
78
78
|
const store = await ctx.store();
|
|
79
79
|
if (!await store.delete(ctx.baseURL)) {
|
|
80
|
-
io.stderr.write(`\n There's no saved key on this computer${ctx.baseURL === "https://wity
|
|
80
|
+
io.stderr.write(`\n There's no saved key on this computer${ctx.baseURL === "https://api.wity.alphanimble.com" ? "" : ` for ${ctx.baseURL}`}.\n\n`);
|
|
81
81
|
envWarning(ctx, "WITY_API_KEY is set in this shell, so commands keep using it. Remove it with: unset WITY_API_KEY");
|
|
82
82
|
return EXIT.ok;
|
|
83
83
|
}
|
|
@@ -232,7 +232,7 @@ const doctor = async (ctx, opts) => {
|
|
|
232
232
|
show({
|
|
233
233
|
name: "API address",
|
|
234
234
|
state: "ok",
|
|
235
|
-
detail: ctx.baseURL === "https://wity
|
|
235
|
+
detail: ctx.baseURL === "https://api.wity.alphanimble.com" ? ctx.baseURL : `${ctx.baseURL} (custom)`
|
|
236
236
|
});
|
|
237
237
|
show(await attempt("Key storage", async () => {
|
|
238
238
|
return {
|
|
@@ -375,6 +375,16 @@ const generate = async (ctx, instructions, flags) => {
|
|
|
375
375
|
};
|
|
376
376
|
//#endregion
|
|
377
377
|
//#region src/context.ts
|
|
378
|
+
/**
|
|
379
|
+
* Opens the store and, on the default address, moves a key saved under the old one.
|
|
380
|
+
* The notice goes to stderr, so stdout stays clean for JSON and for `wity mcp serve`.
|
|
381
|
+
*/
|
|
382
|
+
const openAndMove = async (io, baseURL) => {
|
|
383
|
+
const store = await openStore(io.env);
|
|
384
|
+
if (baseURL === "https://api.wity.alphanimble.com" && await moveKey(store, "https://wity-proxy-production-2c33.up.railway.app", baseURL)) io.stderr.write(`[wity] Notice: the Wity API has moved to ${baseURL}.\n[wity] Your saved API key was moved to the new address. No action is needed.
|
|
385
|
+
`);
|
|
386
|
+
return store;
|
|
387
|
+
};
|
|
378
388
|
const makeCtx = (io, baseUrlFlag) => {
|
|
379
389
|
const baseURL = resolveBaseURL(baseUrlFlag, io.env);
|
|
380
390
|
let opened;
|
|
@@ -382,7 +392,7 @@ const makeCtx = (io, baseUrlFlag) => {
|
|
|
382
392
|
io,
|
|
383
393
|
baseURL,
|
|
384
394
|
store: () => {
|
|
385
|
-
opened ??=
|
|
395
|
+
opened ??= openAndMove(io, baseURL);
|
|
386
396
|
return opened;
|
|
387
397
|
},
|
|
388
398
|
out: painter(shouldColor(io.env, io.stdout)),
|
|
@@ -425,7 +435,7 @@ const main = async (argv, io) => {
|
|
|
425
435
|
outputError: (text, write) => write(text.replace(/wity_[\w-]{16,}/g, "wity_…"))
|
|
426
436
|
}).exitOverride().action(async () => {
|
|
427
437
|
if (!io.stdin.isTTY || !io.stdout.isTTY) program.help();
|
|
428
|
-
const { playground } = await import("./playground-
|
|
438
|
+
const { playground } = await import("./playground-pvc9-JRy.mjs");
|
|
429
439
|
code = await playground(ctx(), "");
|
|
430
440
|
});
|
|
431
441
|
const setHint = "Run `wity api-key set <key>`, or `wity api-key set` to paste it at a hidden prompt.";
|
|
@@ -468,11 +478,11 @@ const main = async (argv, io) => {
|
|
|
468
478
|
});
|
|
469
479
|
program.command("playground").description("try questions live in the terminal (also: wity with no arguments)").option("-t, --text <text>", "start with this text").option("--file <path>", "start with the text of this file").action(async (opts) => {
|
|
470
480
|
const text = opts.text !== void 0 || opts.file !== void 0 ? await readState(opts, io) : "";
|
|
471
|
-
const { playground } = await import("./playground-
|
|
481
|
+
const { playground } = await import("./playground-pvc9-JRy.mjs");
|
|
472
482
|
code = await playground(ctx(), text);
|
|
473
483
|
});
|
|
474
484
|
program.command("mcp").description("run Wity as an MCP server for AI agents").command("serve").description("serve Wity's tools over stdio, for Claude Code, Claude Desktop, Cursor and others").option("--max-spend <usd>", "stop paid calls after this many dollars in one session", number).action(async (opts) => {
|
|
475
|
-
const { serveMcp } = await import("./mcp-
|
|
485
|
+
const { serveMcp } = await import("./mcp-CWnSbpgj.mjs");
|
|
476
486
|
code = await serveMcp(ctx(), opts);
|
|
477
487
|
});
|
|
478
488
|
try {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as version } from "./package-
|
|
2
|
-
import {
|
|
1
|
+
import { t as version } from "./package-m9GoQGcx.mjs";
|
|
2
|
+
import { F as PRICE_PER_MILLION_INPUT_USD, L as CliError, O as pct, R as EXIT, S as clean, a as checkStateLength, c as MAX_STATE_CHARS, s as questionSchema, t as requireKey, v as explain, w as cost, y as makeClient } from "./send-xVjyr_dj.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as
|
|
2
|
-
import { a as scoreQuestion, f as systemOneTs, n as choiceQuestion, o as renderAnswer, r as noulQuestion, s as renderFooter } from "./questions-
|
|
1
|
+
import { C as cleanBlock, D as painter, L as CliError, R as EXIT, S as clean, a as checkStateLength, k as shouldColor, p as keyPrefix, t as requireKey, v as explain, w as cost, y as makeClient } from "./send-xVjyr_dj.mjs";
|
|
2
|
+
import { a as scoreQuestion, f as systemOneTs, n as choiceQuestion, o as renderAnswer, r as noulQuestion, s as renderFooter } from "./questions-Djd7w1yM.mjs";
|
|
3
3
|
import { Box, Text, render, useAnimation, useApp, useInput, usePaste, useWindowSize } from "ink";
|
|
4
4
|
import { useEffect, useRef, useState } from "react";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { B as choice, E as ms, H as score, L as CliError, M as writeJson, O as pct, R as EXIT, S as clean, T as decimal, V as noul, j as truncate, r as sendSystemOne, u as readState, w as cost, x as bar } from "./send-xVjyr_dj.mjs";
|
|
2
2
|
//#region src/code.ts
|
|
3
3
|
/** A string as a JavaScript literal. JSON's escaping is valid JavaScript, and safe for any text. */
|
|
4
4
|
const str = (value) => JSON.stringify(value);
|
|
@@ -16,7 +16,7 @@ const builder = (question, indent) => {
|
|
|
16
16
|
const inline = `[${levels.join(", ")}]`;
|
|
17
17
|
return inline.length <= 80 ? `score(${str(question.instructions)}, ${inline})` : `score(${str(question.instructions)}, [\n${levels.map((level) => `${indent} ${level},`).join("\n")}\n${indent}])`;
|
|
18
18
|
};
|
|
19
|
-
const clientLine = (baseURL) => baseURL === "https://wity
|
|
19
|
+
const clientLine = (baseURL) => baseURL === "https://api.wity.alphanimble.com" ? "const client = new WityClient(); // reads WITY_API_KEY" : `const client = new WityClient({ baseURL: ${str(baseURL)} }); // reads WITY_API_KEY`;
|
|
20
20
|
const systemOneTs = (request, baseURL) => {
|
|
21
21
|
const types = [...new Set(Object.values(request.questions).map((q) => q.type))].sort();
|
|
22
22
|
const questions = Object.entries(request.questions).map(([name, question]) => ` ${prop(name)}: ${builder(question, " ")},`).join("\n");
|
|
@@ -196,7 +196,7 @@ const sleep = (ms, signal) => new Promise((resolve, reject) => {
|
|
|
196
196
|
* If it ever moves: change this line, bump the version and publish.
|
|
197
197
|
* Until users update, they can set WITY_BASE_URL or the `baseURL` option.
|
|
198
198
|
*/
|
|
199
|
-
const DEFAULT_BASE_URL = "https://wity
|
|
199
|
+
const DEFAULT_BASE_URL = "https://api.wity.alphanimble.com";
|
|
200
200
|
/** Extra time on top of `max_latency_ms` for the network and Wity's own work. */
|
|
201
201
|
const LATENCY_MARGIN_MS = 1e4;
|
|
202
202
|
/** The longest delay `setTimeout` accepts. A longer one fires at once. */
|
|
@@ -307,7 +307,7 @@ var WityClient = class {
|
|
|
307
307
|
if (!apiKey) throw new WityError("No API key found. Set the WITY_API_KEY environment variable, or pass apiKey to WityClient.");
|
|
308
308
|
if (!KEY_PATTERN.test(apiKey)) throw new WityError("The API key contains spaces or unusual characters. Check WITY_API_KEY.");
|
|
309
309
|
this.#apiKey = apiKey;
|
|
310
|
-
this.baseURL = checkBaseURL(options.baseURL ?? readEnv("WITY_BASE_URL") ?? "https://wity
|
|
310
|
+
this.baseURL = checkBaseURL(options.baseURL ?? readEnv("WITY_BASE_URL") ?? "https://api.wity.alphanimble.com");
|
|
311
311
|
this.timeoutMs = options.timeoutMs ?? 6e4;
|
|
312
312
|
if (!Number.isFinite(this.timeoutMs) || this.timeoutMs <= 0 || this.timeoutMs > MAX_TIMER_MS) throw new WityError(`timeoutMs must be a positive number of milliseconds, at most ${MAX_TIMER_MS}.`);
|
|
313
313
|
this.maxRetries = options.maxRetries ?? 2;
|
|
@@ -522,6 +522,12 @@ var CliError = class extends Error {
|
|
|
522
522
|
const CONSOLE_URL = "https://wity.alphanimble.com";
|
|
523
523
|
const KEYS_PAGE = `${CONSOLE_URL}/console/keys`;
|
|
524
524
|
const BILLING_PAGE = `${CONSOLE_URL}/console/billing`;
|
|
525
|
+
/**
|
|
526
|
+
* Where the API lived before it moved to api.wity.alphanimble.com (SDK 0.1.1).
|
|
527
|
+
* Keys saved by CLI 0.1.0 are filed under it, so they're moved to the new address on first use.
|
|
528
|
+
* Both addresses reach the same server, so moving the key doesn't send it anywhere new.
|
|
529
|
+
*/
|
|
530
|
+
const OLD_BASE_URL = "https://wity-proxy-production-2c33.up.railway.app";
|
|
525
531
|
/** Dollars per million input tokens, from wity.alphanimble.com/pricing. Output and thinking are free. */
|
|
526
532
|
const PRICE_PER_MILLION_INPUT_USD = .042;
|
|
527
533
|
/**
|
|
@@ -530,7 +536,7 @@ const PRICE_PER_MILLION_INPUT_USD = .042;
|
|
|
530
536
|
* The SDK does the full check (https only, no user or password) when the client is made.
|
|
531
537
|
*/
|
|
532
538
|
const resolveBaseURL = (flag, env) => {
|
|
533
|
-
const raw = flag?.trim() || env.WITY_BASE_URL?.trim() || "https://wity
|
|
539
|
+
const raw = flag?.trim() || env.WITY_BASE_URL?.trim() || "https://api.wity.alphanimble.com";
|
|
534
540
|
let url;
|
|
535
541
|
try {
|
|
536
542
|
url = new URL(raw);
|
|
@@ -853,6 +859,21 @@ const openStore = async (env) => {
|
|
|
853
859
|
if (wanted === "keychain") throw new CliError("No working keychain was found on this machine.", EXIT.auth, "Unset WITY_CREDENTIAL_STORE to save the key in a private file instead.");
|
|
854
860
|
return fileStore(env);
|
|
855
861
|
};
|
|
862
|
+
/**
|
|
863
|
+
* Moves the key saved under `from` to `to`, unless `to` already has one. `true` if a key was moved.
|
|
864
|
+
* The new entry is written before the old one is removed, so a failure never loses the key.
|
|
865
|
+
*/
|
|
866
|
+
const moveKey = async (store, from, to) => {
|
|
867
|
+
if (from === to || await store.get(to)) return false;
|
|
868
|
+
const old = await store.get(from);
|
|
869
|
+
if (!old) return false;
|
|
870
|
+
await store.set({
|
|
871
|
+
...old,
|
|
872
|
+
baseURL: to
|
|
873
|
+
});
|
|
874
|
+
await store.delete(from);
|
|
875
|
+
return true;
|
|
876
|
+
};
|
|
856
877
|
/** WITY_API_KEY wins over a saved key, like in the SDK. `wity api-key show` says which one is in use. */
|
|
857
878
|
const findKey = async (baseURL, env, store) => {
|
|
858
879
|
const fromEnv = env.WITY_API_KEY?.trim();
|
|
@@ -1049,4 +1070,4 @@ const sendGenerate = async (ctx, request) => {
|
|
|
1049
1070
|
}
|
|
1050
1071
|
};
|
|
1051
1072
|
//#endregion
|
|
1052
|
-
export {
|
|
1073
|
+
export { spinner as A, choice as B, cleanBlock as C, painter as D, ms as E, PRICE_PER_MILLION_INPUT_USD as F, score as H, resolveBaseURL as I, CliError as L, writeJson as M, KEYS_PAGE as N, pct as O, OLD_BASE_URL as P, EXIT as R, clean as S, decimal as T, noul as V, checkKey as _, checkStateLength as a, refusedHint as b, MAX_STATE_CHARS as c, readStdin as d, findKey as f, checkHealth as g, openStore as h, askFileSchema as i, truncate as j, shouldColor as k, readHidden as l, moveKey as m, sendGenerate as n, describeIssues as o, keyPrefix as p, sendSystemOne as r, questionSchema as s, requireKey as t, readState as u, explain as v, cost as w, bar as x, makeClient as y, DEFAULT_BASE_URL as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wity-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Command-line tool for Wity, the typed-decision API",
|
|
5
5
|
"homepage": "https://wity.alphanimble.com",
|
|
6
6
|
"repository": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"type": "module",
|
|
12
12
|
"bin": {
|
|
13
|
-
"wity": "
|
|
13
|
+
"wity": "dist/cli.mjs"
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
16
16
|
"dist",
|
|
@@ -45,6 +45,6 @@
|
|
|
45
45
|
"tsdown": "^0.23.0",
|
|
46
46
|
"typescript": "^6.0.3",
|
|
47
47
|
"vitest": "^5.0.2",
|
|
48
|
-
"wity-sdk": "^0.1.
|
|
48
|
+
"wity-sdk": "^0.1.1"
|
|
49
49
|
}
|
|
50
50
|
}
|