shipr-agent 0.1.3 → 0.1.5

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 (2) hide show
  1. package/dist/index.js +155 -57
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -101309,70 +101309,156 @@ async function handleSimulate(args, state2) {
101309
101309
  process.stdout.write(PROMPT);
101310
101310
  });
101311
101311
  }
101312
- function handleModel(args, state2) {
101312
+ function interactivePick(title, items) {
101313
+ return new Promise((resolve) => {
101314
+ let cursor = items.findIndex((i2) => i2.active) ?? 0;
101315
+ if (cursor < 0)
101316
+ cursor = 0;
101317
+ const stdin = process.stdin;
101318
+ const wasRaw = stdin.isRaw;
101319
+ function render2() {
101320
+ const totalLines = items.length + 4;
101321
+ process.stdout.write(`\x1B[${totalLines}A\x1B[0J`);
101322
+ draw();
101323
+ }
101324
+ function draw() {
101325
+ console.log("");
101326
+ console.log(` ${BRAND_BOLD(title)} ${DIM2("↑↓ navigate Enter select q back")}`);
101327
+ console.log("");
101328
+ let lastGroup = "";
101329
+ for (let i2 = 0;i2 < items.length; i2++) {
101330
+ const item = items[i2];
101331
+ if (item.group && item.group !== lastGroup) {
101332
+ if (lastGroup)
101333
+ console.log("");
101334
+ lastGroup = item.group;
101335
+ }
101336
+ const selected = i2 === cursor;
101337
+ const pointer = selected ? BRAND8("❯ ") : " ";
101338
+ const label = selected ? source_default.bold(item.label) : item.label;
101339
+ const hint = item.hint ? ` ${DIM2(item.hint)}` : "";
101340
+ const activeTag = item.active ? source_default.green(" ◀") : "";
101341
+ console.log(` ${pointer}${label}${hint}${activeTag}`);
101342
+ }
101343
+ console.log("");
101344
+ }
101345
+ function cleanup() {
101346
+ stdin.removeListener("data", onKey);
101347
+ stdin.setRawMode(wasRaw ?? false);
101348
+ if (!stdin.isRaw) {
101349
+ stdin.resume();
101350
+ }
101351
+ }
101352
+ function onKey(data) {
101353
+ const key = data.toString();
101354
+ if (key === "q" || key === "\x1B" || key === "\x03") {
101355
+ cleanup();
101356
+ console.log(DIM2(" Cancelled."));
101357
+ resolve(null);
101358
+ return;
101359
+ }
101360
+ if (key === "\r" || key === `
101361
+ `) {
101362
+ cleanup();
101363
+ const selected = items[cursor];
101364
+ console.log(source_default.green(" ✓"), `Selected: ${source_default.bold(selected.label)}`);
101365
+ resolve(selected.value);
101366
+ return;
101367
+ }
101368
+ if (key === "\x1B[A" || key === "k") {
101369
+ cursor = cursor > 0 ? cursor - 1 : items.length - 1;
101370
+ render2();
101371
+ return;
101372
+ }
101373
+ if (key === "\x1B[B" || key === "j") {
101374
+ cursor = cursor < items.length - 1 ? cursor + 1 : 0;
101375
+ render2();
101376
+ return;
101377
+ }
101378
+ }
101379
+ stdin.setRawMode(true);
101380
+ stdin.resume();
101381
+ stdin.on("data", onKey);
101382
+ draw();
101383
+ });
101384
+ }
101385
+ async function handleModel(args, state2, rl) {
101313
101386
  const parts = args.trim().split(/\s+/).filter(Boolean);
101314
- if (parts.length === 0) {
101315
- console.log("");
101316
- console.log(` ${BRAND8("Provider:")} ${source_default.bold(state2.activeProvider)}`);
101317
- console.log(` ${BRAND8("Model:")} ${source_default.bold(state2.activeModel)}`);
101318
- console.log("");
101319
- console.log(DIM2(" Usage:"));
101320
- console.log(DIM2(" /model <provider> Switch provider (uses default model)"));
101321
- console.log(DIM2(" /model <provider> <model> Switch provider and model"));
101322
- console.log("");
101323
- console.log(DIM2(" Available:"));
101324
- const providers = listProviders();
101325
- for (const name of providers) {
101326
- const factory = PROVIDER_MAP[name];
101327
- if (!factory)
101328
- continue;
101329
- const p = factory();
101330
- const models = p.getModels();
101331
- const active = name === state2.activeProvider ? BRAND8(" ◀ active") : "";
101332
- console.log(` ${source_default.bold(name)}${active}`);
101333
- for (const m of models) {
101334
- const isActive = name === state2.activeProvider && m.id === state2.activeModel;
101335
- const marker = isActive ? source_default.green(" ● ") : " ";
101336
- const ctx = `${(m.contextWindow / 1000).toFixed(0)}k`;
101337
- console.log(`${marker}${m.id} ${DIM2(ctx)}`);
101387
+ if (parts.length >= 1) {
101388
+ const providerName = parts[0];
101389
+ const allProviders = listProviders();
101390
+ const match = allProviders.find((p) => p === providerName) ?? allProviders.find((p) => p.startsWith(providerName));
101391
+ if (!match) {
101392
+ console.log(source_default.red(" "), `Unknown provider: ${providerName}`);
101393
+ console.log(DIM2(` Available: ${allProviders.join(", ")}`));
101394
+ return;
101395
+ }
101396
+ state2.activeProvider = match;
101397
+ if (parts.length >= 2) {
101398
+ const modelId = parts[1];
101399
+ const available = getAllModelsForProvider(match);
101400
+ const exactMatch = available.find((m) => m === modelId);
101401
+ const fuzzyMatch = available.find((m) => m.includes(modelId));
101402
+ state2.activeModel = exactMatch ?? fuzzyMatch ?? getDefaultModel(match);
101403
+ if (!exactMatch && !fuzzyMatch) {
101404
+ console.log(source_default.yellow(""), `Model "${modelId}" not found. Using default.`);
101338
101405
  }
101406
+ } else {
101407
+ state2.activeModel = getDefaultModel(match);
101339
101408
  }
101340
- console.log("");
101409
+ console.log(source_default.green(""), `Provider: ${source_default.bold(state2.activeProvider)} Model: ${source_default.bold(state2.activeModel)}`);
101341
101410
  return;
101342
101411
  }
101343
- const providerName = parts[0];
101344
- const allProviders = listProviders();
101345
- if (!allProviders.includes(providerName)) {
101346
- const match = allProviders.find((p) => p.startsWith(providerName));
101347
- if (match) {
101348
- state2.activeProvider = match;
101349
- state2.activeModel = getDefaultModel(match);
101350
- console.log(source_default.green(" ✓"), `Provider: ${source_default.bold(match)} Model: ${source_default.bold(state2.activeModel)}`);
101351
- return;
101352
- }
101353
- console.log(source_default.red(" ✗"), `Unknown provider: ${providerName}`);
101354
- console.log(DIM2(` Available: ${allProviders.join(", ")}`));
101412
+ rl.pause();
101413
+ const providers = listProviders();
101414
+ const providerItems = providers.map((name) => {
101415
+ const factory2 = PROVIDER_MAP[name];
101416
+ const models2 = factory2 ? factory2().getModels() : [];
101417
+ return {
101418
+ label: name,
101419
+ value: name,
101420
+ hint: `${models2.length} model${models2.length !== 1 ? "s" : ""}`,
101421
+ active: name === state2.activeProvider
101422
+ };
101423
+ });
101424
+ const chosenProvider = await interactivePick("Select Provider", providerItems);
101425
+ if (!chosenProvider) {
101426
+ rl.resume();
101355
101427
  return;
101356
101428
  }
101357
- state2.activeProvider = providerName;
101358
- if (parts.length >= 2) {
101359
- const modelId = parts[1];
101360
- const available = getAllModelsForProvider(providerName);
101361
- const exactMatch = available.find((m) => m === modelId);
101362
- const fuzzyMatch = available.find((m) => m.includes(modelId));
101363
- if (exactMatch) {
101364
- state2.activeModel = exactMatch;
101365
- } else if (fuzzyMatch) {
101366
- state2.activeModel = fuzzyMatch;
101367
- } else {
101368
- console.log(source_default.yellow(" ⚠"), `Model "${modelId}" not found for ${providerName}. Using default.`);
101369
- console.log(DIM2(` Available: ${available.join(", ")}`));
101370
- state2.activeModel = getDefaultModel(providerName);
101371
- }
101372
- } else {
101373
- state2.activeModel = getDefaultModel(providerName);
101429
+ state2.activeProvider = chosenProvider;
101430
+ const models = getAllModelsForProvider(chosenProvider);
101431
+ const defaultModel = getDefaultModel(chosenProvider);
101432
+ if (models.length <= 1) {
101433
+ state2.activeModel = models[0] ?? defaultModel;
101434
+ console.log(source_default.green(" ✓"), `Provider: ${source_default.bold(state2.activeProvider)} Model: ${source_default.bold(state2.activeModel)}`);
101435
+ rl.resume();
101436
+ return;
101374
101437
  }
101438
+ const factory = PROVIDER_MAP[chosenProvider];
101439
+ const providerInstance = factory ? factory() : null;
101440
+ const modelDefs = providerInstance ? providerInstance.getModels() : [];
101441
+ const modelItems = models.map((id) => {
101442
+ const def = modelDefs.find((m) => m.id === id);
101443
+ const ctx = def ? `${(def.contextWindow / 1000).toFixed(0)}k` : "";
101444
+ const price = def && def.inputPricePer1M > 0 ? `$${def.inputPricePer1M.toFixed(2)}/$${def.outputPricePer1M.toFixed(2)}` : def ? "free" : "";
101445
+ return {
101446
+ label: id,
101447
+ value: id,
101448
+ hint: [ctx, price].filter(Boolean).join(" "),
101449
+ active: id === state2.activeModel && chosenProvider === state2.activeProvider
101450
+ };
101451
+ });
101452
+ const chosenModel = await interactivePick("Select Model", modelItems);
101453
+ if (!chosenModel) {
101454
+ state2.activeModel = defaultModel;
101455
+ console.log(source_default.green(" ✓"), `Provider: ${source_default.bold(state2.activeProvider)} Model: ${source_default.bold(state2.activeModel)}`);
101456
+ rl.resume();
101457
+ return;
101458
+ }
101459
+ state2.activeModel = chosenModel;
101375
101460
  console.log(source_default.green(" ✓"), `Provider: ${source_default.bold(state2.activeProvider)} Model: ${source_default.bold(state2.activeModel)}`);
101461
+ rl.resume();
101376
101462
  }
101377
101463
  async function handleStatus() {
101378
101464
  const { readdir: readdir8, readFile: readFile21 } = await import("node:fs/promises");
@@ -101753,7 +101839,7 @@ async function startRepl() {
101753
101839
  await handleCost();
101754
101840
  break;
101755
101841
  case "/model":
101756
- handleModel(args, state2);
101842
+ await handleModel(args, state2, rl);
101757
101843
  break;
101758
101844
  case "/auth":
101759
101845
  await handleAuth(args);
@@ -101829,6 +101915,9 @@ ${BRAND_BOLD(" ╚══════╝╚═╝ ╚═╝╚═╝╚═╝
101829
101915
  `;
101830
101916
  });
101831
101917
 
101918
+ // src/index.ts
101919
+ import { createRequire as createRequire2 } from "module";
101920
+
101832
101921
  // node_modules/commander/esm.mjs
101833
101922
  var import__ = __toESM(require_commander(), 1);
101834
101923
  var {
@@ -103278,13 +103367,22 @@ async function findActiveMission(cwd2) {
103278
103367
  }
103279
103368
 
103280
103369
  // src/index.ts
103370
+ function getVersion() {
103371
+ try {
103372
+ const require2 = createRequire2(import.meta.url);
103373
+ const pkg = require2("../package.json");
103374
+ return pkg.version;
103375
+ } catch {
103376
+ return "0.1.5";
103377
+ }
103378
+ }
103281
103379
  var hasArgs = process.argv.length > 2;
103282
103380
  if (!hasArgs) {
103283
103381
  const { startRepl: startRepl2 } = await init_repl().then(() => exports_repl);
103284
103382
  await startRepl2();
103285
103383
  } else {
103286
103384
  const program2 = new Command;
103287
- program2.name("shipr").version("0.1.1").description("Fully autonomous terminal-based coding agent");
103385
+ program2.name("shipr").version(getVersion()).description("Fully autonomous terminal-based coding agent");
103288
103386
  registerRunCommand(program2);
103289
103387
  registerNewCommand(program2);
103290
103388
  registerResumeCommand(program2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shipr-agent",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Fully autonomous terminal-based coding agent",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,7 +14,7 @@
14
14
  ],
15
15
  "scripts": {
16
16
  "dev": "bun src/index.ts",
17
- "build": "bun build src/index.ts --outdir dist --target node --format esm && node -e \"const fs=require('fs');const f='dist/index.js';let c=fs.readFileSync(f,'utf8');c=c.replace('#!/usr/bin/env bun','#!/usr/bin/env node');fs.writeFileSync(f,c)\"",
17
+ "build": "bun build src/index.ts --outdir dist --target node --format esm && node -e \"const fs=require('fs');const f='dist/index.js';const pkg=JSON.parse(fs.readFileSync('package.json','utf8'));let c=fs.readFileSync(f,'utf8');c=c.replace('#!/usr/bin/env bun','#!/usr/bin/env node');c=c.replace('__SHIPR_VERSION__',pkg.version);fs.writeFileSync(f,c)\"",
18
18
  "build:bin": "bun build src/index.ts --compile --outfile shipr",
19
19
  "typecheck": "bunx tsc --noEmit",
20
20
  "lint": "bunx biome check src/",