@dosu/cli 0.11.0-alpha.5 → 0.11.0-alpha.6

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/bin/dosu.js +96 -33
  2. package/package.json +1 -1
package/bin/dosu.js CHANGED
@@ -4341,7 +4341,7 @@ function getSupabaseAnonKey() {
4341
4341
  function getVersionString() {
4342
4342
  return `v${VERSION}`;
4343
4343
  }
4344
- var VERSION = "0.11.0-alpha.5";
4344
+ var VERSION = "0.11.0-alpha.6";
4345
4345
 
4346
4346
  // src/debug/logger.ts
4347
4347
  import {
@@ -6439,12 +6439,13 @@ function visibleOptions(cursor, options, maxItems) {
6439
6439
  return { kind: "option", index: start + index };
6440
6440
  });
6441
6441
  }
6442
- var import_picocolors22, ACTION_ARROW, ADD_REPOSITORIES_VALUE = "__add_repositories__", GitHubRepoPrompt;
6442
+ var import_picocolors22, ACTION_ARROW, SEPARATOR_LINE, ADD_REPOSITORIES_VALUE = "__add_repositories__", REFRESH_LIST_VALUE = "__refresh_list__", GitHubRepoPrompt;
6443
6443
  var init_github_repo_prompt = __esm(() => {
6444
6444
  init_dist5();
6445
6445
  init_prompt_symbols();
6446
6446
  import_picocolors22 = __toESM(require_picocolors(), 1);
6447
6447
  ACTION_ARROW = symbol("→", ">");
6448
+ SEPARATOR_LINE = "─".repeat(30);
6448
6449
  GitHubRepoPrompt = class GitHubRepoPrompt extends x {
6449
6450
  options;
6450
6451
  message;
@@ -6461,7 +6462,8 @@ var init_github_repo_prompt = __esm(() => {
6461
6462
  this.options = options;
6462
6463
  this.maxItems = maxItems;
6463
6464
  this.selected = initialValues.filter((value) => options.some((option) => option.kind === "repo" && option.value === value));
6464
- this.cursor = Math.max(this.options.findIndex((option) => option.kind === "repo" && this.selected.includes(option.value)), 0);
6465
+ const initialCursor = this.options.findIndex((option) => option.kind === "repo" && this.selected.includes(option.value));
6466
+ this.cursor = initialCursor >= 0 ? initialCursor : this.firstFocusableIndex();
6465
6467
  this.syncValue();
6466
6468
  this.on("key", (key) => {
6467
6469
  if (key === "a") {
@@ -6473,11 +6475,11 @@ var init_github_repo_prompt = __esm(() => {
6473
6475
  switch (key) {
6474
6476
  case "left":
6475
6477
  case "up":
6476
- this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
6478
+ this.cursor = this.advanceCursor(-1);
6477
6479
  break;
6478
6480
  case "down":
6479
6481
  case "right":
6480
- this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
6482
+ this.cursor = this.advanceCursor(1);
6481
6483
  break;
6482
6484
  case "space":
6483
6485
  this.toggleCurrent();
@@ -6486,6 +6488,22 @@ var init_github_repo_prompt = __esm(() => {
6486
6488
  this.syncValue();
6487
6489
  });
6488
6490
  }
6491
+ firstFocusableIndex() {
6492
+ const idx = this.options.findIndex((option) => option.kind !== "separator");
6493
+ return idx >= 0 ? idx : 0;
6494
+ }
6495
+ advanceCursor(direction) {
6496
+ const total = this.options.length;
6497
+ if (total === 0)
6498
+ return 0;
6499
+ let next = this.cursor;
6500
+ for (let i = 0;i < total; i++) {
6501
+ next = (next + direction + total) % total;
6502
+ if (this.options[next].kind !== "separator")
6503
+ return next;
6504
+ }
6505
+ return this.cursor;
6506
+ }
6489
6507
  get currentOption() {
6490
6508
  return this.options[this.cursor] ?? this.options[0];
6491
6509
  }
@@ -6493,10 +6511,11 @@ var init_github_repo_prompt = __esm(() => {
6493
6511
  this.value = this.currentOption.kind === "action" ? this.currentOption.value : [...this.selected];
6494
6512
  }
6495
6513
  toggleCurrent() {
6496
- if (this.currentOption.kind !== "repo")
6514
+ const current = this.currentOption;
6515
+ if (current.kind !== "repo")
6497
6516
  return;
6498
- const selected = this.selected.includes(this.currentOption.value);
6499
- this.selected = selected ? this.selected.filter((value) => value !== this.currentOption.value) : [...this.selected, this.currentOption.value];
6517
+ const selected = this.selected.includes(current.value);
6518
+ this.selected = selected ? this.selected.filter((value) => value !== current.value) : [...this.selected, current.value];
6500
6519
  }
6501
6520
  toggleAll() {
6502
6521
  const repoValues = this.options.filter((option) => option.kind === "repo").map((option) => option.value);
@@ -6514,12 +6533,14 @@ ${symbolByState} ${this.message}
6514
6533
  return `${header}${import_picocolors22.default.gray(BAR)}`;
6515
6534
  }
6516
6535
  const body = visibleOptions(this.cursor, this.options, this.maxItems).map((option) => {
6517
- const actualIndex = option.kind === "ellipsis" ? -1 : option.index;
6518
6536
  if (option.kind === "ellipsis") {
6519
6537
  return `${import_picocolors22.default.gray(BAR)} ${import_picocolors22.default.dim(ELLIPSIS)}`;
6520
6538
  }
6521
- const isActive = actualIndex === this.cursor;
6522
- const current = this.options[actualIndex];
6539
+ const current = this.options[option.index];
6540
+ if (current.kind === "separator") {
6541
+ return `${import_picocolors22.default.gray(BAR)} ${import_picocolors22.default.dim(SEPARATOR_LINE)}`;
6542
+ }
6543
+ const isActive = option.index === this.cursor;
6523
6544
  const marker = current.kind === "action" ? isActive ? import_picocolors22.default.cyan(ACTION_ARROW) : import_picocolors22.default.dim(ACTION_ARROW) : this.selected.includes(current.value) ? isActive ? import_picocolors22.default.cyan(CHECKBOX_ON) : CHECKBOX_ON : isActive ? import_picocolors22.default.cyan(CHECKBOX_OFF) : CHECKBOX_OFF;
6524
6545
  const label = isActive ? import_picocolors22.default.cyan(current.label) : current.label;
6525
6546
  const hint = current.hint ? ` ${import_picocolors22.default.dim(`(${current.hint})`)}` : "";
@@ -6530,9 +6551,12 @@ ${symbolByState} ${this.message}
6530
6551
  ${import_picocolors22.default.cyan(FOOTER)}`;
6531
6552
  }
6532
6553
  submitLabel() {
6533
- if (this.value === ADD_REPOSITORIES_VALUE) {
6534
- const action = this.options.find((option) => option.kind === "action");
6535
- return action?.label ?? "Add repositories...";
6554
+ if (typeof this.value === "string") {
6555
+ const matched = this.options.find((option) => option.kind === "action" && option.value === this.value);
6556
+ if (matched && matched.kind === "action")
6557
+ return matched.label;
6558
+ const fallback = this.options.find((option) => option.kind === "action");
6559
+ return fallback && fallback.kind === "action" ? fallback.label : "Add repositories...";
6536
6560
  }
6537
6561
  const selectedValues = Array.isArray(this.value) ? this.value : [];
6538
6562
  if (selectedValues.length === 0) {
@@ -7206,8 +7230,15 @@ function buildPromptOptions(repos) {
7206
7230
  kind: "action",
7207
7231
  label: "Add repositories...",
7208
7232
  value: ADD_REPOSITORIES_VALUE,
7209
- hint: "Open GitHub and refresh this list"
7233
+ hint: "Open GitHub to install/update access"
7210
7234
  },
7235
+ {
7236
+ kind: "action",
7237
+ label: "Refresh list",
7238
+ value: REFRESH_LIST_VALUE,
7239
+ hint: "Re-check Dosu for new repos"
7240
+ },
7241
+ { kind: "separator" },
7211
7242
  ...repos.map((r) => ({ kind: "repo", label: r.slug, value: r.slug }))
7212
7243
  ];
7213
7244
  }
@@ -7218,20 +7249,23 @@ function hasNewVisibleRepository(previousRepos, nextRepos) {
7218
7249
  function sleep2(ms) {
7219
7250
  return new Promise((resolve) => setTimeout(resolve, ms));
7220
7251
  }
7221
- async function waitForRepositoryRefresh(trpc, orgID, previousRepos) {
7252
+ async function waitForRepositoryRefresh(trpc, orgID, previousRepos, opts) {
7253
+ const timeoutMs = opts?.timeoutMs ?? REPO_REFRESH_POLL_TIMEOUT_MS;
7254
+ const intervalMs = opts?.intervalMs ?? REPO_REFRESH_POLL_INTERVAL_MS;
7222
7255
  const startedAt = Date.now();
7223
7256
  let latestRepos = previousRepos;
7224
- while (Date.now() - startedAt < REPO_REFRESH_POLL_TIMEOUT_MS) {
7257
+ while (Date.now() - startedAt < timeoutMs) {
7225
7258
  const polledRepos = await fetchListForOrg(trpc, orgID);
7226
7259
  latestRepos = polledRepos.length === 0 && previousRepos.length > 0 ? previousRepos : polledRepos;
7227
7260
  if (hasNewVisibleRepository(previousRepos, latestRepos)) {
7228
- return latestRepos;
7261
+ return { repos: latestRepos, foundNew: true };
7229
7262
  }
7230
- await sleep2(REPO_REFRESH_POLL_INTERVAL_MS);
7263
+ await sleep2(intervalMs);
7231
7264
  }
7232
- return latestRepos;
7265
+ return { repos: latestRepos, foundNew: false };
7233
7266
  }
7234
- async function openGitHubInstallFlow(onInstalled) {
7267
+ async function openGitHubInstallFlow(onInstalled, opts) {
7268
+ const timeoutMs = opts?.timeoutMs ?? INSTALLATION_TIMEOUT_MS;
7235
7269
  const { server, installationPromise } = await startInstallationCallbackServer();
7236
7270
  let timeoutId;
7237
7271
  try {
@@ -7251,9 +7285,9 @@ async function openGitHubInstallFlow(onInstalled) {
7251
7285
  }
7252
7286
  const timeout = new Promise((resolve) => {
7253
7287
  timeoutId = setTimeout(() => {
7254
- logger.warn("setup", `GitHub install timed out after ${INSTALLATION_TIMEOUT_MS / 1000}s`);
7288
+ logger.warn("setup", `GitHub install timed out after ${timeoutMs / 1000}s`);
7255
7289
  resolve(null);
7256
- }, INSTALLATION_TIMEOUT_MS);
7290
+ }, timeoutMs);
7257
7291
  });
7258
7292
  const s = Y2();
7259
7293
  s.start("Waiting for GitHub install to complete...");
@@ -7263,7 +7297,7 @@ async function openGitHubInstallFlow(onInstalled) {
7263
7297
  ]);
7264
7298
  if (result === null) {
7265
7299
  s.stop("Timed out");
7266
- M2.warn(`Didn't hear back from the browser after ${Math.floor(INSTALLATION_TIMEOUT_MS / 1000)}s. Run \`dosu setup\` again once you've completed the install.`);
7300
+ M2.warn(`Didn't hear back from the browser after ${Math.floor(timeoutMs / 1000)}s. Run \`dosu setup\` again once you've completed the install.`);
7267
7301
  return null;
7268
7302
  }
7269
7303
  if (onInstalled) {
@@ -7399,14 +7433,26 @@ ${lines}`);
7399
7433
  return { advance: false, has_connected_repo: deployed.length > 0 };
7400
7434
  }
7401
7435
  if (selected === ADD_REPOSITORIES_VALUE) {
7402
- let refreshedRepos = repos;
7436
+ let refresh = { repos, foundNew: false };
7403
7437
  const installationID = await openGitHubInstallFlow(async () => {
7404
- refreshedRepos = await waitForRepositoryRefresh(trpc, orgID, repos);
7405
- });
7438
+ refresh = await waitForRepositoryRefresh(trpc, orgID, repos, opts.refresh);
7439
+ }, opts.install);
7406
7440
  if (installationID === null) {
7407
7441
  return { advance: false, has_connected_repo: deployed.length > 0 };
7408
7442
  }
7409
- repos = refreshedRepos;
7443
+ repos = refresh.repos;
7444
+ if (!refresh.foundNew) {
7445
+ M2.warn("GitHub may still be syncing. Pick 'Refresh list' in a moment to re-check — sync usually completes within a minute.");
7446
+ }
7447
+ continue;
7448
+ }
7449
+ if (selected === REFRESH_LIST_VALUE) {
7450
+ const s2 = Y2();
7451
+ s2.start("Refreshing repository list...");
7452
+ const previousIds = new Set(repos.map((r) => r.repository_id));
7453
+ repos = await fetchListForOrg(trpc, orgID);
7454
+ const newCount = repos.filter((r) => !previousIds.has(r.repository_id)).length;
7455
+ s2.stop(newCount > 0 ? `Found ${newCount} new repo${newCount === 1 ? "" : "s"}` : "List refreshed — no new repos yet");
7410
7456
  continue;
7411
7457
  }
7412
7458
  const slugs = selected;
@@ -8349,6 +8395,8 @@ __export(exports_flow2, {
8349
8395
  runInstallSkill: () => runInstallSkill,
8350
8396
  isStdioOnly: () => isStdioOnly
8351
8397
  });
8398
+ import { existsSync as existsSync9 } from "node:fs";
8399
+ import { join as join19 } from "node:path";
8352
8400
  async function runSetup(opts = {}) {
8353
8401
  logger.info("setup", `Setup flow started${opts.deploymentID ? ` deployment=${opts.deploymentID}` : ""}${opts.mode ? ` mode=${opts.mode}` : ""}`);
8354
8402
  Ie("Dosu CLI Setup");
@@ -8439,7 +8487,11 @@ async function runSetup(opts = {}) {
8439
8487
  }
8440
8488
  }
8441
8489
  if (mcpConfiguredThisRun) {
8442
- showTryItOutPrompt(cfg.mode);
8490
+ showTryItOutPrompt({
8491
+ mode: cfg.mode,
8492
+ docsImported: choices.connectGitHub && githubOnboardingDone,
8493
+ hasAgentsMd: existsSync9(join19(process.cwd(), "AGENTS.md"))
8494
+ });
8443
8495
  }
8444
8496
  if (cfg.mode === MODE_OSS) {
8445
8497
  Se("Setup complete! Using open-source libraries only.\n\nTips: Run `dosu setup --mode cloud` to connect your own repos.");
@@ -8799,12 +8851,12 @@ async function stepSelectTools(detected) {
8799
8851
  return {
8800
8852
  label: p2.name(),
8801
8853
  value: p2.id(),
8802
- hint: configured ? "configured" : undefined
8854
+ hint: configured ? "configured — untick to remove" : undefined
8803
8855
  };
8804
8856
  });
8805
8857
  const preselected = detected.filter((p2) => configuredMap.get(p2.id())).map((p2) => p2.id());
8806
8858
  const selected = await fe({
8807
- message: "Select agents to configure or update",
8859
+ message: "Select agents — tick to configure, untick to remove",
8808
8860
  options,
8809
8861
  initialValues: preselected
8810
8862
  });
@@ -8875,8 +8927,19 @@ ${lines}`);
8875
8927
  M2.success("All agents already configured. No changes needed.");
8876
8928
  }
8877
8929
  }
8878
- function showTryItOutPrompt(mode) {
8879
- const prompt = mode === MODE_OSS ? `What can Dosu help me with? Pick an open source library related to my project and explain how it works.` : `Please use Dosu to host my AGENTS.md`;
8930
+ function showTryItOutPrompt(opts = {}) {
8931
+ const prompt = (() => {
8932
+ if (opts.mode === MODE_OSS) {
8933
+ return `What can Dosu help me with? Pick an open source library related to my project and explain how it works.`;
8934
+ }
8935
+ if (opts.docsImported) {
8936
+ return `Use Dosu to summarize the most important docs in my repo.`;
8937
+ }
8938
+ if (opts.hasAgentsMd) {
8939
+ return `Please use Dosu to host my AGENTS.md`;
8940
+ }
8941
+ return `Ask Dosu to draft an AGENTS.md for this project.`;
8942
+ })();
8880
8943
  M2.message(`Try it out! Paste this into your agent:
8881
8944
 
8882
8945
  ${info(prompt)}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dosu/cli",
3
- "version": "0.11.0-alpha.5",
3
+ "version": "0.11.0-alpha.6",
4
4
  "type": "module",
5
5
  "description": "Dosu CLI - Manage MCP servers for AI tools",
6
6
  "license": "MIT",