backthread 0.6.0 → 0.7.0
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/.claude-plugin/plugin.json +1 -1
- package/dist-bundle/backthread.js +133 -132
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "backthread",
|
|
3
3
|
"displayName": "Backthread",
|
|
4
4
|
"description": "Backthread helps you understand your codebase while AI ships features. It captures the why behind every Claude Code session so you can ask \"how does X work?\" without digging through PRs.",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.7.0",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Backthread"
|
|
8
8
|
},
|
|
@@ -6892,109 +6892,6 @@ import { realpathSync } from "node:fs";
|
|
|
6892
6892
|
// src/login.ts
|
|
6893
6893
|
import { hostname } from "node:os";
|
|
6894
6894
|
|
|
6895
|
-
// src/loopback.ts
|
|
6896
|
-
import { createServer } from "node:http";
|
|
6897
|
-
import { randomBytes } from "node:crypto";
|
|
6898
|
-
function generateState() {
|
|
6899
|
-
return base64url(randomBytes(32));
|
|
6900
|
-
}
|
|
6901
|
-
function base64url(bytes) {
|
|
6902
|
-
return bytes.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
6903
|
-
}
|
|
6904
|
-
function validateCallback(method, rawUrl, expectedState) {
|
|
6905
|
-
if ((method ?? "").toUpperCase() !== "GET") return { ok: false, reason: "bad_method" };
|
|
6906
|
-
let url2;
|
|
6907
|
-
try {
|
|
6908
|
-
url2 = new URL(rawUrl ?? "", "http://127.0.0.1");
|
|
6909
|
-
} catch {
|
|
6910
|
-
return { ok: false, reason: "wrong_path" };
|
|
6911
|
-
}
|
|
6912
|
-
if (url2.pathname !== "/callback") return { ok: false, reason: "wrong_path" };
|
|
6913
|
-
const errorParam = url2.searchParams.get("error");
|
|
6914
|
-
if (errorParam) return { ok: false, reason: "error_param", error: errorParam };
|
|
6915
|
-
const state = url2.searchParams.get("state");
|
|
6916
|
-
if (state === null || state !== expectedState) return { ok: false, reason: "state_mismatch" };
|
|
6917
|
-
const token = url2.searchParams.get("token");
|
|
6918
|
-
if (!token || !/^backthread_pat_[A-Za-z0-9_-]+$/.test(token)) {
|
|
6919
|
-
return { ok: false, reason: "missing_token" };
|
|
6920
|
-
}
|
|
6921
|
-
return { ok: true, token };
|
|
6922
|
-
}
|
|
6923
|
-
function resultPage(ok) {
|
|
6924
|
-
const title = ok ? "You\u2019re connected" : "Something went wrong";
|
|
6925
|
-
const body = ok ? "Backthread is now authorized on this device. You can close this tab and return to your terminal." : "Backthread couldn\u2019t finish authorizing this device. Close this tab and run <code>backthread login</code> again.";
|
|
6926
|
-
return `<!doctype html><html><head><meta charset="utf-8"><title>${title}</title>
|
|
6927
|
-
<style>body{font:16px/1.5 system-ui,sans-serif;max-width:32rem;margin:18vh auto;padding:0 1.5rem;color:#18181b}
|
|
6928
|
-
h1{font-size:1.25rem}code{background:#f4f4f5;padding:.1em .3em;border-radius:4px}</style></head>
|
|
6929
|
-
<body><h1>${title}</h1><p>${body}</p></body></html>`;
|
|
6930
|
-
}
|
|
6931
|
-
function startLoopbackServer() {
|
|
6932
|
-
return new Promise((resolveStart, rejectStart) => {
|
|
6933
|
-
const state = generateState();
|
|
6934
|
-
let outcome = null;
|
|
6935
|
-
let onOutcome = null;
|
|
6936
|
-
const deliver = (o) => {
|
|
6937
|
-
if (outcome) return;
|
|
6938
|
-
outcome = o;
|
|
6939
|
-
onOutcome?.();
|
|
6940
|
-
};
|
|
6941
|
-
const server = createServer((req, res) => {
|
|
6942
|
-
const result = validateCallback(req.method, req.url, state);
|
|
6943
|
-
if (!result.ok && result.reason === "wrong_path") {
|
|
6944
|
-
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
6945
|
-
res.end("not found");
|
|
6946
|
-
return;
|
|
6947
|
-
}
|
|
6948
|
-
res.writeHead(result.ok ? 200 : 400, { "Content-Type": "text/html; charset=utf-8" });
|
|
6949
|
-
res.end(resultPage(result.ok));
|
|
6950
|
-
if (result.ok && result.token) {
|
|
6951
|
-
deliver({ token: result.token });
|
|
6952
|
-
} else {
|
|
6953
|
-
deliver({
|
|
6954
|
-
error: new Error(
|
|
6955
|
-
result.reason === "error_param" ? `web app reported: ${result.error}` : `invalid callback (${result.reason})`
|
|
6956
|
-
)
|
|
6957
|
-
});
|
|
6958
|
-
}
|
|
6959
|
-
});
|
|
6960
|
-
server.on("error", (err) => {
|
|
6961
|
-
if (outcome === null && onOutcome === null) rejectStart(err);
|
|
6962
|
-
else deliver({ error: err });
|
|
6963
|
-
});
|
|
6964
|
-
server.listen(0, "127.0.0.1", () => {
|
|
6965
|
-
const addr = server.address();
|
|
6966
|
-
const port = addr.port;
|
|
6967
|
-
const close = () => {
|
|
6968
|
-
try {
|
|
6969
|
-
server.close();
|
|
6970
|
-
} catch {
|
|
6971
|
-
}
|
|
6972
|
-
};
|
|
6973
|
-
const waitForToken = (timeoutMs = 5 * 6e4) => new Promise((resolve, reject) => {
|
|
6974
|
-
const finish = () => {
|
|
6975
|
-
if (!outcome) return;
|
|
6976
|
-
close();
|
|
6977
|
-
if ("token" in outcome) resolve(outcome.token);
|
|
6978
|
-
else reject(outcome.error);
|
|
6979
|
-
};
|
|
6980
|
-
const timer = setTimeout(() => {
|
|
6981
|
-
close();
|
|
6982
|
-
reject(new Error("timed out waiting for the browser to authorize this device"));
|
|
6983
|
-
}, timeoutMs);
|
|
6984
|
-
onOutcome = () => {
|
|
6985
|
-
clearTimeout(timer);
|
|
6986
|
-
finish();
|
|
6987
|
-
};
|
|
6988
|
-
if (outcome) {
|
|
6989
|
-
clearTimeout(timer);
|
|
6990
|
-
finish();
|
|
6991
|
-
}
|
|
6992
|
-
});
|
|
6993
|
-
resolveStart({ port, state, waitForToken, close });
|
|
6994
|
-
});
|
|
6995
|
-
});
|
|
6996
|
-
}
|
|
6997
|
-
|
|
6998
6895
|
// src/urls.ts
|
|
6999
6896
|
var DEFAULT_APP_URL = "https://app.backthread.dev";
|
|
7000
6897
|
function appBaseUrl(env = process.env) {
|
|
@@ -7002,10 +6899,11 @@ function appBaseUrl(env = process.env) {
|
|
|
7002
6899
|
if (override && override.trim().length > 0) return override.replace(/\/+$/, "");
|
|
7003
6900
|
return DEFAULT_APP_URL;
|
|
7004
6901
|
}
|
|
7005
|
-
function buildCliAuthUrl(
|
|
6902
|
+
function buildCliAuthUrl(session, clientPubKey, env = process.env, label) {
|
|
7006
6903
|
const u = new URL("/cli-auth", appBaseUrl(env));
|
|
7007
|
-
u.searchParams.set("
|
|
7008
|
-
u.searchParams.set("
|
|
6904
|
+
u.searchParams.set("session", session);
|
|
6905
|
+
u.searchParams.set("k", clientPubKey);
|
|
6906
|
+
if (label && label.trim().length > 0) u.searchParams.set("label", label.trim());
|
|
7009
6907
|
return u.toString();
|
|
7010
6908
|
}
|
|
7011
6909
|
var DEFAULT_WORKER_URL = "https://clew-ingest-worker.arpy-183.workers.dev";
|
|
@@ -7032,6 +6930,9 @@ function buildIngestDecisionsUrl(env = process.env) {
|
|
|
7032
6930
|
function buildOnboardingStateUrl(env = process.env) {
|
|
7033
6931
|
return new URL(`${functionsBaseUrl(env).replace(/\/+$/, "")}/onboarding-state`).toString();
|
|
7034
6932
|
}
|
|
6933
|
+
function buildCliAuthPollUrl(env = process.env) {
|
|
6934
|
+
return new URL(`${functionsBaseUrl(env).replace(/\/+$/, "")}/cli-auth-poll`).toString();
|
|
6935
|
+
}
|
|
7035
6936
|
function buildRepoDeepLink(owner, name, env = process.env) {
|
|
7036
6937
|
const base = appBaseUrl(env);
|
|
7037
6938
|
return `${base}/${encodeURIComponent(owner)}/${encodeURIComponent(name)}`;
|
|
@@ -7278,22 +7179,117 @@ function configLocationHint(env) {
|
|
|
7278
7179
|
return env.BACKTHREAD_CONFIG_DIR ? `${env.BACKTHREAD_CONFIG_DIR}/config.json` : "~/.backthread/config.json";
|
|
7279
7180
|
}
|
|
7280
7181
|
|
|
7182
|
+
// src/cliAuthCrypto.ts
|
|
7183
|
+
import { createECDH, hkdfSync, createDecipheriv, randomBytes } from "node:crypto";
|
|
7184
|
+
var HKDF_SALT = Buffer.from("backthread-cli-auth");
|
|
7185
|
+
var HKDF_INFO = Buffer.from("device-token-v1");
|
|
7186
|
+
function generateSessionId() {
|
|
7187
|
+
return toB64url(randomBytes(32));
|
|
7188
|
+
}
|
|
7189
|
+
function generateEphemeralKeypair() {
|
|
7190
|
+
const ecdh = createECDH("prime256v1");
|
|
7191
|
+
ecdh.generateKeys();
|
|
7192
|
+
return { ecdh, publicKeyB64url: toB64url(ecdh.getPublicKey()) };
|
|
7193
|
+
}
|
|
7194
|
+
function decryptToken(enc, ecdh) {
|
|
7195
|
+
const pagePub = fromB64url(enc.page_ephemeral_pubkey);
|
|
7196
|
+
const shared = ecdh.computeSecret(pagePub);
|
|
7197
|
+
const aesKey = Buffer.from(hkdfSync("sha256", shared, HKDF_SALT, HKDF_INFO, 32));
|
|
7198
|
+
const ctFull = fromB64url(enc.ciphertext);
|
|
7199
|
+
const tag = ctFull.subarray(ctFull.length - 16);
|
|
7200
|
+
const ct = ctFull.subarray(0, ctFull.length - 16);
|
|
7201
|
+
const iv = fromB64url(enc.iv);
|
|
7202
|
+
const decipher = createDecipheriv("aes-256-gcm", aesKey, iv);
|
|
7203
|
+
decipher.setAuthTag(tag);
|
|
7204
|
+
return Buffer.concat([decipher.update(ct), decipher.final()]).toString("utf8");
|
|
7205
|
+
}
|
|
7206
|
+
function toB64url(buf) {
|
|
7207
|
+
return buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
7208
|
+
}
|
|
7209
|
+
function fromB64url(s) {
|
|
7210
|
+
return Buffer.from(s.replace(/-/g, "+").replace(/_/g, "/"), "base64");
|
|
7211
|
+
}
|
|
7212
|
+
|
|
7213
|
+
// src/cliAuthPoll.ts
|
|
7214
|
+
var TOKEN_RE = /^backthread_pat_[A-Za-z0-9_-]+$/;
|
|
7215
|
+
async function pollForToken(sessionId, keypair, opts = {}) {
|
|
7216
|
+
const env = opts.env ?? process.env;
|
|
7217
|
+
const doFetch = opts.fetchImpl ?? fetch;
|
|
7218
|
+
const interval = opts.intervalMs ?? 1500;
|
|
7219
|
+
const timeout = opts.timeoutMs ?? 5 * 6e4;
|
|
7220
|
+
const sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
7221
|
+
const now = opts.now ?? (() => Date.now());
|
|
7222
|
+
const url2 = buildCliAuthPollUrl(env);
|
|
7223
|
+
const deadline = now() + timeout;
|
|
7224
|
+
while (now() < deadline) {
|
|
7225
|
+
let res;
|
|
7226
|
+
try {
|
|
7227
|
+
res = await doFetch(url2, {
|
|
7228
|
+
method: "POST",
|
|
7229
|
+
headers: { "Content-Type": "application/json", ...versionHeaders() },
|
|
7230
|
+
// The CLI is the CONSUMING poller (default mode) — the browser peeks separately.
|
|
7231
|
+
body: JSON.stringify({ session_id: sessionId })
|
|
7232
|
+
});
|
|
7233
|
+
} catch {
|
|
7234
|
+
await sleep(interval);
|
|
7235
|
+
continue;
|
|
7236
|
+
}
|
|
7237
|
+
if (res.status === 429 || res.status >= 500) {
|
|
7238
|
+
await sleep(interval);
|
|
7239
|
+
continue;
|
|
7240
|
+
}
|
|
7241
|
+
const body = await res.json().catch(() => null);
|
|
7242
|
+
const status = typeof body?.status === "string" ? body.status : null;
|
|
7243
|
+
if (status === "ready") {
|
|
7244
|
+
const enc = extractPayload(body);
|
|
7245
|
+
if (!enc) return { ok: false, reason: "error", message: "incomplete token payload from the server" };
|
|
7246
|
+
let token;
|
|
7247
|
+
try {
|
|
7248
|
+
token = decryptToken(enc, keypair.ecdh);
|
|
7249
|
+
} catch {
|
|
7250
|
+
return { ok: false, reason: "error", message: "could not decrypt the token (key mismatch)" };
|
|
7251
|
+
}
|
|
7252
|
+
if (!TOKEN_RE.test(token)) {
|
|
7253
|
+
return { ok: false, reason: "error", message: "the decrypted token was malformed" };
|
|
7254
|
+
}
|
|
7255
|
+
return { ok: true, token };
|
|
7256
|
+
}
|
|
7257
|
+
if (status === "expired") {
|
|
7258
|
+
return { ok: false, reason: "expired", message: "the login session expired before you authorized" };
|
|
7259
|
+
}
|
|
7260
|
+
if (status === "consumed") {
|
|
7261
|
+
return { ok: false, reason: "error", message: "this login was already used \u2014 start a fresh `bt login`" };
|
|
7262
|
+
}
|
|
7263
|
+
await sleep(interval);
|
|
7264
|
+
}
|
|
7265
|
+
return { ok: false, reason: "timeout", message: "timed out waiting for the browser to authorize this device" };
|
|
7266
|
+
}
|
|
7267
|
+
function extractPayload(body) {
|
|
7268
|
+
if (!body) return null;
|
|
7269
|
+
const { page_ephemeral_pubkey, iv, ciphertext } = body;
|
|
7270
|
+
if (typeof page_ephemeral_pubkey === "string" && typeof iv === "string" && typeof ciphertext === "string") {
|
|
7271
|
+
return { page_ephemeral_pubkey, iv, ciphertext };
|
|
7272
|
+
}
|
|
7273
|
+
return null;
|
|
7274
|
+
}
|
|
7275
|
+
|
|
7281
7276
|
// src/login.ts
|
|
7282
7277
|
async function login(opts = {}) {
|
|
7283
7278
|
const env = opts.env ?? process.env;
|
|
7284
7279
|
const log = opts.log ?? ((m) => console.error(m));
|
|
7285
7280
|
if (opts.claim) {
|
|
7286
|
-
const
|
|
7287
|
-
log(
|
|
7288
|
-
return { ok:
|
|
7281
|
+
const result2 = await exchangeClaim(opts.claim, { env, label: deviceLabel() });
|
|
7282
|
+
log(result2.message);
|
|
7283
|
+
return { ok: result2.ok, message: result2.message };
|
|
7289
7284
|
}
|
|
7290
7285
|
if (opts.device) {
|
|
7291
7286
|
return deviceLogin(log);
|
|
7292
7287
|
}
|
|
7293
|
-
const
|
|
7294
|
-
const
|
|
7288
|
+
const sessionId = generateSessionId();
|
|
7289
|
+
const keypair = generateEphemeralKeypair();
|
|
7290
|
+
const authUrl = buildCliAuthUrl(sessionId, keypair.publicKeyB64url, env, deviceLabel());
|
|
7295
7291
|
log("Opening your browser to authorize this device\u2026");
|
|
7296
|
-
log(`If it doesn't open
|
|
7292
|
+
log(`If it doesn't open \u2014 or you're on a remote/SSH box \u2014 open this on any device:
|
|
7297
7293
|
|
|
7298
7294
|
${authUrl}
|
|
7299
7295
|
`);
|
|
@@ -7303,17 +7299,21 @@ async function login(opts = {}) {
|
|
|
7303
7299
|
log("(Could not open a browser automatically \u2014 use the URL above.)");
|
|
7304
7300
|
}
|
|
7305
7301
|
}
|
|
7306
|
-
|
|
7307
|
-
|
|
7308
|
-
|
|
7309
|
-
|
|
7310
|
-
handle.close();
|
|
7311
|
-
return { ok: false, message: `Login failed: ${err.message}` };
|
|
7302
|
+
const poll = opts.pollImpl ?? pollForToken;
|
|
7303
|
+
const result = await poll(sessionId, keypair, { env });
|
|
7304
|
+
if (!result.ok) {
|
|
7305
|
+
return { ok: false, message: pollFailureMessage(result) };
|
|
7312
7306
|
}
|
|
7313
|
-
await updateConfig({ device_token: token }, env);
|
|
7307
|
+
await updateConfig({ device_token: result.token }, env);
|
|
7314
7308
|
log(`Authorized. Token stored in ${configLocationHint2(env)} (chmod 0600).`);
|
|
7315
7309
|
return { ok: true, message: "Device authorized and token stored." };
|
|
7316
7310
|
}
|
|
7311
|
+
function pollFailureMessage(result) {
|
|
7312
|
+
if (result.reason === "expired" || result.reason === "timeout") {
|
|
7313
|
+
return `Login ${result.reason === "expired" ? "expired" : "timed out"}: ${result.message}. Re-run \`backthread login\` to try again.`;
|
|
7314
|
+
}
|
|
7315
|
+
return `Login failed: ${result.message}`;
|
|
7316
|
+
}
|
|
7317
7317
|
function deviceLabel() {
|
|
7318
7318
|
try {
|
|
7319
7319
|
const h = hostname();
|
|
@@ -7330,10 +7330,11 @@ function deviceLogin(log) {
|
|
|
7330
7330
|
[
|
|
7331
7331
|
"Headless (--device) login is not available yet.",
|
|
7332
7332
|
"",
|
|
7333
|
-
"
|
|
7334
|
-
"
|
|
7335
|
-
"
|
|
7336
|
-
|
|
7333
|
+
"You usually don\u2019t need it: `backthread login` prints a URL you can open on ANY",
|
|
7334
|
+
"device (phone, laptop) \u2014 the token is delivered by polling, so the browser doesn\u2019t",
|
|
7335
|
+
"have to be on this machine. For a fully browserless box, mint a token from the web",
|
|
7336
|
+
"app (Account \u2192 Connected devices) and place it in ~/.backthread/config.json under",
|
|
7337
|
+
'"device_token", or use `--claim <code>` from the web app.'
|
|
7337
7338
|
].join("\n")
|
|
7338
7339
|
);
|
|
7339
7340
|
return { ok: false, message: "--device fallback not implemented yet." };
|
|
@@ -14533,8 +14534,8 @@ function uint8ArrayToBase64(bytes) {
|
|
|
14533
14534
|
}
|
|
14534
14535
|
return btoa(binaryString);
|
|
14535
14536
|
}
|
|
14536
|
-
function base64urlToUint8Array(
|
|
14537
|
-
const base643 =
|
|
14537
|
+
function base64urlToUint8Array(base64url3) {
|
|
14538
|
+
const base643 = base64url3.replace(/-/g, "+").replace(/_/g, "/");
|
|
14538
14539
|
const padding = "=".repeat((4 - base643.length % 4) % 4);
|
|
14539
14540
|
return base64ToUint8Array(base643 + padding);
|
|
14540
14541
|
}
|
|
@@ -14791,7 +14792,7 @@ var safeDecodeAsync = /* @__PURE__ */ _safeDecodeAsync($ZodRealError);
|
|
|
14791
14792
|
var regexes_exports = {};
|
|
14792
14793
|
__export(regexes_exports, {
|
|
14793
14794
|
base64: () => base64,
|
|
14794
|
-
base64url: () =>
|
|
14795
|
+
base64url: () => base64url,
|
|
14795
14796
|
bigint: () => bigint,
|
|
14796
14797
|
boolean: () => boolean,
|
|
14797
14798
|
browserEmail: () => browserEmail,
|
|
@@ -14886,7 +14887,7 @@ var mac = (delimiter) => {
|
|
|
14886
14887
|
var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/;
|
|
14887
14888
|
var cidrv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/;
|
|
14888
14889
|
var base64 = /^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/;
|
|
14889
|
-
var
|
|
14890
|
+
var base64url = /^[A-Za-z0-9_-]*$/;
|
|
14890
14891
|
var hostname2 = /^(?=.{1,253}\.?$)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?)*\.?$/;
|
|
14891
14892
|
var domain = /^([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/;
|
|
14892
14893
|
var httpProtocol = /^https?$/;
|
|
@@ -15900,14 +15901,14 @@ var $ZodBase64 = /* @__PURE__ */ $constructor("$ZodBase64", (inst, def) => {
|
|
|
15900
15901
|
};
|
|
15901
15902
|
});
|
|
15902
15903
|
function isValidBase64URL(data) {
|
|
15903
|
-
if (!
|
|
15904
|
+
if (!base64url.test(data))
|
|
15904
15905
|
return false;
|
|
15905
15906
|
const base643 = data.replace(/[-_]/g, (c) => c === "-" ? "+" : "/");
|
|
15906
15907
|
const padded = base643.padEnd(Math.ceil(base643.length / 4) * 4, "=");
|
|
15907
15908
|
return isValidBase64(padded);
|
|
15908
15909
|
}
|
|
15909
15910
|
var $ZodBase64URL = /* @__PURE__ */ $constructor("$ZodBase64URL", (inst, def) => {
|
|
15910
|
-
def.pattern ?? (def.pattern =
|
|
15911
|
+
def.pattern ?? (def.pattern = base64url);
|
|
15911
15912
|
$ZodStringFormat.init(inst, def);
|
|
15912
15913
|
inst._zod.bag.contentEncoding = "base64url";
|
|
15913
15914
|
inst._zod.check = (payload) => {
|
|
@@ -25936,7 +25937,7 @@ __export(external_exports, {
|
|
|
25936
25937
|
any: () => any,
|
|
25937
25938
|
array: () => array,
|
|
25938
25939
|
base64: () => base642,
|
|
25939
|
-
base64url: () =>
|
|
25940
|
+
base64url: () => base64url2,
|
|
25940
25941
|
bigint: () => bigint2,
|
|
25941
25942
|
boolean: () => boolean2,
|
|
25942
25943
|
catch: () => _catch2,
|
|
@@ -26166,7 +26167,7 @@ __export(schemas_exports2, {
|
|
|
26166
26167
|
any: () => any,
|
|
26167
26168
|
array: () => array,
|
|
26168
26169
|
base64: () => base642,
|
|
26169
|
-
base64url: () =>
|
|
26170
|
+
base64url: () => base64url2,
|
|
26170
26171
|
bigint: () => bigint2,
|
|
26171
26172
|
boolean: () => boolean2,
|
|
26172
26173
|
catch: () => _catch2,
|
|
@@ -26788,7 +26789,7 @@ var ZodBase64URL = /* @__PURE__ */ $constructor("ZodBase64URL", (inst, def) => {
|
|
|
26788
26789
|
$ZodBase64URL.init(inst, def);
|
|
26789
26790
|
ZodStringFormat.init(inst, def);
|
|
26790
26791
|
});
|
|
26791
|
-
function
|
|
26792
|
+
function base64url2(params) {
|
|
26792
26793
|
return _base64url(ZodBase64URL, params);
|
|
26793
26794
|
}
|
|
26794
26795
|
var ZodE164 = /* @__PURE__ */ $constructor("ZodE164", (inst, def) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "backthread",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Backthread helps you understand your codebase while AI ships features. The CLI captures the why behind every AI session and lets you ask how your codebase works, right from the terminal.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Backthread",
|