@raegent/earshot 0.3.0 → 0.3.2

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/main.js CHANGED
@@ -18381,7 +18381,7 @@ class ShadowGit {
18381
18381
  }
18382
18382
 
18383
18383
  // packages/core/src/version.ts
18384
- var VERSION = "0.3.0";
18384
+ var VERSION = "0.3.2";
18385
18385
 
18386
18386
  // packages/core/src/session/repair.ts
18387
18387
  var REPAIR_TEXT = "No result was recorded for this call: earshot exited before the tool finished. " + "The call may or may not have run, so treat its effect as unknown and check " + "the current state rather than assuming either outcome.";
@@ -22006,53 +22006,63 @@ function Onboarding({ onDone, ...rest }) {
22006
22006
  onDone(result);
22007
22007
  exit();
22008
22008
  }, [exit, onDone]);
22009
- const verify2 = useCallback2(async (provider) => {
22010
- setScreen({ name: "probing", provider });
22011
- const result = await options.current.probe(provider.id);
22009
+ const verify2 = useCallback2(async (provider, model2) => {
22010
+ setScreen({ name: "probing", provider, model: model2 });
22011
+ const result = await options.current.probe(provider.id, model2.id);
22012
22012
  if (result.ok) {
22013
- setScreen({ name: "ready", provider });
22013
+ setScreen({ name: "ready", provider, model: model2 });
22014
22014
  return;
22015
22015
  }
22016
22016
  if (result.reason === "rejected")
22017
22017
  await options.current.forgetKey(provider.id).catch(() => {});
22018
- setScreen({ name: "failed", provider, result });
22018
+ setScreen({ name: "failed", provider, model: model2, result });
22019
22019
  }, []);
22020
22020
  const submitKey = useCallback2(async () => {
22021
- const provider = screen.name === "key" ? screen.provider : undefined;
22021
+ const selected = screen.name === "key" ? screen : undefined;
22022
22022
  const key2 = secret.current;
22023
22023
  secret.current = "";
22024
22024
  setInput("");
22025
- if (!provider)
22025
+ if (!selected)
22026
22026
  return;
22027
22027
  if (key2.trim() === "") {
22028
22028
  setError("a key is needed, or press esc to go back");
22029
22029
  return;
22030
22030
  }
22031
22031
  setError(undefined);
22032
- await options.current.storeKey(provider.id, key2.trim());
22033
- await verify2(provider);
22032
+ await options.current.storeKey(selected.provider.id, key2.trim());
22033
+ await verify2(selected.provider, selected.model);
22034
22034
  }, [screen, verify2]);
22035
- const startSignIn = useCallback2(async (provider) => {
22036
- setScreen({ name: "oauth", provider });
22035
+ const startSignIn = useCallback2(async (provider, model2) => {
22036
+ setScreen({ name: "oauth", provider, model: model2 });
22037
22037
  try {
22038
- await options.current.signIn(provider.id, (url) => setScreen({ name: "oauth", provider, url }));
22038
+ await options.current.signIn(provider.id, (url) => setScreen({ name: "oauth", provider, model: model2, url }));
22039
22039
  } catch (failure) {
22040
22040
  setScreen({
22041
22041
  name: "failed",
22042
22042
  provider,
22043
+ model: model2,
22043
22044
  result: { ok: false, reason: "other", message: failure.message }
22044
22045
  });
22045
22046
  return;
22046
22047
  }
22047
- await verify2(provider);
22048
+ await verify2(provider, model2);
22048
22049
  }, [verify2]);
22049
- const choose = useCallback2((provider) => {
22050
+ const chooseModel = useCallback2((provider, model2) => {
22051
+ setInput("");
22050
22052
  setError(undefined);
22051
- if (provider.kind === "oauth")
22052
- startSignIn(provider);
22053
+ if (provider.configured)
22054
+ verify2(provider, model2);
22055
+ else if (provider.kind === "oauth")
22056
+ startSignIn(provider, model2);
22053
22057
  else
22054
- setScreen({ name: "key", provider });
22055
- }, [startSignIn]);
22058
+ setScreen({ name: "key", provider, model: model2 });
22059
+ }, [startSignIn, verify2]);
22060
+ const chooseProvider = useCallback2((provider) => {
22061
+ setInput("");
22062
+ setError(undefined);
22063
+ setCursor(preferredModelIndex(provider.models, rest.wantedModel));
22064
+ setScreen({ name: "model", provider });
22065
+ }, [rest.wantedModel]);
22056
22066
  useInput5((key2, meta) => {
22057
22067
  if (meta.ctrl && key2 === "c") {
22058
22068
  finish({ outcome: "quit" });
@@ -22070,8 +22080,23 @@ function Onboarding({ onDone, ...rest }) {
22070
22080
  if (meta.return) {
22071
22081
  const provider = providers[cursor];
22072
22082
  if (provider)
22073
- choose(provider);
22083
+ chooseProvider(provider);
22084
+ }
22085
+ return;
22086
+ }
22087
+ if (screen.name === "model") {
22088
+ if (meta.escape) {
22089
+ setInput("");
22090
+ setError(undefined);
22091
+ setCursor(0);
22092
+ setScreen({ name: "choose" });
22093
+ return;
22074
22094
  }
22095
+ const matches3 = matchingModels(screen.provider.models, input);
22096
+ if (meta.upArrow)
22097
+ setCursor((c) => c <= 0 ? Math.max(0, matches3.length - 1) : c - 1);
22098
+ if (meta.downArrow)
22099
+ setCursor((c) => c >= matches3.length - 1 ? 0 : c + 1);
22075
22100
  return;
22076
22101
  }
22077
22102
  if (screen.name === "key" && !meta.escape) {
@@ -22096,11 +22121,11 @@ function Onboarding({ onDone, ...rest }) {
22096
22121
  secret.current = "";
22097
22122
  setInput("");
22098
22123
  setError(undefined);
22099
- setScreen({ name: "choose" });
22124
+ setScreen(screen.name === "key" || screen.name === "oauth" || screen.name === "failed" ? { name: "model", provider: screen.provider } : { name: "choose" });
22100
22125
  return;
22101
22126
  }
22102
22127
  if (screen.name === "failed" && key2 === "k" && screen.result.reason === "unreachable") {
22103
- setScreen({ name: "ready", provider: screen.provider });
22128
+ setScreen({ name: "ready", provider: screen.provider, model: screen.model });
22104
22129
  }
22105
22130
  });
22106
22131
  if (screen.name === "choose") {
@@ -22138,6 +22163,79 @@ function Onboarding({ onDone, ...rest }) {
22138
22163
  ]
22139
22164
  }, undefined, true, undefined, this);
22140
22165
  }
22166
+ if (screen.name === "model") {
22167
+ const matches3 = matchingModels(screen.provider.models, input);
22168
+ const selected = matches3[cursor];
22169
+ const start = Math.max(0, Math.min(cursor - 3, matches3.length - 8));
22170
+ return /* @__PURE__ */ jsxDEV11(Box10, {
22171
+ flexDirection: "column",
22172
+ children: [
22173
+ /* @__PURE__ */ jsxDEV11(Header, {}, undefined, false, undefined, this),
22174
+ /* @__PURE__ */ jsxDEV11(Text11, {
22175
+ children: [
22176
+ "choose a model from ",
22177
+ screen.provider.id,
22178
+ " (",
22179
+ matches3.length,
22180
+ " matching)"
22181
+ ]
22182
+ }, undefined, true, undefined, this),
22183
+ /* @__PURE__ */ jsxDEV11(Box10, {
22184
+ children: [
22185
+ /* @__PURE__ */ jsxDEV11(Text11, {
22186
+ color: theme.user,
22187
+ children: "> "
22188
+ }, undefined, false, undefined, this),
22189
+ /* @__PURE__ */ jsxDEV11(TextInput, {
22190
+ value: input,
22191
+ onChange: (value) => {
22192
+ setInput(value);
22193
+ setCursor(0);
22194
+ setError(undefined);
22195
+ },
22196
+ onSubmit: () => {
22197
+ if (selected)
22198
+ chooseModel(screen.provider, selected);
22199
+ else
22200
+ setError("no model matches that search");
22201
+ },
22202
+ placeholder: "type to filter models"
22203
+ }, undefined, false, undefined, this)
22204
+ ]
22205
+ }, undefined, true, undefined, this),
22206
+ /* @__PURE__ */ jsxDEV11(Box10, {
22207
+ flexDirection: "column",
22208
+ marginTop: 1,
22209
+ children: [
22210
+ matches3.slice(start, start + 8).map((model2) => /* @__PURE__ */ jsxDEV11(Text11, {
22211
+ color: model2 === selected ? theme.user : theme.muted,
22212
+ children: [
22213
+ model2 === selected ? "› " : " ",
22214
+ model2.id,
22215
+ " · ",
22216
+ model2.name
22217
+ ]
22218
+ }, model2.id, true, undefined, this)),
22219
+ matches3.length === 0 ? /* @__PURE__ */ jsxDEV11(Text11, {
22220
+ color: theme.muted,
22221
+ children: "no matching models"
22222
+ }, undefined, false, undefined, this) : null
22223
+ ]
22224
+ }, undefined, true, undefined, this),
22225
+ /* @__PURE__ */ jsxDEV11(Box10, {
22226
+ marginTop: 1,
22227
+ children: /* @__PURE__ */ jsxDEV11(Text11, {
22228
+ color: theme.muted,
22229
+ children: "type filter · ↑↓ choose · enter select · esc back"
22230
+ }, undefined, false, undefined, this)
22231
+ }, undefined, false, undefined, this),
22232
+ error ? /* @__PURE__ */ jsxDEV11(Text11, {
22233
+ color: theme.warning,
22234
+ children: error
22235
+ }, undefined, false, undefined, this) : null
22236
+ ]
22237
+ }, undefined, true, undefined, this);
22238
+ }
22141
22239
  if (screen.name === "key") {
22142
22240
  return /* @__PURE__ */ jsxDEV11(Box10, {
22143
22241
  flexDirection: "column",
@@ -22271,7 +22369,9 @@ function Onboarding({ onDone, ...rest }) {
22271
22369
  color: theme.user,
22272
22370
  children: [
22273
22371
  "ready: ",
22274
- screen.provider.id
22372
+ screen.provider.id,
22373
+ "/",
22374
+ screen.model.id
22275
22375
  ]
22276
22376
  }, undefined, true, undefined, this),
22277
22377
  /* @__PURE__ */ jsxDEV11(Box10, {
@@ -22290,7 +22390,12 @@ function Onboarding({ onDone, ...rest }) {
22290
22390
  /* @__PURE__ */ jsxDEV11(TextInput, {
22291
22391
  value: input,
22292
22392
  onChange: setInput,
22293
- onSubmit: (text2) => finish({ outcome: "ready", providerId: screen.provider.id, firstPrompt: text2.trim() })
22393
+ onSubmit: (text2) => finish({
22394
+ outcome: "ready",
22395
+ providerId: screen.provider.id,
22396
+ model: `${screen.provider.id}/${screen.model.id}`,
22397
+ firstPrompt: text2.trim()
22398
+ })
22294
22399
  }, undefined, false, undefined, this)
22295
22400
  ]
22296
22401
  }, undefined, true, undefined, this)
@@ -22313,6 +22418,19 @@ function hint(provider) {
22313
22418
  return "sign in with a browser - no key to paste";
22314
22419
  return provider.envVars?.length ? provider.envVars.join(" or ") : "api key";
22315
22420
  }
22421
+ function matchingModels(models, query) {
22422
+ const wanted = query.trim().toLowerCase();
22423
+ if (!wanted)
22424
+ return models;
22425
+ return models.filter((model2) => model2.id.toLowerCase().includes(wanted) || model2.name.toLowerCase().includes(wanted));
22426
+ }
22427
+ function preferredModelIndex(models, wanted) {
22428
+ if (!wanted)
22429
+ return 0;
22430
+ const modelId = wanted.includes("/") ? wanted.slice(wanted.indexOf("/") + 1) : wanted;
22431
+ const index = models.findIndex((model2) => model2.id === wanted || model2.id === modelId);
22432
+ return Math.max(0, index);
22433
+ }
22316
22434
  function order(providers, wanted) {
22317
22435
  if (!wanted)
22318
22436
  return providers;
@@ -22361,7 +22479,7 @@ async function runOnboarding(options) {
22361
22479
  return result;
22362
22480
  }
22363
22481
  // packages/cli/src/onboard.ts
22364
- async function buildOnboardingOptions(wanted) {
22482
+ async function buildOnboardingOptions(wanted, wantedModel) {
22365
22483
  const registry2 = buildRegistry();
22366
22484
  const store3 = new AuthStore;
22367
22485
  const providers = [];
@@ -22374,13 +22492,14 @@ async function buildOnboardingOptions(wanted) {
22374
22492
  return {
22375
22493
  providers,
22376
22494
  ...wanted ? { wanted } : {},
22495
+ ...wantedModel ? { wantedModel } : {},
22377
22496
  storeKey: (providerId, key2) => store3.set(providerId, { type: "api-key", apiKey: key2 }),
22378
22497
  forgetKey: (providerId) => store3.remove(providerId),
22379
22498
  signIn: async (providerId, onUrl) => {
22380
22499
  const credentials = await loginToOpenRouter({ onUrl });
22381
22500
  await store3.set(providerId, credentials);
22382
22501
  },
22383
- probe: (providerId) => probe(registry2, providerId)
22502
+ probe: (providerId, modelId) => probe(registry2, providerId, modelId)
22384
22503
  };
22385
22504
  }
22386
22505
  async function describe3(provider, store3) {
@@ -22389,6 +22508,7 @@ async function describe3(provider, store3) {
22389
22508
  });
22390
22509
  return {
22391
22510
  id: provider.id,
22511
+ models: provider.models().map((model2) => ({ id: model2.id, name: model2.name })),
22392
22512
  kind: provider.auth.kind === "oauth" ? "oauth" : "api-key",
22393
22513
  ...envVarsOf2(provider.auth).length ? { envVars: envVarsOf2(provider.auth) } : {},
22394
22514
  ...configured ? { configured: describeConfigured(configured.type) } : {}
@@ -22400,16 +22520,16 @@ function envVarsOf2(auth2) {
22400
22520
  function describeConfigured(kind) {
22401
22521
  return kind === "ambient" ? "ambient credentials" : kind === "oauth" ? "signed in" : "api key set";
22402
22522
  }
22403
- async function probe(registry2, providerId) {
22523
+ async function probe(registry2, providerId, modelId) {
22404
22524
  const listed = registry2.list().find((provider) => provider.id === providerId);
22405
22525
  if (!listed)
22406
22526
  return { ok: false, reason: "other", message: `unknown provider "${providerId}"` };
22407
- const model2 = listed.models()[0];
22527
+ const model2 = listed.models().find((candidate) => candidate.id === modelId);
22408
22528
  if (!model2) {
22409
22529
  return {
22410
22530
  ok: false,
22411
22531
  reason: "other",
22412
- message: `${providerId} publishes no models to check against`
22532
+ message: `${providerId} does not publish model "${modelId}"`
22413
22533
  };
22414
22534
  }
22415
22535
  let resolved;
@@ -22485,7 +22605,7 @@ async function interactiveCommand(args) {
22485
22605
  return 2;
22486
22606
  }
22487
22607
  const extensions = await startExtensions(process.cwd());
22488
- const model2 = typeof flags.model === "string" ? flags.model : DEFAULT_MODEL3;
22608
+ let model2 = typeof flags.model === "string" ? flags.model : DEFAULT_MODEL3;
22489
22609
  const onboardingAllowed = flags["no-onboarding"] !== true;
22490
22610
  let firstPrompt = initialPrompt;
22491
22611
  let attempted = false;
@@ -22513,12 +22633,14 @@ async function interactiveCommand(args) {
22513
22633
  } catch (error) {
22514
22634
  if (error instanceof MissingCredentialsError && onboardingAllowed && !attempted) {
22515
22635
  attempted = true;
22516
- const result = await runOnboarding(await buildOnboardingOptions(error.provider.id));
22636
+ const result = await runOnboarding(await buildOnboardingOptions(error.provider.id, model2));
22517
22637
  if (result.outcome === "quit") {
22518
22638
  process.stdout.write("nothing was stored. run `earshot auth login <provider>` when you are ready.\n");
22519
22639
  await extensions.close();
22520
22640
  return 0;
22521
22641
  }
22642
+ if (result.model)
22643
+ model2 = result.model;
22522
22644
  firstPrompt = result.firstPrompt ?? firstPrompt;
22523
22645
  continue;
22524
22646
  }
@@ -22757,23 +22879,38 @@ function compareVersions(a, b) {
22757
22879
  return -1;
22758
22880
  return left.pre < right.pre ? -1 : 1;
22759
22881
  }
22760
- async function resolveLatest(kind, fetchImpl) {
22761
- if (kind === "npm") {
22762
- const response2 = await fetchImpl(REGISTRY);
22763
- if (!response2.ok)
22764
- throw new Error(`npm registry returned ${response2.status}`);
22765
- const body2 = await response2.json();
22766
- if (!body2.version)
22767
- throw new Error("npm registry returned no version");
22768
- return body2.version;
22769
- }
22770
- const response = await fetchImpl(RELEASE);
22882
+ function releaseAuth(env) {
22883
+ const token = env.EARSHOT_GITHUB_TOKEN ?? env.GITHUB_TOKEN ?? env.GH_TOKEN;
22884
+ return token ? { headers: { authorization: `Bearer ${token}` } } : {};
22885
+ }
22886
+ function releaseNotFound(env) {
22887
+ return releaseAuth(env).headers === undefined ? "GitHub returned 404. The releases are not public, so this needs a token: " + "set GITHUB_TOKEN (or GH_TOKEN) to one that can read the repository." : "GitHub returned 404 for the token in GITHUB_TOKEN; it may not have access " + "to this repository.";
22888
+ }
22889
+ async function fetchRelease(fetchImpl, env) {
22890
+ const response = await fetchImpl(RELEASE, releaseAuth(env));
22891
+ if (response.status === 404)
22892
+ throw new Error(releaseNotFound(env));
22771
22893
  if (!response.ok)
22772
22894
  throw new Error(`GitHub releases returned ${response.status}`);
22773
22895
  const body = await response.json();
22774
22896
  if (!body.tag_name)
22775
22897
  throw new Error("GitHub returned a release with no tag");
22776
- return body.tag_name.replace(/^v/, "");
22898
+ const assets = {};
22899
+ for (const asset of body.assets ?? [])
22900
+ assets[asset.name] = asset.url;
22901
+ return { version: body.tag_name.replace(/^v/, ""), assets };
22902
+ }
22903
+ async function resolveLatest(kind, fetchImpl, env = process.env) {
22904
+ if (kind === "npm") {
22905
+ const response = await fetchImpl(REGISTRY);
22906
+ if (!response.ok)
22907
+ throw new Error(`npm registry returned ${response.status}`);
22908
+ const body = await response.json();
22909
+ if (!body.version)
22910
+ throw new Error("npm registry returned no version");
22911
+ return body.version;
22912
+ }
22913
+ return (await fetchRelease(fetchImpl, env)).version;
22777
22914
  }
22778
22915
  function findChecksum(sums, asset) {
22779
22916
  for (const line of sums.split(`
@@ -22811,7 +22948,7 @@ async function runUpdate(options = {}) {
22811
22948
  },
22812
22949
  isProjectRoot: (dir) => existsSync2(join19(dir, "package.json"))
22813
22950
  });
22814
- const fetchImpl = options.fetch ?? ((url) => fetch(url));
22951
+ const fetchImpl = options.fetch ?? ((url, init) => fetch(url, init));
22815
22952
  if (install.kind === "source" || install.kind === "unknown") {
22816
22953
  err(`earshot update: ${install.reason}
22817
22954
  `);
@@ -22826,8 +22963,14 @@ async function runUpdate(options = {}) {
22826
22963
  return 2;
22827
22964
  }
22828
22965
  let latest;
22966
+ let release2;
22829
22967
  try {
22830
- latest = await resolveLatest(install.kind, fetchImpl);
22968
+ if (install.kind === "binary") {
22969
+ release2 = await fetchRelease(fetchImpl, options.env ?? process.env);
22970
+ latest = release2.version;
22971
+ } else {
22972
+ latest = await resolveLatest(install.kind, fetchImpl, options.env ?? process.env);
22973
+ }
22831
22974
  } catch (error) {
22832
22975
  err(`earshot update: ${error.message}
22833
22976
  `);
@@ -22871,7 +23014,7 @@ async function runUpdate(options = {}) {
22871
23014
  `);
22872
23015
  return 0;
22873
23016
  }
22874
- return await updateBinary(install, latest, options, out, err);
23017
+ return await updateBinary(install, release2, options, out, err);
22875
23018
  }
22876
23019
  function runCommand2(command, args) {
22877
23020
  const result = spawnSync2(command, args, { stdio: "inherit", windowsHide: true, shell: false });
@@ -22894,11 +23037,12 @@ async function defaultConfirm(question) {
22894
23037
  rl.close();
22895
23038
  }
22896
23039
  }
22897
- async function updateBinary(install, latest, options, out, err) {
23040
+ async function updateBinary(install, release2, options, out, err) {
22898
23041
  const target = install.path;
22899
23042
  const asset = install.asset;
22900
23043
  const dir = dirname9(target);
22901
- const fetchImpl = options.fetch ?? ((url) => fetch(url));
23044
+ const latest = release2.version;
23045
+ const fetchImpl = options.fetch ?? ((url, init) => fetch(url, init));
22902
23046
  await sweepStale(dir, target);
22903
23047
  out(` ${target} ${asset}
22904
23048
  `);
@@ -22919,16 +23063,29 @@ async function updateBinary(install, latest, options, out, err) {
22919
23063
  `);
22920
23064
  return 0;
22921
23065
  }
22922
- const base = `https://github.com/${REPO}/releases/download/v${latest}`;
23066
+ const assetUrl = release2.assets[asset];
23067
+ const sumsUrl = release2.assets.SHA256SUMS;
23068
+ if (assetUrl === undefined || sumsUrl === undefined) {
23069
+ err(`earshot update: release v${latest} does not publish ${assetUrl ? "SHA256SUMS" : asset}
23070
+ `);
23071
+ return 1;
23072
+ }
22923
23073
  const temp = join19(dir, `.earshot-update-${process.pid}.tmp`);
22924
23074
  try {
23075
+ const auth2 = releaseAuth(options.env ?? process.env);
23076
+ const octet = {
23077
+ ...auth2,
23078
+ headers: { ...auth2.headers, accept: "application/octet-stream" }
23079
+ };
22925
23080
  out(" downloading… ");
22926
- const download = await fetchImpl(`${base}/${asset}`);
23081
+ const download = await fetchImpl(assetUrl, octet);
23082
+ if (download.status === 404)
23083
+ throw new Error(releaseNotFound(options.env ?? process.env));
22927
23084
  if (!download.ok)
22928
23085
  throw new Error(`downloading ${asset} returned ${download.status}`);
22929
23086
  const bytes = new Uint8Array(await download.arrayBuffer());
22930
23087
  out("verifying SHA256… ");
22931
- const sumsResponse = await fetchImpl(`${base}/SHA256SUMS`);
23088
+ const sumsResponse = await fetchImpl(sumsUrl, octet);
22932
23089
  if (!sumsResponse.ok)
22933
23090
  throw new Error(`SHA256SUMS returned ${sumsResponse.status}`);
22934
23091
  const expected = findChecksum(await sumsResponse.text(), asset);
@@ -23068,5 +23225,5 @@ async function main(argv = process.argv.slice(2)) {
23068
23225
  var code = await main();
23069
23226
  process.exitCode = code;
23070
23227
 
23071
- //# debugId=8F9F015F9221906F64756E2164756E21
23228
+ //# debugId=50400322D722C83B64756E2164756E21
23072
23229
  //# sourceMappingURL=main.js.map