@dosu/cli 0.30.0 → 0.32.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.
Files changed (2) hide show
  1. package/bin/dosu.js +318 -900
  2. package/package.json +1 -1
package/bin/dosu.js CHANGED
@@ -4577,7 +4577,7 @@ var init_dist4 = __esm(() => {
4577
4577
  function getVersionString() {
4578
4578
  return `v${VERSION}`;
4579
4579
  }
4580
- var VERSION = "0.30.0", INSTALL_CHANNEL = "npm";
4580
+ var VERSION = "0.32.0", INSTALL_CHANNEL = "npm";
4581
4581
 
4582
4582
  // src/debug/logger.ts
4583
4583
  import {
@@ -4711,7 +4711,7 @@ var init_logger = __esm(() => {
4711
4711
  });
4712
4712
 
4713
4713
  // src/client/contract.ts
4714
- var CLI_CONTRACT_HASH = "888669da10bd";
4714
+ var CLI_CONTRACT_HASH = "f5c0727a7884";
4715
4715
 
4716
4716
  // src/client/trpc.ts
4717
4717
  var exports_trpc = {};
@@ -6961,6 +6961,10 @@ var init_installation_server = __esm(() => {
6961
6961
  function dim(msg) {
6962
6962
  return import_picocolors7.default.dim(msg);
6963
6963
  }
6964
+ function browserFallbackHint(url) {
6965
+ return dim(`If your browser doesn't open automatically, visit:
6966
+ ${url}`);
6967
+ }
6964
6968
  function info(msg) {
6965
6969
  return import_picocolors7.default.cyan(msg);
6966
6970
  }
@@ -7624,12 +7628,6 @@ var init_open = __esm(() => {
7624
7628
  });
7625
7629
 
7626
7630
  // src/setup/github-step.ts
7627
- var exports_github_step = {};
7628
- __export(exports_github_step, {
7629
- verifyDataSourcesPersist: () => verifyDataSourcesPersist,
7630
- stepConnectGitHubRepo: () => stepConnectGitHubRepo,
7631
- detectGitRepo: () => detectGitRepo
7632
- });
7633
7631
  import { execSync } from "node:child_process";
7634
7632
  function detectGitRepo(cwd = process.cwd()) {
7635
7633
  let url;
@@ -7722,6 +7720,7 @@ async function openGitHubInstallFlow(onInstalled, opts) {
7722
7720
  middleURL.searchParams.set("callback", callbackURL);
7723
7721
  log.info(`Opening your browser to GitHub.
7724
7722
  ` + "Add repositories or install the Dosu GitHub App, and we'll pick up automatically.");
7723
+ log.message(browserFallbackHint(middleURL.toString()));
7725
7724
  try {
7726
7725
  const open2 = await Promise.resolve().then(() => (init_open(), exports_open));
7727
7726
  await open2.default(middleURL.toString());
@@ -11135,633 +11134,6 @@ var init_audit_handoff = __esm(() => {
11135
11134
  init_styles();
11136
11135
  });
11137
11136
 
11138
- // src/setup/github-doc-import-prompt.ts
11139
- async function promptGitHubDocsImport({
11140
- repositories
11141
- }) {
11142
- const prompt = new GitHubDocsImportPrompt({ repositories });
11143
- return await prompt.prompt();
11144
- }
11145
- function getSelectableFileIds(files) {
11146
- return files.filter((file) => !file.is_synced).map((file) => file.id);
11147
- }
11148
- function visibleOptions2(cursor3, totalItems, maxItems) {
11149
- const terminalRows = process.stdout.rows ? Math.max(process.stdout.rows - 8, 0) : totalItems;
11150
- const visibleCount = Math.min(terminalRows || totalItems, Math.max(maxItems ?? Infinity, 5));
11151
- if (visibleCount >= totalItems) {
11152
- return Array.from({ length: totalItems }, (_2, index) => ({ kind: "option", index }));
11153
- }
11154
- let start = 0;
11155
- if (cursor3 >= start + visibleCount - 3) {
11156
- start = Math.max(Math.min(cursor3 - visibleCount + 3, totalItems - visibleCount), 0);
11157
- } else if (cursor3 < start + 2) {
11158
- start = Math.max(cursor3 - 2, 0);
11159
- }
11160
- const hasTopEllipsis = visibleCount < totalItems && start > 0;
11161
- const hasBottomEllipsis = visibleCount < totalItems && start + visibleCount < totalItems;
11162
- return Array.from({ length: visibleCount }, (_2, index) => {
11163
- const isTopEllipsis = index === 0 && hasTopEllipsis;
11164
- const isBottomEllipsis = index === visibleCount - 1 && hasBottomEllipsis;
11165
- if (isTopEllipsis || isBottomEllipsis) {
11166
- return { kind: "ellipsis" };
11167
- }
11168
- return { kind: "option", index: start + index };
11169
- });
11170
- }
11171
- function wrapIndex(index, length) {
11172
- if (length === 0)
11173
- return 0;
11174
- if (index < 0)
11175
- return length - 1;
11176
- if (index >= length)
11177
- return 0;
11178
- return index;
11179
- }
11180
- function isPrintableKey(key) {
11181
- return key.length === 1 && key >= " " && key !== "";
11182
- }
11183
- var import_picocolors14, CHECKBOX_PARTIAL, MAX_VISIBLE_FILE_ITEMS = 15, GitHubDocsImportPrompt;
11184
- var init_github_doc_import_prompt = __esm(() => {
11185
- init_dist7();
11186
- init_prompt_symbols();
11187
- import_picocolors14 = __toESM(require_picocolors(), 1);
11188
- CHECKBOX_PARTIAL = symbol2("◧", "[-]");
11189
- GitHubDocsImportPrompt = class GitHubDocsImportPrompt extends V {
11190
- repositories;
11191
- mode = "repos";
11192
- repoCursor = 0;
11193
- fileCursor = 0;
11194
- searchQuery = "";
11195
- searchActive = false;
11196
- selectedIds = new Set;
11197
- constructor({ repositories }) {
11198
- super({
11199
- render() {
11200
- return this.renderPrompt();
11201
- }
11202
- }, false);
11203
- this.repositories = repositories;
11204
- this.selectedIds = new Set(repositories.flatMap((repository) => getSelectableFileIds(repository.files)));
11205
- this.syncValue();
11206
- this.onKeypress = this.handleRawKeypress.bind(this);
11207
- }
11208
- handleRawKeypress(key, info2) {
11209
- this.handleKeypress(key, info2);
11210
- this.syncValue();
11211
- if (this.rl) {
11212
- this.render();
11213
- }
11214
- if ((this.state === "submit" || this.state === "cancel") && this.rl) {
11215
- this.close();
11216
- }
11217
- }
11218
- handleKeypress(key, info2) {
11219
- if (info2?.ctrl && info2.name === "c") {
11220
- this.state = "cancel";
11221
- return;
11222
- }
11223
- if (this.mode === "repos") {
11224
- this.handleRepoModeKey(info2);
11225
- return;
11226
- }
11227
- this.handleFileModeKey(key, info2);
11228
- }
11229
- handleRepoModeKey(info2) {
11230
- switch (info2?.name) {
11231
- case "up":
11232
- this.moveRepoCursor(-1);
11233
- return;
11234
- case "down":
11235
- this.moveRepoCursor(1);
11236
- return;
11237
- case "right":
11238
- this.enterRepository();
11239
- return;
11240
- case "space":
11241
- this.toggleCurrentRepository();
11242
- return;
11243
- case "return":
11244
- this.state = "submit";
11245
- return;
11246
- case "left":
11247
- return;
11248
- case "escape":
11249
- this.state = "cancel";
11250
- return;
11251
- default:
11252
- return;
11253
- }
11254
- }
11255
- handleFileModeKey(key, info2) {
11256
- switch (info2?.name) {
11257
- case "up":
11258
- this.moveFileCursor(-1);
11259
- return;
11260
- case "down":
11261
- this.moveFileCursor(1);
11262
- return;
11263
- case "left":
11264
- this.leaveRepository();
11265
- return;
11266
- case "space":
11267
- this.toggleCurrentFile();
11268
- return;
11269
- case "backspace":
11270
- this.searchQuery = this.searchQuery.slice(0, -1);
11271
- this.searchActive = this.searchQuery.length > 0;
11272
- this.resetFileCursor();
11273
- return;
11274
- case "return":
11275
- this.leaveRepository();
11276
- return;
11277
- case "escape":
11278
- if (this.searchQuery || this.searchActive) {
11279
- this.searchQuery = "";
11280
- this.searchActive = false;
11281
- this.resetFileCursor();
11282
- return;
11283
- }
11284
- this.state = "cancel";
11285
- return;
11286
- default:
11287
- break;
11288
- }
11289
- if (!key)
11290
- return;
11291
- if (key === "/") {
11292
- this.searchActive = true;
11293
- return;
11294
- }
11295
- if (key === "a" && !this.searchActive && this.searchQuery.length === 0) {
11296
- this.toggleAllVisibleFiles();
11297
- return;
11298
- }
11299
- if (!isPrintableKey(key))
11300
- return;
11301
- this.searchActive = true;
11302
- this.searchQuery += key;
11303
- this.resetFileCursor();
11304
- }
11305
- get currentRepository() {
11306
- return this.repositories[this.repoCursor];
11307
- }
11308
- get filteredFiles() {
11309
- const files = this.currentRepository?.files ?? [];
11310
- const query = this.searchQuery.trim().toLowerCase();
11311
- if (!query)
11312
- return files;
11313
- return files.filter((file) => file.path.toLowerCase().includes(query));
11314
- }
11315
- syncValue() {
11316
- this.value = Array.from(this.selectedIds);
11317
- }
11318
- moveRepoCursor(delta) {
11319
- if (this.repositories.length === 0)
11320
- return;
11321
- this.repoCursor = wrapIndex(this.repoCursor + delta, this.repositories.length);
11322
- }
11323
- moveFileCursor(delta) {
11324
- if (this.filteredFiles.length === 0)
11325
- return;
11326
- this.fileCursor = wrapIndex(this.fileCursor + delta, this.filteredFiles.length);
11327
- }
11328
- enterRepository() {
11329
- if (!this.currentRepository)
11330
- return;
11331
- this.mode = "files";
11332
- this.searchQuery = "";
11333
- this.searchActive = false;
11334
- this.resetFileCursor();
11335
- }
11336
- leaveRepository() {
11337
- this.mode = "repos";
11338
- this.searchQuery = "";
11339
- this.searchActive = false;
11340
- this.fileCursor = 0;
11341
- }
11342
- resetFileCursor() {
11343
- this.fileCursor = 0;
11344
- }
11345
- toggleCurrentRepository() {
11346
- const repo = this.currentRepository;
11347
- if (!repo)
11348
- return;
11349
- const selectableIds = getSelectableFileIds(repo.files);
11350
- if (selectableIds.length === 0)
11351
- return;
11352
- const allSelected = selectableIds.every((id) => this.selectedIds.has(id));
11353
- if (allSelected) {
11354
- for (const id of selectableIds) {
11355
- this.selectedIds.delete(id);
11356
- }
11357
- return;
11358
- }
11359
- for (const id of selectableIds) {
11360
- this.selectedIds.add(id);
11361
- }
11362
- }
11363
- toggleCurrentFile() {
11364
- const file = this.filteredFiles[this.fileCursor];
11365
- if (!file || file.is_synced)
11366
- return;
11367
- if (this.selectedIds.has(file.id)) {
11368
- this.selectedIds.delete(file.id);
11369
- return;
11370
- }
11371
- this.selectedIds.add(file.id);
11372
- }
11373
- toggleAllVisibleFiles() {
11374
- const selectableIds = getSelectableFileIds(this.filteredFiles);
11375
- if (selectableIds.length === 0)
11376
- return;
11377
- const allSelected = selectableIds.every((id) => this.selectedIds.has(id));
11378
- if (allSelected) {
11379
- for (const id of selectableIds) {
11380
- this.selectedIds.delete(id);
11381
- }
11382
- return;
11383
- }
11384
- for (const id of selectableIds) {
11385
- this.selectedIds.add(id);
11386
- }
11387
- }
11388
- getRepositorySelectionState(repo) {
11389
- const selectableIds = getSelectableFileIds(repo.files);
11390
- if (selectableIds.length === 0)
11391
- return "locked";
11392
- let selectedCount = 0;
11393
- for (const id of selectableIds) {
11394
- if (this.selectedIds.has(id))
11395
- selectedCount += 1;
11396
- }
11397
- if (selectedCount === 0)
11398
- return "none";
11399
- if (selectedCount === selectableIds.length)
11400
- return "all";
11401
- return "partial";
11402
- }
11403
- renderPrompt() {
11404
- const promptSymbol = this.state === "submit" ? import_picocolors14.default.green(SUBMIT_SYMBOL) : this.state === "cancel" ? import_picocolors14.default.red(CANCEL_SYMBOL2) : import_picocolors14.default.cyan(ACTIVE_SYMBOL);
11405
- const title = this.mode === "repos" ? "Select docs to import" : this.currentRepository?.slug ?? "Files";
11406
- const header = `${import_picocolors14.default.gray(BAR)}
11407
- ${promptSymbol} ${title}
11408
- `;
11409
- if (this.state === "submit") {
11410
- return `${header}${import_picocolors14.default.gray(BAR)} ${import_picocolors14.default.dim(this.submitLabel())}`;
11411
- }
11412
- if (this.state === "cancel") {
11413
- return `${header}${import_picocolors14.default.gray(BAR)}`;
11414
- }
11415
- return this.mode === "repos" ? this.renderRepositoryMode(header) : this.renderFileMode(header);
11416
- }
11417
- renderRepositoryMode(header) {
11418
- const help = `${import_picocolors14.default.gray(BAR)} ${import_picocolors14.default.dim("space: import all docs in a repo →: browse repo docs Enter: confirm")}`;
11419
- const body = visibleOptions2(this.repoCursor, this.repositories.length).map((option) => {
11420
- if (option.kind === "ellipsis") {
11421
- return `${import_picocolors14.default.gray(BAR)} ${import_picocolors14.default.dim(ELLIPSIS)}`;
11422
- }
11423
- const repo = this.repositories[option.index];
11424
- const isActive = option.index === this.repoCursor;
11425
- const state = this.getRepositorySelectionState(repo);
11426
- const marker = this.renderRepositoryMarker(state, isActive);
11427
- const label = isActive ? import_picocolors14.default.cyan(repo.slug) : repo.slug;
11428
- const hint = state === "locked" ? ` ${import_picocolors14.default.dim("(All docs already imported)")}` : "";
11429
- return `${import_picocolors14.default.gray(BAR)} ${marker} ${label}${hint}`;
11430
- });
11431
- return `${header}${help}
11432
- ${import_picocolors14.default.gray(BAR)}
11433
- ${body.join(`
11434
- `)}
11435
- ${import_picocolors14.default.cyan(FOOTER)}`;
11436
- }
11437
- renderFileMode(header) {
11438
- const back = `${import_picocolors14.default.gray(BAR)} ${import_picocolors14.default.dim("←: back / Enter")}`;
11439
- const searchValue = this.searchQuery || import_picocolors14.default.dim(this.searchActive ? "" : "type to filter");
11440
- const search = `${import_picocolors14.default.gray(BAR)} Search: ${searchValue}`;
11441
- const help = `${import_picocolors14.default.gray(BAR)} ${import_picocolors14.default.dim("space: toggle doc type: search a: select all visible ←: back / Enter")}`;
11442
- const body = visibleOptions2(this.fileCursor, this.filteredFiles.length, MAX_VISIBLE_FILE_ITEMS).map((option) => {
11443
- if (option.kind === "ellipsis") {
11444
- return `${import_picocolors14.default.gray(BAR)} ${import_picocolors14.default.dim(ELLIPSIS)}`;
11445
- }
11446
- const file = this.filteredFiles[option.index];
11447
- const isActive = option.index === this.fileCursor;
11448
- const isSelected = this.selectedIds.has(file.id);
11449
- const marker = file.is_synced ? isActive ? import_picocolors14.default.cyan(CHECKBOX_OFF) : import_picocolors14.default.dim(CHECKBOX_OFF) : isSelected ? isActive ? import_picocolors14.default.cyan(CHECKBOX_ON) : CHECKBOX_ON : isActive ? import_picocolors14.default.cyan(CHECKBOX_OFF) : CHECKBOX_OFF;
11450
- const label = file.is_synced ? isActive ? import_picocolors14.default.cyan(file.path) : import_picocolors14.default.dim(file.path) : isActive ? import_picocolors14.default.cyan(file.path) : file.path;
11451
- const hint = file.is_synced ? ` ${import_picocolors14.default.dim("(Already imported)")}` : "";
11452
- return `${import_picocolors14.default.gray(BAR)} ${marker} ${label}${hint}`;
11453
- });
11454
- const content = body.length > 0 ? body.join(`
11455
- `) : `${import_picocolors14.default.gray(BAR)} ${import_picocolors14.default.dim("No docs match your search.")}`;
11456
- return `${header}${back}
11457
- ${import_picocolors14.default.gray(BAR)}
11458
- ${search}
11459
- ${import_picocolors14.default.gray(BAR)}
11460
- ${content}
11461
- ${import_picocolors14.default.gray(BAR)}
11462
- ${help}
11463
- ${import_picocolors14.default.cyan(FOOTER)}`;
11464
- }
11465
- renderRepositoryMarker(state, isActive) {
11466
- if (state === "all") {
11467
- return isActive ? import_picocolors14.default.cyan(CHECKBOX_ON) : CHECKBOX_ON;
11468
- }
11469
- if (state === "partial") {
11470
- return isActive ? import_picocolors14.default.cyan(CHECKBOX_PARTIAL) : CHECKBOX_PARTIAL;
11471
- }
11472
- if (state === "locked") {
11473
- return isActive ? import_picocolors14.default.cyan(CHECKBOX_OFF) : import_picocolors14.default.dim(CHECKBOX_OFF);
11474
- }
11475
- return isActive ? import_picocolors14.default.cyan(CHECKBOX_OFF) : CHECKBOX_OFF;
11476
- }
11477
- submitLabel() {
11478
- const count = this.selectedIds.size;
11479
- if (count === 0) {
11480
- return "Skip for now";
11481
- }
11482
- return `${count} doc${count === 1 ? "" : "s"} selected`;
11483
- }
11484
- };
11485
- });
11486
-
11487
- // src/setup/github-doc-import-step.ts
11488
- var exports_github_doc_import_step = {};
11489
- __export(exports_github_doc_import_step, {
11490
- stepImportGitHubDocs: () => stepImportGitHubDocs
11491
- });
11492
- async function stepImportGitHubDocs(cfg, opts = {}) {
11493
- logger.info("setup", "Step: import GitHub docs");
11494
- if (!cfg.org_id || !cfg.space_id) {
11495
- log.warn("Cannot import GitHub docs: your Dosu workspace is missing org/space context. " + "Re-run `dosu setup` from a fresh state.");
11496
- return { advance: false };
11497
- }
11498
- const trpc = createTypedClient(cfg);
11499
- const files = opts.waitForFreshDocs ? await waitForImportableGithubFiles(trpc, cfg.org_id, cfg.space_id, opts.expectedDataSourceIds) : await fetchImportableGithubFiles(trpc, cfg.space_id);
11500
- if (files === null) {
11501
- return { advance: false };
11502
- }
11503
- if (files.length === 0) {
11504
- log.info("No markdown docs available to import right now. You can import them later.");
11505
- return { advance: true, imported: false, imported_count: 0 };
11506
- }
11507
- const repositories = buildRepositories(files);
11508
- const selected = await promptGitHubDocsImport({ repositories });
11509
- if (isCancel(selected)) {
11510
- logger.info("setup", "GitHub doc import selection cancelled");
11511
- return { advance: false };
11512
- }
11513
- const fileIDs = selected;
11514
- if (fileIDs.length === 0) {
11515
- log.info("Skipped importing docs for now. You can import them later.");
11516
- return { advance: true, imported: false, imported_count: 0 };
11517
- }
11518
- const knowledgeStoreID = await getKnowledgeStoreID(trpc, cfg.space_id);
11519
- if (!knowledgeStoreID) {
11520
- return { advance: false };
11521
- }
11522
- const spinner2 = spinner();
11523
- spinner2.start(`Queueing import for ${fileIDs.length} doc${fileIDs.length === 1 ? "" : "s"}...`);
11524
- try {
11525
- const result = await trpc.docImports.importGithubFiles.mutate({
11526
- knowledge_store_id: knowledgeStoreID,
11527
- space_id: cfg.space_id,
11528
- file_ids: fileIDs
11529
- });
11530
- const taskID = result?.task_id;
11531
- if (!taskID) {
11532
- spinner2.stop("Import task started");
11533
- log.success("Import task started.");
11534
- log.info("Your docs should finish importing in a few minutes.");
11535
- return { advance: true, imported: false, imported_count: 0, queued: true };
11536
- }
11537
- spinner2.stop("Import task started");
11538
- logger.info("setup", `Watching import task ${taskID}`);
11539
- log.info("This can take a few minutes. We'll keep watching until it finishes.");
11540
- const progressSpinner = spinner();
11541
- progressSpinner.start(`Preparing document import... 0/${fileIDs.length} complete`);
11542
- const finalStatus = await waitForImportTaskCompletion(trpc, taskID, progressSpinner, fileIDs.length);
11543
- if (!finalStatus) {
11544
- progressSpinner.stop("Stopped watching import progress");
11545
- log.info(`The import is still running in the background.
11546
- Check status later with: dosu docs import-status ${taskID}`);
11547
- return {
11548
- advance: true,
11549
- imported: false,
11550
- imported_count: 0,
11551
- queued: true,
11552
- task_id: taskID
11553
- };
11554
- }
11555
- handleImportCompletion(finalStatus, progressSpinner);
11556
- const importedCount = finalStatus.detail?.completed ?? 0;
11557
- return {
11558
- advance: true,
11559
- imported: importedCount > 0,
11560
- imported_count: importedCount,
11561
- failed_count: finalStatus.detail?.failed ?? 0,
11562
- task_id: taskID
11563
- };
11564
- } catch (err) {
11565
- spinner2.stop("Failed");
11566
- const msg = err instanceof Error ? err.message : String(err);
11567
- logger.error("setup", `Failed to import GitHub docs: ${msg}`);
11568
- log.error("Could not start the GitHub doc import.");
11569
- return { advance: false };
11570
- }
11571
- }
11572
- async function waitForImportTaskCompletion(trpc, taskID, spinner2, expectedTotal) {
11573
- let consecutiveErrors = 0;
11574
- while (true) {
11575
- try {
11576
- const status = await trpc.docImports.getImportStatus.query(taskID);
11577
- if (!status) {
11578
- consecutiveErrors += 1;
11579
- if (consecutiveErrors >= IMPORT_STATUS_MAX_ERRORS) {
11580
- return null;
11581
- }
11582
- } else {
11583
- consecutiveErrors = 0;
11584
- spinner2.message(buildImportProgressMessage(status, expectedTotal));
11585
- if (status.state !== "PROGRESS") {
11586
- return status;
11587
- }
11588
- }
11589
- } catch (err) {
11590
- consecutiveErrors += 1;
11591
- const msg = err instanceof Error ? err.message : String(err);
11592
- logger.warn("setup", `getImportStatus failed for ${taskID}: ${msg}`);
11593
- if (consecutiveErrors >= IMPORT_STATUS_MAX_ERRORS) {
11594
- return null;
11595
- }
11596
- }
11597
- await sleep5(IMPORT_STATUS_POLL_INTERVAL_MS);
11598
- }
11599
- }
11600
- function buildImportProgressMessage(status, expectedTotal) {
11601
- const detail = status.detail;
11602
- if (!detail) {
11603
- return `Importing documents... 0/${expectedTotal} complete`;
11604
- }
11605
- const processed = detail.completed + detail.failed;
11606
- const total = detail.total > 0 ? detail.total : expectedTotal;
11607
- if (status.state === "SUCCESS") {
11608
- return `Import complete (${processed}/${total})`;
11609
- }
11610
- if (status.state === "FAILURE") {
11611
- return `Import finished with issues (${processed}/${total}, ${detail.failed} failed)`;
11612
- }
11613
- const prefix = detail.message === "STARTING" ? "Preparing document import" : "Importing documents";
11614
- const failureSuffix = detail.failed > 0 ? `, ${detail.failed} failed` : "";
11615
- return `${prefix}... ${processed}/${total} complete${failureSuffix}`;
11616
- }
11617
- function handleImportCompletion(status, spinner2) {
11618
- const detail = status.detail;
11619
- const processed = detail ? detail.completed + detail.failed : 0;
11620
- const total = detail?.total ?? processed;
11621
- const failed = detail?.failed ?? 0;
11622
- if (status.state === "SUCCESS") {
11623
- spinner2.stop("Import complete");
11624
- log.success(`Imported ${total} doc${total === 1 ? "" : "s"}.
11625
- Your GitHub docs are ready, and onboarding is complete.`);
11626
- return;
11627
- }
11628
- spinner2.stop("Import completed with issues");
11629
- log.warn(`Imported ${processed - failed} of ${total} doc${total === 1 ? "" : "s"}; ${failed} failed.
11630
- You can review the failed docs later, but onboarding is complete.`);
11631
- }
11632
- async function waitForImportableGithubFiles(trpc, orgID, spaceID, expectedDataSourceIds) {
11633
- while (true) {
11634
- const spinner2 = spinner();
11635
- spinner2.start("Scanning repositories for markdown documents...");
11636
- log.info("This usually takes a few seconds.");
11637
- const startedAt = Date.now();
11638
- let latestFiles = [];
11639
- const waitsForExpectedDataSources = expectedDataSourceIds !== undefined && expectedDataSourceIds.length > 0;
11640
- while (Date.now() - startedAt < DOC_SCAN_POLL_TIMEOUT_MS) {
11641
- const dataSources = await fetchGitHubDataSources(trpc, orgID);
11642
- if (waitsForExpectedDataSources) {
11643
- if (isScanComplete(dataSources, expectedDataSourceIds)) {
11644
- latestFiles = await fetchImportableGithubFiles(trpc, spaceID);
11645
- spinner2.stop(latestFiles.length > 0 ? "Docs ready" : "No markdown docs found");
11646
- return latestFiles;
11647
- }
11648
- await sleep5(DOC_SCAN_POLL_INTERVAL_MS);
11649
- continue;
11650
- }
11651
- latestFiles = await fetchImportableGithubFiles(trpc, spaceID);
11652
- if (latestFiles.length > 0) {
11653
- spinner2.stop("Docs ready");
11654
- return latestFiles;
11655
- }
11656
- if (isScanComplete(dataSources, expectedDataSourceIds)) {
11657
- spinner2.stop("No markdown docs found");
11658
- return [];
11659
- }
11660
- await sleep5(DOC_SCAN_POLL_INTERVAL_MS);
11661
- }
11662
- spinner2.stop("Timed out");
11663
- const choice = await select({
11664
- message: "Still waiting for GitHub docs to become available",
11665
- options: [
11666
- { value: "retry", label: "Retry" },
11667
- { value: "skip", label: "Skip for now" }
11668
- ]
11669
- });
11670
- if (isCancel(choice)) {
11671
- return null;
11672
- }
11673
- if (choice === "skip") {
11674
- log.info("Skipped importing docs for now. You can import them later.");
11675
- return [];
11676
- }
11677
- }
11678
- }
11679
- function isScanComplete(dataSources, expectedDataSourceIds) {
11680
- if (expectedDataSourceIds && expectedDataSourceIds.length > 0) {
11681
- const byId = new Map;
11682
- for (const ds of dataSources) {
11683
- if (ds.data_source_id)
11684
- byId.set(ds.data_source_id, ds);
11685
- }
11686
- for (const id of expectedDataSourceIds) {
11687
- const ds = byId.get(id);
11688
- if (!ds)
11689
- continue;
11690
- if (ds.is_indexed !== true)
11691
- return false;
11692
- }
11693
- return true;
11694
- }
11695
- return dataSources.length > 0 && dataSources.every((ds) => ds.is_indexed === true);
11696
- }
11697
- async function fetchGitHubDataSources(trpc, orgID) {
11698
- try {
11699
- const dataSources = await trpc.dataSource.list.query({
11700
- org_id: orgID,
11701
- excluded_provider_slugs: []
11702
- });
11703
- return dataSources.filter((dataSource) => dataSource.provider_slug === "github");
11704
- } catch (err) {
11705
- const msg = err instanceof Error ? err.message : String(err);
11706
- logger.warn("setup", `dataSource.list failed while waiting for docs: ${msg}`);
11707
- return [];
11708
- }
11709
- }
11710
- async function fetchImportableGithubFiles(trpc, spaceID) {
11711
- try {
11712
- return await trpc.docImports.listImportableGithubFiles.query(spaceID);
11713
- } catch (err) {
11714
- const msg = err instanceof Error ? err.message : String(err);
11715
- logger.warn("setup", `listImportableGithubFiles failed: ${msg}`);
11716
- return [];
11717
- }
11718
- }
11719
- function buildRepositories(files) {
11720
- const repositories = new Map;
11721
- for (const file of files) {
11722
- const slug = file.repository_slug ?? "unknown";
11723
- if (!repositories.has(slug)) {
11724
- repositories.set(slug, { slug, files: [] });
11725
- }
11726
- repositories.get(slug)?.files.push({
11727
- id: file.id,
11728
- path: file.file_path,
11729
- is_synced: file.is_synced
11730
- });
11731
- }
11732
- return Array.from(repositories.values()).map((repository) => ({
11733
- ...repository,
11734
- files: [...repository.files].sort((a3, b2) => a3.path.localeCompare(b2.path))
11735
- })).sort((a3, b2) => a3.slug.localeCompare(b2.slug));
11736
- }
11737
- async function getKnowledgeStoreID(trpc, spaceID) {
11738
- try {
11739
- const store = await trpc.knowledgeStore.getBySpaceId.query({
11740
- space_id: spaceID
11741
- });
11742
- if (!store?.id) {
11743
- log.error("No knowledge store found for this deployment.");
11744
- return null;
11745
- }
11746
- return store.id;
11747
- } catch (err) {
11748
- const msg = err instanceof Error ? err.message : String(err);
11749
- logger.error("setup", `knowledgeStore.getBySpaceId failed: ${msg}`);
11750
- log.error("Could not load the knowledge store for this deployment.");
11751
- return null;
11752
- }
11753
- }
11754
- function sleep5(ms) {
11755
- return new Promise((resolve) => setTimeout(resolve, ms));
11756
- }
11757
- var DOC_SCAN_POLL_INTERVAL_MS = 2000, DOC_SCAN_POLL_TIMEOUT_MS = 60000, IMPORT_STATUS_POLL_INTERVAL_MS = 2000, IMPORT_STATUS_MAX_ERRORS = 3;
11758
- var init_github_doc_import_step = __esm(() => {
11759
- init_dist8();
11760
- init_trpc();
11761
- init_logger();
11762
- init_github_doc_import_prompt();
11763
- });
11764
-
11765
11137
  // src/auth/errors.ts
11766
11138
  var exports_errors = {};
11767
11139
  __export(exports_errors, {
@@ -11841,14 +11213,53 @@ code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; background:
11841
11213
  </body>
11842
11214
  </html>`;
11843
11215
  }
11844
- function buildSuccessHtml(email) {
11216
+ function buildNextPollScript(settleMsg) {
11217
+ return `<script>
11218
+ (function () {
11219
+ var tries = 0;
11220
+ var misses = 0;
11221
+ var setCopy = function (heading, msg) {
11222
+ var h = document.getElementById('heading');
11223
+ var m = document.getElementById('close-msg');
11224
+ if (h && heading) h.textContent = heading;
11225
+ if (m && msg) m.textContent = msg;
11226
+ };
11227
+ var settle = function () { setCopy(null, ${JSON.stringify(settleMsg)}); };
11228
+ var timer = setInterval(function () {
11229
+ tries += 1;
11230
+ if (tries > 720) { clearInterval(timer); settle(); return; }
11231
+ fetch('/next').then(function (res) {
11232
+ misses = 0;
11233
+ if (res.status === 200) {
11234
+ clearInterval(timer);
11235
+ res.json().then(function (body) {
11236
+ if (body && body.url) {
11237
+ setCopy("You're ready to connect your data sources", 'Redirecting...');
11238
+ window.location.replace(body.url);
11239
+ }
11240
+ });
11241
+ } else if (res.status === 410) {
11242
+ clearInterval(timer);
11243
+ settle();
11244
+ }
11245
+ }).catch(function () {
11246
+ misses += 1;
11247
+ if (misses >= 8) { clearInterval(timer); settle(); }
11248
+ });
11249
+ }, 250);
11250
+ })();
11251
+ </script>`;
11252
+ }
11253
+ function buildSuccessHtml(email, variant = "auth", withNextPoll = false) {
11254
+ const copy2 = SUCCESS_COPY[variant];
11255
+ const closeMsg = withNextPoll ? "Hang tight — this tab will continue automatically." : copy2.close;
11845
11256
  const emailLine = email ? `<p class="email">Signed in as <strong>${email.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")}</strong></p>` : "";
11846
11257
  return `<!DOCTYPE html>
11847
11258
  <html lang="en">
11848
11259
  <head>
11849
11260
  <meta charset="UTF-8">
11850
11261
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
11851
- <title>Dosu CLI - Authentication Successful</title>
11262
+ <title>${copy2.title}</title>
11852
11263
  <style>
11853
11264
  * { margin: 0; padding: 0; box-sizing: border-box; }
11854
11265
  body {
@@ -11950,31 +11361,47 @@ h1 {
11950
11361
  <path d="M0.348633 85.4946C0.348633 85.4946 29.4856 85.8309 34.809 85.698C44.8337 85.4477 51.2872 84.402 57.5269 78.9724C62.8129 74.3727 75.1342 59.6836 75.1342 59.6836" stroke="black" stroke-width="6.16482"/>
11951
11362
  </svg>
11952
11363
  </div>
11953
- <h1>Authentication Successful</h1>
11364
+ <h1 id="heading">${copy2.heading}</h1>
11954
11365
  ${emailLine}
11955
- <p class="close-msg">You can close this tab and return to your terminal.</p>
11366
+ <p class="close-msg" id="close-msg">${closeMsg}</p>
11956
11367
  </div>
11957
11368
  <div class="tip">
11958
11369
  <div class="tip-rule" aria-hidden="true"><span class="tip-dot"></span></div>
11959
11370
  <span class="tip-label">Did you know?</span>
11960
11371
  You can use Dosu to make your coding agents faster and cheaper. Just ask your agent to use Dosu to update your AGENTS.md.
11961
11372
  </div>
11373
+ ${withNextPoll ? buildNextPollScript(copy2.close) : ""}
11962
11374
  </body>
11963
11375
  </html>`;
11964
11376
  }
11965
- async function startCallbackServer() {
11377
+ async function startCallbackServer(opts = {}) {
11966
11378
  let resolveToken;
11967
11379
  let rejectToken;
11968
11380
  const tokenPromise = new Promise((resolve, reject) => {
11969
11381
  resolveToken = resolve;
11970
11382
  rejectToken = reject;
11971
11383
  });
11384
+ let nextTarget;
11972
11385
  const http = __require("node:http");
11973
11386
  const httpServer = http.createServer((req, res) => {
11974
11387
  const url = new URL(req.url ?? "/", `http://localhost`);
11975
11388
  const cookieLen = (req.headers.cookie ?? "").length;
11976
11389
  const ua = req.headers["user-agent"] ?? "none";
11977
11390
  logger.debug("auth.server", `Request: ${req.method} ${url.pathname} cookie-len=${cookieLen} ua=${ua} has-token=${url.searchParams.has("access_token")}`);
11391
+ if (opts.nextHold && url.pathname === "/next") {
11392
+ if (nextTarget === undefined) {
11393
+ res.writeHead(204);
11394
+ res.end();
11395
+ } else if (nextTarget === null) {
11396
+ res.writeHead(410);
11397
+ res.end();
11398
+ } else {
11399
+ logger.info("auth.server", "Handing tab onward via /next");
11400
+ res.writeHead(200, { "Content-Type": "application/json" });
11401
+ res.end(JSON.stringify({ url: nextTarget }));
11402
+ }
11403
+ return;
11404
+ }
11978
11405
  if (url.pathname !== "/callback") {
11979
11406
  logger.debug("auth.server", `404: ${url.pathname}`);
11980
11407
  res.writeHead(404, { "Content-Type": "text/plain" });
@@ -12022,17 +11449,24 @@ async function startCallbackServer() {
12022
11449
  });
12023
11450
  logger.info("auth.server", "Served success HTML");
12024
11451
  res.writeHead(200, { "Content-Type": "text/html" });
12025
- res.end(buildSuccessHtml(email ?? undefined));
11452
+ res.end(buildSuccessHtml(email ?? undefined, opts.successVariant ?? "auth", Boolean(opts.nextHold)));
12026
11453
  });
12027
11454
  await new Promise((resolve) => {
12028
11455
  httpServer.listen(0, "localhost", () => resolve());
12029
11456
  });
11457
+ httpServer.unref();
12030
11458
  const addr = httpServer.address();
12031
11459
  logger.info("auth.server", `Callback server listening on port ${addr.port}`);
12032
11460
  return {
12033
11461
  server: {
12034
11462
  port: addr.port,
12035
- close: () => httpServer.close()
11463
+ close: () => {
11464
+ httpServer.close();
11465
+ httpServer.closeAllConnections?.();
11466
+ },
11467
+ setNext: (url) => {
11468
+ nextTarget = url;
11469
+ }
12036
11470
  },
12037
11471
  tokenPromise
12038
11472
  };
@@ -12101,10 +11535,22 @@ if (hash) {
12101
11535
  }
12102
11536
  </script>
12103
11537
  </body>
12104
- </html>`;
11538
+ </html>`, SUCCESS_COPY;
12105
11539
  var init_server = __esm(() => {
12106
11540
  init_logger();
12107
11541
  init_errors();
11542
+ SUCCESS_COPY = {
11543
+ auth: {
11544
+ title: "Dosu CLI - Authentication Successful",
11545
+ heading: "Authentication Successful",
11546
+ close: "You can close this tab and return to your terminal."
11547
+ },
11548
+ onboarding: {
11549
+ title: "Dosu CLI - Onboarding Complete",
11550
+ heading: "Onboarding Complete",
11551
+ close: "You're all set — return to your terminal, Dosu is finishing your setup there."
11552
+ }
11553
+ };
12108
11554
  });
12109
11555
 
12110
11556
  // src/auth/flow.ts
@@ -12112,24 +11558,35 @@ var exports_flow = {};
12112
11558
  __export(exports_flow, {
12113
11559
  startOAuthFlow: () => startOAuthFlow
12114
11560
  });
12115
- async function startOAuthFlow(signal, path3 = "/cli/auth", params = {}) {
12116
- const { server, tokenPromise } = await startCallbackServer();
11561
+ async function startOAuthFlow(signal, path3 = "/cli/auth", params = {}, onAuthURL, options = {}) {
11562
+ const { server, tokenPromise } = await startCallbackServer({
11563
+ nextHold: options.holdNext,
11564
+ successVariant: options.successVariant
11565
+ });
12117
11566
  let timeoutId;
11567
+ let handedOver = false;
12118
11568
  try {
12119
11569
  const callbackURL = `http://localhost:${server.port}/callback`;
12120
11570
  logger.debug("auth.flow", `Callback URL: ${callbackURL}`);
12121
11571
  const authURL = buildAuthURL(callbackURL, path3, params);
12122
11572
  logger.info("auth.flow", `Auth URL: ${authURL}`);
12123
- const open2 = await Promise.resolve().then(() => (init_open(), exports_open));
11573
+ options.onAuthURL?.(authURL);
12124
11574
  let browserOpened = false;
12125
- try {
12126
- await open2.default(authURL);
11575
+ if (options.suppressBrowserOpen) {
12127
11576
  browserOpened = true;
12128
- logger.info("auth.flow", "Browser open command executed");
12129
- } catch (openErr) {
12130
- logger.warn("auth.flow", `Could not open browser automatically: ${openErr instanceof Error ? openErr.message : String(openErr)}`);
11577
+ logger.info("auth.flow", "Browser open suppressed — caller steers an existing tab");
11578
+ } else {
11579
+ const open2 = await Promise.resolve().then(() => (init_open(), exports_open));
11580
+ try {
11581
+ await open2.default(authURL);
11582
+ browserOpened = true;
11583
+ logger.info("auth.flow", "Browser open command executed");
11584
+ onAuthURL?.(authURL);
11585
+ } catch (openErr) {
11586
+ logger.warn("auth.flow", `Could not open browser automatically: ${openErr instanceof Error ? openErr.message : String(openErr)}`);
11587
+ }
12131
11588
  }
12132
- if (!browserOpened) {
11589
+ if (!browserOpened && !options.waitWithoutBrowser) {
12133
11590
  logger.debug("auth.flow", "Browser unavailable — returning to caller for fallback");
12134
11591
  return { browserOpened: false };
12135
11592
  }
@@ -12147,11 +11604,17 @@ async function startOAuthFlow(signal, path3 = "/cli/auth", params = {}) {
12147
11604
  }) : new Promise(() => {});
12148
11605
  const token = await Promise.race([tokenPromise, timeout, abort]);
12149
11606
  logger.info("auth.flow", "Token received");
11607
+ if (options.holdNext) {
11608
+ handedOver = true;
11609
+ return { browserOpened: true, token, server };
11610
+ }
12150
11611
  return { browserOpened: true, token };
12151
11612
  } finally {
12152
11613
  clearTimeout(timeoutId);
12153
- server.close();
12154
- logger.debug("auth.flow", "Cleaning up: timeout cleared, server closed");
11614
+ if (!handedOver) {
11615
+ server.close();
11616
+ logger.debug("auth.flow", "Cleaning up: timeout cleared, server closed");
11617
+ }
12155
11618
  }
12156
11619
  }
12157
11620
  function buildAuthURL(callbackURL, path3, extraParams) {
@@ -12170,14 +11633,11 @@ __export(exports_flow2, {
12170
11633
  stepShowSummary: () => stepShowSummary,
12171
11634
  stepDetectTools: () => stepDetectTools,
12172
11635
  stepConfigureTools: () => stepConfigureTools,
12173
- showTryItOutPrompt: () => showTryItOutPrompt,
12174
11636
  runSetup: () => runSetup,
12175
11637
  runInstallSkill: () => runInstallSkill,
12176
11638
  isStdioOnly: () => isStdioOnly
12177
11639
  });
12178
11640
  import { randomUUID } from "node:crypto";
12179
- import { existsSync as existsSync16 } from "node:fs";
12180
- import { join as join26 } from "node:path";
12181
11641
  async function runSetup(opts = {}) {
12182
11642
  const onboardingRunID = randomUUID();
12183
11643
  logger.info("setup", `Setup flow started${opts.deploymentID ? ` deployment=${opts.deploymentID}` : ""}${opts.mode ? ` mode=${opts.mode}` : ""}`);
@@ -12192,10 +11652,15 @@ async function runSetup(opts = {}) {
12192
11652
  cfg.mode = undefined;
12193
11653
  saveConfig(cfg);
12194
11654
  }
12195
- const authedCfg = await stepAuthenticate(cfg, onboardingRunID);
12196
- if (!authedCfg)
11655
+ const authed = await stepAuthenticate(cfg, onboardingRunID);
11656
+ if (!authed)
12197
11657
  return;
12198
- cfg = authedCfg;
11658
+ cfg = authed.cfg;
11659
+ const authTab = authed.authTab;
11660
+ const releaseAuthTab = () => {
11661
+ authTab?.setNext(null);
11662
+ authTab?.close();
11663
+ };
12199
11664
  await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_auth_completed");
12200
11665
  const apiClient = new Client(cfg);
12201
11666
  let cloudSetupContext = null;
@@ -12208,6 +11673,7 @@ async function runSetup(opts = {}) {
12208
11673
  reason: "cloud_setup_context_failed"
12209
11674
  });
12210
11675
  s.stop("Workspace load failed");
11676
+ releaseAuthTab();
12211
11677
  return;
12212
11678
  }
12213
11679
  s.stop("Workspace loaded");
@@ -12215,7 +11681,18 @@ async function runSetup(opts = {}) {
12215
11681
  await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_started", {
12216
11682
  flow_kind: cloudSetupContext?.kind ?? "oss"
12217
11683
  });
12218
- if (cfg.mode !== MODE_OSS && cloudSetupContext?.kind === "onboarding") {
11684
+ const firstRunOnboarding = cfg.mode !== MODE_OSS && cloudSetupContext?.kind === "onboarding" && !opts.deploymentID;
11685
+ if (!firstRunOnboarding) {
11686
+ releaseAuthTab();
11687
+ }
11688
+ if (firstRunOnboarding && cloudSetupContext) {
11689
+ const onboarded = await stepWebOnboarding(cfg, onboardingRunID, authTab);
11690
+ if (!onboarded) {
11691
+ await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_failed", {
11692
+ reason: "web_onboarding_incomplete"
11693
+ });
11694
+ return;
11695
+ }
12219
11696
  const ok = await bindOnboardingDeployment(apiClient, cfg, cloudSetupContext.targetOrg ?? null);
12220
11697
  if (!ok) {
12221
11698
  await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_failed", {
@@ -12241,9 +11718,7 @@ async function runSetup(opts = {}) {
12241
11718
  }
12242
11719
  cfg.api_key = apiKey;
12243
11720
  saveConfig(cfg);
12244
- const choices = await stepOneShotConfirm({
12245
- includeGitHub: cloudSetupContext?.kind === "onboarding"
12246
- });
11721
+ const choices = await stepOneShotConfirm();
12247
11722
  if (!choices) {
12248
11723
  await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_cancelled", {
12249
11724
  reason: "options_cancelled"
@@ -12252,13 +11727,11 @@ async function runSetup(opts = {}) {
12252
11727
  }
12253
11728
  await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_options_selected", {
12254
11729
  configure_mcp: choices.configureMcp,
12255
- install_skill: choices.installSkill,
12256
- connect_github: choices.connectGitHub
11730
+ install_skill: choices.installSkill
12257
11731
  });
12258
11732
  let mcpConfiguredThisRun = false;
12259
11733
  let mcpCompleted = false;
12260
11734
  let skillCompleted = false;
12261
- let docsImported = false;
12262
11735
  if (choices.configureMcp) {
12263
11736
  const configured = await stepConfigureMcpTools(cfg);
12264
11737
  if (configured === null) {
@@ -12283,84 +11756,14 @@ async function runSetup(opts = {}) {
12283
11756
  await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_skill_installed");
12284
11757
  }
12285
11758
  }
12286
- let githubOnboardingDone = !choices.connectGitHub;
12287
- if (choices.connectGitHub && cloudSetupContext?.kind === "onboarding") {
12288
- const { stepConnectGitHubRepo: stepConnectGitHubRepo2 } = await Promise.resolve().then(() => (init_github_step(), exports_github_step));
12289
- const connectResult = await stepConnectGitHubRepo2(cfg);
12290
- if (!connectResult.advance) {
12291
- await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_cancelled", {
12292
- reason: "github_connect_not_advanced",
12293
- has_connected_repo: connectResult.has_connected_repo
12294
- });
12295
- return;
12296
- }
12297
- if (connectResult.has_connected_repo || (connectResult.created_data_source_ids?.length ?? 0) > 0) {
12298
- await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_github_connected", {
12299
- created_data_source_count: connectResult.created_data_source_ids?.length ?? 0,
12300
- created_repository_slugs: connectResult.created_repository_slugs
12301
- });
12302
- }
12303
- if (connectResult.space_id && !cfg.space_id) {
12304
- cfg.space_id = connectResult.space_id;
12305
- saveConfig(cfg);
12306
- }
12307
- const { stepImportGitHubDocs: stepImportGitHubDocs2 } = await Promise.resolve().then(() => (init_github_doc_import_step(), exports_github_doc_import_step));
12308
- const importResult = await stepImportGitHubDocs2(cfg, {
12309
- waitForFreshDocs: Boolean(connectResult.deployment_id),
12310
- expectedDataSourceIds: connectResult.created_data_source_ids
12311
- });
12312
- if (!importResult.advance) {
12313
- await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_failed", {
12314
- reason: "github_docs_import_failed"
12315
- });
12316
- return;
12317
- }
12318
- docsImported = importResult.imported === true && (importResult.imported_count ?? 0) > 0;
12319
- if (docsImported) {
12320
- await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_docs_imported", {
12321
- imported_count: importResult.imported_count ?? 0,
12322
- failed_count: importResult.failed_count ?? 0,
12323
- task_id: importResult.task_id
12324
- });
12325
- await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_activated", {
12326
- imported_count: importResult.imported_count ?? 0,
12327
- failed_count: importResult.failed_count ?? 0
12328
- });
12329
- }
12330
- githubOnboardingDone = true;
12331
- }
12332
- const shouldCompleteRemoteOnboarding = cloudSetupContext?.kind === "onboarding" && githubOnboardingDone;
12333
- if (shouldCompleteRemoteOnboarding && cloudSetupContext) {
12334
- const profileUserID = cloudSetupContext.profileUserID;
12335
- try {
12336
- const { createTypedClient: createTypedClient2 } = await Promise.resolve().then(() => (init_trpc(), exports_trpc));
12337
- const trpc = createTypedClient2(cfg);
12338
- await trpc.user.updateProfile.mutate({
12339
- user_id: profileUserID,
12340
- finished_onboarding: true
12341
- });
12342
- logger.info("setup", "Server onboarding marked complete");
12343
- } catch (err) {
12344
- logger.warn("setup", `completeOnboarding failed: ${err instanceof Error ? err.message : String(err)}`);
12345
- log.warn("Could not mark onboarding complete on the server — you can retry later by running `dosu setup` again.");
12346
- }
12347
- }
12348
11759
  let handoffToAudit = false;
12349
- if (mcpConfiguredThisRun) {
12350
- showTryItOutPrompt({
12351
- mode: cfg.mode,
12352
- docsImported: choices.connectGitHub && githubOnboardingDone,
12353
- hasAgentsMd: existsSync16(join26(process.cwd(), "AGENTS.md"))
12354
- });
12355
- if (cfg.mode !== MODE_OSS) {
12356
- handoffToAudit = await offerAuditHandoff();
12357
- }
11760
+ if (mcpConfiguredThisRun && cfg.mode !== MODE_OSS) {
11761
+ handoffToAudit = await offerAuditHandoff();
12358
11762
  }
12359
- if (mcpCompleted || skillCompleted || docsImported) {
11763
+ if (mcpCompleted || skillCompleted) {
12360
11764
  await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_completed", {
12361
11765
  completed_mcp: mcpCompleted,
12362
- completed_skill: skillCompleted,
12363
- imported_docs: docsImported
11766
+ completed_skill: skillCompleted
12364
11767
  });
12365
11768
  }
12366
11769
  if (cfg.mode === MODE_OSS) {
@@ -12389,17 +11792,11 @@ function applyModeOverride(cfg, opts) {
12389
11792
  }
12390
11793
  saveConfig(cfg);
12391
11794
  }
12392
- async function stepOneShotConfirm(opts) {
11795
+ async function stepOneShotConfirm() {
12393
11796
  const items = [
12394
11797
  { value: "configureMcp", label: "Install Dosu MCP" },
12395
11798
  { value: "installSkill", label: "Install Dosu skill" }
12396
11799
  ];
12397
- if (opts.includeGitHub) {
12398
- items.push({
12399
- value: "connectGitHub",
12400
- label: `Import docs from GitHub ${dim("(Keep them up to date)")}`
12401
- });
12402
- }
12403
11800
  const selected = await multiselect({
12404
11801
  message: "Dosu will set these up — press Enter to accept, space to toggle",
12405
11802
  options: items.map((it) => ({ value: it.value, label: it.label })),
@@ -12413,8 +11810,7 @@ async function stepOneShotConfirm(opts) {
12413
11810
  const chosen = new Set(selected);
12414
11811
  return {
12415
11812
  configureMcp: chosen.has("configureMcp"),
12416
- installSkill: chosen.has("installSkill"),
12417
- connectGitHub: chosen.has("connectGitHub")
11813
+ installSkill: chosen.has("installSkill")
12418
11814
  };
12419
11815
  }
12420
11816
  async function stepConfigureMcpTools(cfg) {
@@ -12461,7 +11857,7 @@ async function stepAuthenticate(existingCfg, onboardingRunID) {
12461
11857
  if (resp.status === 200) {
12462
11858
  logger.info("setup", `Session verified, status=${resp.status}`);
12463
11859
  s.stop("Authenticated");
12464
- return cfg;
11860
+ return { cfg };
12465
11861
  }
12466
11862
  try {
12467
11863
  logger.debug("setup", "Attempting token refresh");
@@ -12469,7 +11865,7 @@ async function stepAuthenticate(existingCfg, onboardingRunID) {
12469
11865
  const resp2 = await apiClient.doRequestRaw("GET", "/v1/mcp/deployments");
12470
11866
  if (resp2.status === 200) {
12471
11867
  s.stop("Authenticated");
12472
- return cfg;
11868
+ return { cfg };
12473
11869
  }
12474
11870
  } catch {}
12475
11871
  s.stop("Session expired");
@@ -12479,15 +11875,6 @@ async function stepAuthenticate(existingCfg, onboardingRunID) {
12479
11875
  s.stop("Session verification failed");
12480
11876
  }
12481
11877
  }
12482
- const shouldLogin = await confirm({ message: "Open browser to log in?" });
12483
- if (isCancel(shouldLogin) || !shouldLogin) {
12484
- if (onboardingRunID) {
12485
- await trackCliOnboardingPreAuthEvent(onboardingRunID, "cli_onboarding_auth_cancelled", {
12486
- reason: isCancel(shouldLogin) ? "prompt_cancelled" : "login_declined"
12487
- });
12488
- }
12489
- return null;
12490
- }
12491
11878
  if (onboardingRunID) {
12492
11879
  await trackCliOnboardingPreAuthEvent(onboardingRunID, "cli_onboarding_auth_started");
12493
11880
  }
@@ -12497,11 +11884,16 @@ async function openBrowserForSetup(cfg, onboardingRunID) {
12497
11884
  try {
12498
11885
  const { startOAuthFlow: startOAuthFlow2 } = await Promise.resolve().then(() => (init_flow(), exports_flow));
12499
11886
  const s = spinner();
12500
- s.start("Waiting for authentication...");
12501
- const result = await startOAuthFlow2(undefined, "/cli/auth", onboardingRunID ? { onboarding_run_id: onboardingRunID } : {});
11887
+ const result = await startOAuthFlow2(undefined, "/cli/auth", onboardingRunID ? { onboarding_run_id: onboardingRunID } : {}, undefined, {
11888
+ waitWithoutBrowser: true,
11889
+ holdNext: true,
11890
+ onAuthURL: (url) => {
11891
+ log.message(browserFallbackHint(url));
11892
+ s.start("Waiting for authentication...");
11893
+ }
11894
+ });
12502
11895
  if (!result.browserOpened) {
12503
11896
  s.stop("Could not open a browser");
12504
- log.error("Run 'dosu login --no-browser' from the terminal to authenticate over SSH.");
12505
11897
  return null;
12506
11898
  }
12507
11899
  const token = result.token;
@@ -12511,7 +11903,7 @@ async function openBrowserForSetup(cfg, onboardingRunID) {
12511
11903
  cfg.refresh_token = token.refresh_token;
12512
11904
  cfg.expires_at = Math.floor(Date.now() / 1000) + token.expires_in;
12513
11905
  saveConfig(cfg);
12514
- return cfg;
11906
+ return { cfg, authTab: result.server };
12515
11907
  } catch (err) {
12516
11908
  const msg = err instanceof Error ? err.stack ?? err.message : String(err);
12517
11909
  logger.error("setup", `Auth failed: ${msg}`);
@@ -12534,6 +11926,43 @@ async function openBrowserForSetup(cfg, onboardingRunID) {
12534
11926
  return null;
12535
11927
  }
12536
11928
  }
11929
+ async function stepWebOnboarding(cfg, onboardingRunID, authTab) {
11930
+ logger.info("setup", "Step: web onboarding handoff");
11931
+ log.info("Almost there — connect your repos in the browser and we'll pick up from here.");
11932
+ const s = spinner();
11933
+ try {
11934
+ const { startOAuthFlow: startOAuthFlow2 } = await Promise.resolve().then(() => (init_flow(), exports_flow));
11935
+ const result = await startOAuthFlow2(undefined, "/onboarding/connections", { source: "cli", onboarding_run_id: onboardingRunID }, undefined, {
11936
+ waitWithoutBrowser: true,
11937
+ suppressBrowserOpen: Boolean(authTab),
11938
+ successVariant: "onboarding",
11939
+ onAuthURL: (url) => {
11940
+ authTab?.setNext(url);
11941
+ log.message(browserFallbackHint(url));
11942
+ s.start("Waiting for onboarding to finish in the browser...");
11943
+ }
11944
+ });
11945
+ if (!result.browserOpened) {
11946
+ s.stop("Could not open a browser");
11947
+ return false;
11948
+ }
11949
+ cfg.access_token = result.token.access_token;
11950
+ cfg.refresh_token = result.token.refresh_token;
11951
+ cfg.expires_at = Math.floor(Date.now() / 1000) + result.token.expires_in;
11952
+ saveConfig(cfg);
11953
+ s.stop("Onboarding finished in the browser");
11954
+ logger.info("setup", "Web onboarding handoff completed");
11955
+ return true;
11956
+ } catch (err) {
11957
+ const msg = err instanceof Error ? err.message : String(err);
11958
+ logger.warn("setup", `Web onboarding handoff did not complete: ${msg}`);
11959
+ s.stop("Onboarding not completed");
11960
+ log.warn("Didn't hear back from the browser. Finish onboarding there, then re-run `dosu setup`.");
11961
+ return false;
11962
+ } finally {
11963
+ authTab?.close();
11964
+ }
11965
+ }
12537
11966
  async function resolveCloudSetupContext(cfg) {
12538
11967
  try {
12539
11968
  const { createTypedClient: createTypedClient2 } = await Promise.resolve().then(() => (init_trpc(), exports_trpc));
@@ -12543,7 +11972,7 @@ async function resolveCloudSetupContext(cfg) {
12543
11972
  log.error("Could not load your profile.");
12544
11973
  return null;
12545
11974
  }
12546
- if (profile.finished_onboarding === true || profile.cli_onboarding_enabled !== true) {
11975
+ if (profile.finished_onboarding === true) {
12547
11976
  return {
12548
11977
  kind: "setup",
12549
11978
  profileUserID: profile.user_id
@@ -12827,23 +12256,6 @@ ${lines}`);
12827
12256
  log.success("All agents already configured. No changes needed.");
12828
12257
  }
12829
12258
  }
12830
- function showTryItOutPrompt(opts = {}) {
12831
- const prompt = (() => {
12832
- if (opts.mode === MODE_OSS) {
12833
- return `What can Dosu help me with? Pick an open source library related to my project and explain how it works.`;
12834
- }
12835
- if (opts.docsImported) {
12836
- return `Use Dosu to summarize the most important docs in my repo.`;
12837
- }
12838
- if (opts.hasAgentsMd) {
12839
- return `Please use Dosu to host my AGENTS.md`;
12840
- }
12841
- return `Ask Dosu to draft an AGENTS.md for this project.`;
12842
- })();
12843
- log.message(`Try it out! Paste this into your agent:
12844
-
12845
- ${info(prompt)}`);
12846
- }
12847
12259
  var init_flow2 = __esm(() => {
12848
12260
  init_dist8();
12849
12261
  init_client();
@@ -12857,8 +12269,8 @@ var init_flow2 = __esm(() => {
12857
12269
  });
12858
12270
 
12859
12271
  // src/commands/insights.ts
12860
- import { existsSync as existsSync17, mkdirSync as mkdirSync8, readdirSync, unlinkSync, writeFileSync as writeFileSync7 } from "node:fs";
12861
- import { dirname as dirname5, join as join27 } from "node:path";
12272
+ import { existsSync as existsSync16, mkdirSync as mkdirSync8, readdirSync, unlinkSync, writeFileSync as writeFileSync7 } from "node:fs";
12273
+ import { dirname as dirname5, join as join26 } from "node:path";
12862
12274
  function shuffled(arr) {
12863
12275
  const copy2 = [...arr];
12864
12276
  for (let i2 = copy2.length - 1;i2 > 0; i2--) {
@@ -12873,7 +12285,7 @@ function createDotsSpinner() {
12873
12285
  let current = "";
12874
12286
  const isTTY = Boolean(process.stdout.isTTY) && process.env.CI !== "true";
12875
12287
  const draw = () => {
12876
- process.stdout.write(`\r\x1B[2K${import_picocolors15.default.cyan(SPINNER_FRAMES[frameIdx])} ${current}`);
12288
+ process.stdout.write(`\r\x1B[2K${import_picocolors14.default.cyan(SPINNER_FRAMES[frameIdx])} ${current}`);
12877
12289
  frameIdx = (frameIdx + 1) % SPINNER_FRAMES.length;
12878
12290
  };
12879
12291
  return {
@@ -12895,7 +12307,7 @@ function createDotsSpinner() {
12895
12307
  clearInterval(timer);
12896
12308
  timer = undefined;
12897
12309
  }
12898
- const symbol3 = code === 0 ? import_picocolors15.default.green("✓") : import_picocolors15.default.red("✗");
12310
+ const symbol3 = code === 0 ? import_picocolors14.default.green("✓") : import_picocolors14.default.red("✗");
12899
12311
  if (isTTY) {
12900
12312
  process.stdout.write(`\r\x1B[2K${symbol3} ${msg}
12901
12313
  `);
@@ -12962,17 +12374,17 @@ function makeAskFn(cfg) {
12962
12374
  };
12963
12375
  }
12964
12376
  function insightsDir() {
12965
- return join27(getConfigDir(), "insights");
12377
+ return join26(getConfigDir(), "insights");
12966
12378
  }
12967
12379
  function reportPath(timestamp) {
12968
12380
  const dir = insightsDir();
12969
12381
  if (!timestamp)
12970
- return join27(dir, "latest.html");
12382
+ return join26(dir, "latest.html");
12971
12383
  const iso = timestamp.toISOString().slice(0, 19).replace(/:/g, "-");
12972
- return join27(dir, `report-${iso}Z.html`);
12384
+ return join26(dir, `report-${iso}Z.html`);
12973
12385
  }
12974
12386
  function pruneOldReports(dir, keepN) {
12975
- if (!existsSync17(dir))
12387
+ if (!existsSync16(dir))
12976
12388
  return;
12977
12389
  let entries;
12978
12390
  try {
@@ -12984,7 +12396,7 @@ function pruneOldReports(dir, keepN) {
12984
12396
  const reports = entries.filter((f2) => REPORT_FILE_PATTERN.test(f2)).sort().reverse();
12985
12397
  for (const f2 of reports.slice(keepN)) {
12986
12398
  try {
12987
- unlinkSync(join27(dir, f2));
12399
+ unlinkSync(join26(dir, f2));
12988
12400
  } catch (err) {
12989
12401
  logger.debug("insights", `failed to prune ${f2}: ${err instanceof Error ? err.message : err}`);
12990
12402
  }
@@ -13036,18 +12448,18 @@ async function runInsights(cfg, runner) {
13036
12448
  runner.writeFile(latestPath, html);
13037
12449
  runner.prune(insightsDir(), KEEP_REPORTS);
13038
12450
  console.log("");
13039
- console.log(import_picocolors15.default.bold(`\uD83D\uDCCA Dosu Insights · ${report.spaceName}`));
12451
+ console.log(import_picocolors14.default.bold(`\uD83D\uDCCA Dosu Insights · ${report.spaceName}`));
13040
12452
  if (report.cheers[0]) {
13041
- console.log(import_picocolors15.default.green(` ${report.cheers[0]}`));
12453
+ console.log(import_picocolors14.default.green(` ${report.cheers[0]}`));
13042
12454
  }
13043
12455
  console.log("");
13044
- console.log(` Snapshot: ${import_picocolors15.default.cyan(`file://${snapshotPath}`)}`);
13045
- console.log(` Latest: ${import_picocolors15.default.cyan(`file://${latestPath}`)}`);
13046
- console.log(import_picocolors15.default.dim(" Opening in your browser..."));
12456
+ console.log(` Snapshot: ${import_picocolors14.default.cyan(`file://${snapshotPath}`)}`);
12457
+ console.log(` Latest: ${import_picocolors14.default.cyan(`file://${latestPath}`)}`);
12458
+ console.log(import_picocolors14.default.dim(" Opening in your browser..."));
13047
12459
  try {
13048
12460
  await runner.openInBrowser(snapshotPath);
13049
12461
  } catch {
13050
- console.log(import_picocolors15.default.dim(" (couldn't auto-open. Copy the link above.)"));
12462
+ console.log(import_picocolors14.default.dim(" (couldn't auto-open. Copy the link above.)"));
13051
12463
  }
13052
12464
  return snapshotPath;
13053
12465
  }
@@ -13057,7 +12469,7 @@ function defaultRunner(cfg) {
13057
12469
  render: renderHTML,
13058
12470
  writeFile: (path3, content) => {
13059
12471
  const dir = dirname5(path3);
13060
- if (!existsSync17(dir))
12472
+ if (!existsSync16(dir))
13061
12473
  mkdirSync8(dir, { recursive: true, mode: 448 });
13062
12474
  writeFileSync7(path3, content, { mode: 384 });
13063
12475
  },
@@ -13074,7 +12486,7 @@ async function executeInsights(cfg) {
13074
12486
  try {
13075
12487
  await runInsights(cfg, defaultRunner(cfg));
13076
12488
  } catch (err) {
13077
- console.error(import_picocolors15.default.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
12489
+ console.error(import_picocolors14.default.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
13078
12490
  }
13079
12491
  }
13080
12492
  function insightsCommand() {
@@ -13085,12 +12497,12 @@ function insightsCommand() {
13085
12497
  try {
13086
12498
  await runInsights(cfg, defaultRunner(cfg));
13087
12499
  } catch (err) {
13088
- console.error(import_picocolors15.default.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
12500
+ console.error(import_picocolors14.default.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
13089
12501
  process.exit(1);
13090
12502
  }
13091
12503
  });
13092
12504
  }
13093
- var import_picocolors15, ASK_TIMEOUT_MS = 90000, KEEP_REPORTS = 20, REPORT_FILE_PATTERN, HINT_INTERVAL_MS = 6000, NARRATIVE_HINTS, SPINNER_FRAMES, SPINNER_INTERVAL_MS = 80;
12505
+ var import_picocolors14, ASK_TIMEOUT_MS = 90000, KEEP_REPORTS = 20, REPORT_FILE_PATTERN, HINT_INTERVAL_MS = 6000, NARRATIVE_HINTS, SPINNER_FRAMES, SPINNER_INTERVAL_MS = 80;
13094
12506
  var init_insights3 = __esm(() => {
13095
12507
  init_dist8();
13096
12508
  init_commander();
@@ -13099,7 +12511,7 @@ var init_insights3 = __esm(() => {
13099
12511
  init_logger();
13100
12512
  init_insights2();
13101
12513
  init_flow2();
13102
- import_picocolors15 = __toESM(require_picocolors(), 1);
12514
+ import_picocolors14 = __toESM(require_picocolors(), 1);
13103
12515
  REPORT_FILE_PATTERN = /^report-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}Z\.html$/;
13104
12516
  NARRATIVE_HINTS = [
13105
12517
  "Reading your reactions and confidence levels",
@@ -13128,7 +12540,7 @@ __export(exports_tui, {
13128
12540
  handleLogout: () => handleLogout
13129
12541
  });
13130
12542
  async function runTUI() {
13131
- console.log(import_picocolors26.default.magenta(LOGO));
12543
+ console.log(import_picocolors25.default.magenta(LOGO));
13132
12544
  const cfg = loadConfig();
13133
12545
  while (true) {
13134
12546
  const insightsReady = Boolean(cfg.space_id && cfg.deployment_id && cfg.api_key);
@@ -13203,8 +12615,10 @@ async function handleAuthenticate(cfg) {
13203
12615
  try {
13204
12616
  const { startOAuthFlow: startOAuthFlow2 } = await Promise.resolve().then(() => (init_flow(), exports_flow));
13205
12617
  const s = spinner();
13206
- s.start("Waiting for authentication...");
13207
- const result = await startOAuthFlow2(undefined, "/cli/auth");
12618
+ const result = await startOAuthFlow2(undefined, "/cli/auth", {}, (url) => {
12619
+ log.message(browserFallbackHint(url));
12620
+ s.start("Waiting for authentication...");
12621
+ });
13208
12622
  if (!result.browserOpened) {
13209
12623
  s.stop("Could not open a browser");
13210
12624
  log.error("Run 'dosu login --no-browser' from the terminal to authenticate over SSH.");
@@ -13240,7 +12654,7 @@ function handleLogout(cfg) {
13240
12654
  saveConfig(cfg);
13241
12655
  log.success("Credentials cleared.");
13242
12656
  }
13243
- var import_picocolors26, LOGO = `
12657
+ var import_picocolors25, LOGO = `
13244
12658
  /$$$$$$$
13245
12659
  | $$__ $$
13246
12660
  | $$ \\ $$ /$$$$$$ /$$$$$$$ /$$ /$$
@@ -13256,7 +12670,8 @@ var init_tui = __esm(() => {
13256
12670
  init_insights3();
13257
12671
  init_config();
13258
12672
  init_flow2();
13259
- import_picocolors26 = __toESM(require_picocolors(), 1);
12673
+ init_styles();
12674
+ import_picocolors25 = __toESM(require_picocolors(), 1);
13260
12675
  });
13261
12676
 
13262
12677
  // src/auth/ticket.ts
@@ -13460,7 +12875,7 @@ Could not open a browser automatically.`);
13460
12875
  while (Date.now() < deadline) {
13461
12876
  if (signal?.aborted)
13462
12877
  throw new Error("authentication cancelled");
13463
- await sleep6(POLL_INTERVAL_MS);
12878
+ await sleep5(POLL_INTERVAL_MS);
13464
12879
  if (signal?.aborted)
13465
12880
  throw new Error("authentication cancelled");
13466
12881
  const result = await exchangeTicket(minted.ticket);
@@ -13477,7 +12892,7 @@ Could not open a browser automatically.`);
13477
12892
  }
13478
12893
  throw new Error("Authentication timed out. Run 'dosu login' to try again.");
13479
12894
  }
13480
- function sleep6(ms) {
12895
+ function sleep5(ms) {
13481
12896
  return new Promise((resolve) => setTimeout(resolve, ms));
13482
12897
  }
13483
12898
  var POLL_INTERVAL_MS = 5000;
@@ -15505,11 +14920,11 @@ init_insights3();
15505
14920
  // src/commands/integrations.ts
15506
14921
  init_commander();
15507
14922
  init_trpc();
15508
- var import_picocolors16 = __toESM(require_picocolors(), 1);
14923
+ var import_picocolors15 = __toESM(require_picocolors(), 1);
15509
14924
  function requireConfig6() {
15510
14925
  const cfg = requireLoginConfig();
15511
14926
  if (!cfg.org_id) {
15512
- console.error(import_picocolors16.default.red("Missing org config. Run 'dosu setup' to reconfigure."));
14927
+ console.error(import_picocolors15.default.red("Missing org config. Run 'dosu setup' to reconfigure."));
15513
14928
  process.exit(1);
15514
14929
  }
15515
14930
  return cfg;
@@ -15560,7 +14975,7 @@ function integrationsCommand() {
15560
14975
  }
15561
14976
  printTable(["Platform", "Status"], results.map((r2) => [
15562
14977
  r2.platform,
15563
- r2.connected ? import_picocolors16.default.green("connected") : import_picocolors16.default.dim("not connected")
14978
+ r2.connected ? import_picocolors15.default.green("connected") : import_picocolors15.default.dim("not connected")
15564
14979
  ]), { rawData: results });
15565
14980
  });
15566
14981
  cmd.command("status").description("Check connection status of a specific platform").argument("<platform>", `Platform: ${DISPLAY_PLATFORMS.join(", ")}`).option("--json", "Output as JSON").action(async (platform4, opts) => {
@@ -15572,7 +14987,7 @@ function integrationsCommand() {
15572
14987
  printResult({ platform: platform4, connected: false, note: "not queryable via nango" }, opts);
15573
14988
  return;
15574
14989
  }
15575
- console.log(`${platform4}: ${import_picocolors16.default.dim("not connected (not queryable)")}`);
14990
+ console.log(`${platform4}: ${import_picocolors15.default.dim("not connected (not queryable)")}`);
15576
14991
  return;
15577
14992
  }
15578
14993
  try {
@@ -15586,13 +15001,13 @@ function integrationsCommand() {
15586
15001
  printResult({ platform: platform4, connected, connection: conn }, opts);
15587
15002
  return;
15588
15003
  }
15589
- console.log(`${platform4}: ${connected ? import_picocolors16.default.green("connected") : import_picocolors16.default.dim("not connected")}`);
15004
+ console.log(`${platform4}: ${connected ? import_picocolors15.default.green("connected") : import_picocolors15.default.dim("not connected")}`);
15590
15005
  } catch {
15591
15006
  if (opts.json) {
15592
15007
  printResult({ platform: platform4, connected: false }, opts);
15593
15008
  return;
15594
15009
  }
15595
- console.log(`${platform4}: ${import_picocolors16.default.dim("not connected")}`);
15010
+ console.log(`${platform4}: ${import_picocolors15.default.dim("not connected")}`);
15596
15011
  }
15597
15012
  });
15598
15013
  cmd.command("slack-channels").description("List Slack channels").option("--json", "Output as JSON").action(async (opts) => {
@@ -15604,7 +15019,7 @@ function integrationsCommand() {
15604
15019
  return;
15605
15020
  }
15606
15021
  if (!channels || channels.length === 0) {
15607
- console.log(import_picocolors16.default.dim("No Slack channels found."));
15022
+ console.log(import_picocolors15.default.dim("No Slack channels found."));
15608
15023
  return;
15609
15024
  }
15610
15025
  printTable(["ID", "Name"], channels.map((c3) => [
@@ -15620,7 +15035,7 @@ function integrationsCommand() {
15620
15035
  printResult({ success: true, channelId }, opts);
15621
15036
  return;
15622
15037
  }
15623
- console.log(import_picocolors16.default.green(`Joined Slack channel ${channelId}.`));
15038
+ console.log(import_picocolors15.default.green(`Joined Slack channel ${channelId}.`));
15624
15039
  });
15625
15040
  cmd.command("github-collaborators").description("List GitHub repository collaborators").option("--json", "Output as JSON").action(async (opts) => {
15626
15041
  const cfg = requireConfig6();
@@ -15631,7 +15046,7 @@ function integrationsCommand() {
15631
15046
  return;
15632
15047
  }
15633
15048
  if (!collaborators || collaborators.length === 0) {
15634
- console.log(import_picocolors16.default.dim("No collaborators found."));
15049
+ console.log(import_picocolors15.default.dim("No collaborators found."));
15635
15050
  return;
15636
15051
  }
15637
15052
  printTable(["Username", "Name", "Email"], collaborators.map((c3) => [c3.user_name ?? "—", c3.full_name ?? "—", c3.email ?? "—"]), { rawData: collaborators });
@@ -15642,11 +15057,11 @@ function integrationsCommand() {
15642
15057
  // src/commands/knowledge.ts
15643
15058
  init_commander();
15644
15059
  init_trpc();
15645
- var import_picocolors17 = __toESM(require_picocolors(), 1);
15060
+ var import_picocolors16 = __toESM(require_picocolors(), 1);
15646
15061
  function requireConfig7() {
15647
15062
  const cfg = requireLoginConfig();
15648
15063
  if (!cfg.org_id || !cfg.space_id) {
15649
- console.error(import_picocolors17.default.red("Missing org/space config. Run 'dosu setup' to reconfigure."));
15064
+ console.error(import_picocolors16.default.red("Missing org/space config. Run 'dosu setup' to reconfigure."));
15650
15065
  process.exit(1);
15651
15066
  }
15652
15067
  return cfg;
@@ -15662,7 +15077,7 @@ function knowledgeCommand() {
15662
15077
  });
15663
15078
  const dataSourceIds = dataSources.map((ds) => ds.id).filter((id) => id !== null);
15664
15079
  if (dataSourceIds.length === 0) {
15665
- console.log(import_picocolors17.default.dim("No data sources connected. Add data sources in the Dosu dashboard."));
15080
+ console.log(import_picocolors16.default.dim("No data sources connected. Add data sources in the Dosu dashboard."));
15666
15081
  return;
15667
15082
  }
15668
15083
  const data = await client.search.getMentions.query({
@@ -15676,7 +15091,7 @@ function knowledgeCommand() {
15676
15091
  return;
15677
15092
  }
15678
15093
  if (!results || results.length === 0) {
15679
- console.log(import_picocolors17.default.dim("No results found."));
15094
+ console.log(import_picocolors16.default.dim("No results found."));
15680
15095
  return;
15681
15096
  }
15682
15097
  const limit = Number.parseInt(opts.limit ?? "10", 10);
@@ -15686,7 +15101,7 @@ function knowledgeCommand() {
15686
15101
  r2.entity_type ?? "—"
15687
15102
  ]), { json: false, rawData: limited });
15688
15103
  if (results.length > limit) {
15689
- console.log(import_picocolors17.default.dim(`
15104
+ console.log(import_picocolors16.default.dim(`
15690
15105
  ${results.length - limit} more results not shown.`));
15691
15106
  }
15692
15107
  });
@@ -15699,10 +15114,10 @@ ${results.length - limit} more results not shown.`));
15699
15114
  return;
15700
15115
  }
15701
15116
  if (!store) {
15702
- console.log(import_picocolors17.default.dim("No knowledge store found for this deployment."));
15117
+ console.log(import_picocolors16.default.dim("No knowledge store found for this deployment."));
15703
15118
  return;
15704
15119
  }
15705
- console.log(import_picocolors17.default.bold("Knowledge Store"));
15120
+ console.log(import_picocolors16.default.bold("Knowledge Store"));
15706
15121
  console.log(` ID: ${store.id}`);
15707
15122
  console.log(` Space ID: ${store.space_id}`);
15708
15123
  });
@@ -15712,11 +15127,11 @@ ${results.length - limit} more results not shown.`));
15712
15127
  // src/commands/members.ts
15713
15128
  init_commander();
15714
15129
  init_trpc();
15715
- var import_picocolors18 = __toESM(require_picocolors(), 1);
15130
+ var import_picocolors17 = __toESM(require_picocolors(), 1);
15716
15131
  function requireConfig8() {
15717
15132
  const cfg = requireLoginConfig();
15718
15133
  if (!cfg.org_id) {
15719
- console.error(import_picocolors18.default.red("Missing org config. Run 'dosu setup' to reconfigure."));
15134
+ console.error(import_picocolors17.default.red("Missing org config. Run 'dosu setup' to reconfigure."));
15720
15135
  process.exit(1);
15721
15136
  }
15722
15137
  return cfg;
@@ -15732,7 +15147,7 @@ function membersCommand() {
15732
15147
  return;
15733
15148
  }
15734
15149
  if (!data.items || data.items.length === 0) {
15735
- console.log(import_picocolors18.default.dim("No members or invitations found."));
15150
+ console.log(import_picocolors17.default.dim("No members or invitations found."));
15736
15151
  return;
15737
15152
  }
15738
15153
  printTable(["Email", "Org"], data.items.map((m3) => [
@@ -15753,7 +15168,7 @@ function membersCommand() {
15753
15168
  printResult({ success: true, email, role }, opts);
15754
15169
  return;
15755
15170
  }
15756
- console.log(import_picocolors18.default.green(`Invitation sent to ${email} as ${role}.`));
15171
+ console.log(import_picocolors17.default.green(`Invitation sent to ${email} as ${role}.`));
15757
15172
  });
15758
15173
  cmd.command("requests").description("List pending access requests").option("--json", "Output as JSON").action(async (opts) => {
15759
15174
  const cfg = requireConfig8();
@@ -15764,7 +15179,7 @@ function membersCommand() {
15764
15179
  return;
15765
15180
  }
15766
15181
  if (!data.items || data.items.length === 0) {
15767
- console.log(import_picocolors18.default.dim("No pending access requests."));
15182
+ console.log(import_picocolors17.default.dim("No pending access requests."));
15768
15183
  return;
15769
15184
  }
15770
15185
  printTable(["Email", "Org"], data.items.map((r2) => [
@@ -15783,7 +15198,7 @@ function membersCommand() {
15783
15198
  printResult({ success: true, email, action: "approved" }, opts);
15784
15199
  return;
15785
15200
  }
15786
- console.log(import_picocolors18.default.green(`Access request from ${email} approved.`));
15201
+ console.log(import_picocolors17.default.green(`Access request from ${email} approved.`));
15787
15202
  });
15788
15203
  cmd.command("deny").description("Deny an access request").argument("<email>", "Email of requester").option("--json", "Output as JSON").action(async (email, opts) => {
15789
15204
  const cfg = requireConfig8();
@@ -15796,7 +15211,7 @@ function membersCommand() {
15796
15211
  printResult({ success: true, email, action: "denied" }, opts);
15797
15212
  return;
15798
15213
  }
15799
- console.log(import_picocolors18.default.green(`Access request from ${email} denied.`));
15214
+ console.log(import_picocolors17.default.green(`Access request from ${email} denied.`));
15800
15215
  });
15801
15216
  return cmd;
15802
15217
  }
@@ -15804,7 +15219,7 @@ function membersCommand() {
15804
15219
  // src/commands/org.ts
15805
15220
  init_commander();
15806
15221
  init_trpc();
15807
- var import_picocolors19 = __toESM(require_picocolors(), 1);
15222
+ var import_picocolors18 = __toESM(require_picocolors(), 1);
15808
15223
  function requireConfig9() {
15809
15224
  return requireLoginConfig();
15810
15225
  }
@@ -15819,7 +15234,7 @@ function orgCommand() {
15819
15234
  return;
15820
15235
  }
15821
15236
  if (!orgs || orgs.length === 0) {
15822
- console.log(import_picocolors19.default.dim("No organizations found."));
15237
+ console.log(import_picocolors18.default.dim("No organizations found."));
15823
15238
  return;
15824
15239
  }
15825
15240
  if (orgs.length === 1) {
@@ -15833,7 +15248,7 @@ function orgCommand() {
15833
15248
  printTable(["ID", "Name"], orgs.map((o2) => [o2.org_id.slice(0, 8), o2.name]), { rawData: orgs });
15834
15249
  if (cfg.org_id) {
15835
15250
  console.log(`
15836
- ${import_picocolors19.default.dim(`Current: ${cfg.org_id}`)}`);
15251
+ ${import_picocolors18.default.dim(`Current: ${cfg.org_id}`)}`);
15837
15252
  }
15838
15253
  });
15839
15254
  return cmd;
@@ -15844,7 +15259,7 @@ init_dist8();
15844
15259
  init_dist();
15845
15260
  init_commander();
15846
15261
  init_trpc();
15847
- var import_picocolors20 = __toESM(require_picocolors(), 1);
15262
+ var import_picocolors19 = __toESM(require_picocolors(), 1);
15848
15263
  import { readFileSync as readFileSync14 } from "node:fs";
15849
15264
  function requireConfig10() {
15850
15265
  return requireLoginConfig();
@@ -15870,7 +15285,7 @@ async function requireChange(client, id) {
15870
15285
  return await client.review.getChange.query({ id });
15871
15286
  } catch (err) {
15872
15287
  if (isNotFound(err) || isInvalidId(err)) {
15873
- console.error(import_picocolors20.default.red(`No review item found for '${id}'. Run 'dosu review list' to see pending items.`));
15288
+ console.error(import_picocolors19.default.red(`No review item found for '${id}'. Run 'dosu review list' to see pending items.`));
15874
15289
  process.exit(1);
15875
15290
  }
15876
15291
  throw err;
@@ -15879,7 +15294,7 @@ async function requireChange(client, id) {
15879
15294
  async function requireDraft(client, id) {
15880
15295
  const draft = await client.messages.getMessage.query(bareMessageId(id));
15881
15296
  if (!draft) {
15882
- console.error(import_picocolors20.default.red(`No review item found for '${id}'. Run 'dosu review list' to see pending items.`));
15297
+ console.error(import_picocolors19.default.red(`No review item found for '${id}'. Run 'dosu review list' to see pending items.`));
15883
15298
  process.exit(1);
15884
15299
  }
15885
15300
  return draft;
@@ -15902,12 +15317,12 @@ function colorizeDiff(diff) {
15902
15317
  return diff.split(`
15903
15318
  `).map((line) => {
15904
15319
  if (line.startsWith("+"))
15905
- return import_picocolors20.default.green(line);
15320
+ return import_picocolors19.default.green(line);
15906
15321
  if (line.startsWith("-"))
15907
- return import_picocolors20.default.red(line);
15322
+ return import_picocolors19.default.red(line);
15908
15323
  if (line.startsWith("@@"))
15909
- return import_picocolors20.default.cyan(line);
15910
- return import_picocolors20.default.dim(line);
15324
+ return import_picocolors19.default.cyan(line);
15325
+ return import_picocolors19.default.dim(line);
15911
15326
  }).join(`
15912
15327
  `);
15913
15328
  }
@@ -15921,7 +15336,7 @@ function printChangePreview(change) {
15921
15336
  ]
15922
15337
  ]);
15923
15338
  if (!change.hasChanges) {
15924
- console.log(import_picocolors20.default.dim("No content changes."));
15339
+ console.log(import_picocolors19.default.dim("No content changes."));
15925
15340
  return;
15926
15341
  }
15927
15342
  console.log();
@@ -15938,7 +15353,7 @@ function printDraftPreview(draft) {
15938
15353
  async function getKnowledgeStoreId2(client, spaceId) {
15939
15354
  const store = await client.knowledgeStore.getBySpaceId.query({ space_id: spaceId });
15940
15355
  if (!store) {
15941
- console.error(import_picocolors20.default.red("No knowledge store found for this deployment."));
15356
+ console.error(import_picocolors19.default.red("No knowledge store found for this deployment."));
15942
15357
  process.exit(1);
15943
15358
  }
15944
15359
  return store.id;
@@ -15948,7 +15363,7 @@ function reviewCommand() {
15948
15363
  cmd.command("list").description("List pending review items (doc changes and draft replies)").option("--json", "Output as JSON").action(async (opts) => {
15949
15364
  const cfg = requireConfig10();
15950
15365
  if (!cfg.space_id) {
15951
- console.error(import_picocolors20.default.red("Missing space config. Run 'dosu setup' to reconfigure."));
15366
+ console.error(import_picocolors19.default.red("Missing space config. Run 'dosu setup' to reconfigure."));
15952
15367
  process.exit(1);
15953
15368
  }
15954
15369
  const client = createTypedClient(cfg);
@@ -15963,7 +15378,7 @@ function reviewCommand() {
15963
15378
  return;
15964
15379
  }
15965
15380
  if (!items || items.length === 0) {
15966
- console.log(import_picocolors20.default.dim("No pending review items."));
15381
+ console.log(import_picocolors19.default.dim("No pending review items."));
15967
15382
  return;
15968
15383
  }
15969
15384
  printTable(["ID", "Kind", "Title", "Source", "Status", "Created"], items.map((i2) => i2.kind === "draft_message" ? [
@@ -15982,7 +15397,7 @@ function reviewCommand() {
15982
15397
  formatDate(i2.createdAt)
15983
15398
  ]), { rawData: items });
15984
15399
  if (truncated) {
15985
- console.log(import_picocolors20.default.dim(`Showing ${items.length} of ${total}+ pending items (list truncated).`));
15400
+ console.log(import_picocolors19.default.dim(`Showing ${items.length} of ${total}+ pending items (list truncated).`));
15986
15401
  }
15987
15402
  });
15988
15403
  cmd.command("diff").description("Show a pending review item (doc-change diff or draft reply body)").argument("<id>", "Review item ID (from `dosu review list`)").option("--json", "Output as JSON").action(async (id, opts) => {
@@ -15994,8 +15409,8 @@ function reviewCommand() {
15994
15409
  printResult({ id, kind: "draft_message", title: draft.title, body: draft.body }, opts);
15995
15410
  return;
15996
15411
  }
15997
- console.log(import_picocolors20.default.bold(draft.title ?? "(untitled)"));
15998
- console.log(import_picocolors20.default.dim("Draft reply"));
15412
+ console.log(import_picocolors19.default.bold(draft.title ?? "(untitled)"));
15413
+ console.log(import_picocolors19.default.dim("Draft reply"));
15999
15414
  console.log("");
16000
15415
  console.log(draft.body ?? "");
16001
15416
  return;
@@ -16006,8 +15421,8 @@ function reviewCommand() {
16006
15421
  return;
16007
15422
  }
16008
15423
  const versions = change.publishedVersion != null ? `v${change.publishedVersion} → v${change.version}` : `v${change.version}`;
16009
- console.log(import_picocolors20.default.bold(change.title));
16010
- console.log(import_picocolors20.default.dim(`${change.source} · ${versions}`));
15424
+ console.log(import_picocolors19.default.bold(change.title));
15425
+ console.log(import_picocolors19.default.dim(`${change.source} · ${versions}`));
16011
15426
  console.log("");
16012
15427
  console.log(change.diff);
16013
15428
  });
@@ -16015,7 +15430,7 @@ function reviewCommand() {
16015
15430
  const cfg = requireConfig10();
16016
15431
  const client = createTypedClient(cfg);
16017
15432
  if (opts.body !== undefined && opts.bodyFile !== undefined) {
16018
- console.error(import_picocolors20.default.red("Pass only one of --body or --body-file."));
15433
+ console.error(import_picocolors19.default.red("Pass only one of --body or --body-file."));
16019
15434
  process.exit(1);
16020
15435
  }
16021
15436
  let body = opts.body;
@@ -16023,17 +15438,17 @@ function reviewCommand() {
16023
15438
  try {
16024
15439
  body = readFileSync14(opts.bodyFile, "utf-8");
16025
15440
  } catch (err) {
16026
- console.error(import_picocolors20.default.red(`Failed to read --body-file: ${err.message}`));
15441
+ console.error(import_picocolors19.default.red(`Failed to read --body-file: ${err.message}`));
16027
15442
  process.exit(1);
16028
15443
  }
16029
15444
  }
16030
15445
  if (body === undefined && opts.title === undefined) {
16031
- console.error(import_picocolors20.default.red("Nothing to edit. Pass --title and/or --body/--body-file."));
15446
+ console.error(import_picocolors19.default.red("Nothing to edit. Pass --title and/or --body/--body-file."));
16032
15447
  process.exit(1);
16033
15448
  }
16034
15449
  if (isDraftId(id)) {
16035
15450
  if (opts.title !== undefined) {
16036
- console.error(import_picocolors20.default.red("Draft replies support --body only (no --title)."));
15451
+ console.error(import_picocolors19.default.red("Draft replies support --body only (no --title)."));
16037
15452
  process.exit(1);
16038
15453
  }
16039
15454
  await requireDraft(client, id);
@@ -16050,7 +15465,7 @@ function reviewCommand() {
16050
15465
  });
16051
15466
  } catch (err) {
16052
15467
  if (isNotFound(err)) {
16053
- console.error(import_picocolors20.default.red(`No pending review item found for '${id}'. Run 'dosu review list' to see editable items.`));
15468
+ console.error(import_picocolors19.default.red(`No pending review item found for '${id}'. Run 'dosu review list' to see editable items.`));
16054
15469
  process.exit(1);
16055
15470
  }
16056
15471
  throw err;
@@ -16060,7 +15475,7 @@ function reviewCommand() {
16060
15475
  printResult({ success: true, id }, opts);
16061
15476
  return;
16062
15477
  }
16063
- console.log(import_picocolors20.default.green(`Review edited: ${truncateId(id)}`));
15478
+ console.log(import_picocolors19.default.green(`Review edited: ${truncateId(id)}`));
16064
15479
  });
16065
15480
  cmd.command("context").description("Get review context for a thread").argument("<thread-id>", "Thread ID").option("--json", "Output as JSON").action(async (threadId, opts) => {
16066
15481
  const cfg = requireConfig10();
@@ -16107,7 +15522,7 @@ function reviewCommand() {
16107
15522
  initialValue: false
16108
15523
  });
16109
15524
  if (isCancel(answer)) {
16110
- console.log(import_picocolors20.default.dim("Cancelled."));
15525
+ console.log(import_picocolors19.default.dim("Cancelled."));
16111
15526
  return;
16112
15527
  }
16113
15528
  proceed = answer === true;
@@ -16122,7 +15537,7 @@ function reviewCommand() {
16122
15537
  };
16123
15538
  printResult({ ...preview, applied: false, confirmRequired: true }, opts);
16124
15539
  } else {
16125
- console.log(import_picocolors20.default.dim("Aborted. Re-run with --confirm to apply."));
15540
+ console.log(import_picocolors19.default.dim("Aborted. Re-run with --confirm to apply."));
16126
15541
  }
16127
15542
  return;
16128
15543
  }
@@ -16137,7 +15552,7 @@ function reviewCommand() {
16137
15552
  printResult({ success: true, id, action }, opts);
16138
15553
  return;
16139
15554
  }
16140
- console.log(import_picocolors20.default.green(`Review ${name}: ${truncateId(id)}`));
15555
+ console.log(import_picocolors19.default.green(`Review ${name}: ${truncateId(id)}`));
16141
15556
  });
16142
15557
  }
16143
15558
  cmd.command("revert").description("Revert a doc change to pending review (not supported for draft replies)").argument("<id>", "Review item ID (from `dosu review list`)").option("--json", "Output as JSON").action(async (id, opts) => {
@@ -16145,7 +15560,7 @@ function reviewCommand() {
16145
15560
  const client = createTypedClient(cfg);
16146
15561
  if (isDraftId(id)) {
16147
15562
  await requireDraft(client, id);
16148
- console.error(import_picocolors20.default.red("Revert is not supported for draft replies. A rejected draft is regenerated on the next agent run."));
15563
+ console.error(import_picocolors19.default.red("Revert is not supported for draft replies. A rejected draft is regenerated on the next agent run."));
16149
15564
  process.exit(1);
16150
15565
  }
16151
15566
  await requireChange(client, id);
@@ -16157,7 +15572,7 @@ function reviewCommand() {
16157
15572
  printResult({ success: true, id, action: "revert_to_pending" }, opts);
16158
15573
  return;
16159
15574
  }
16160
- console.log(import_picocolors20.default.green(`Review revert: ${truncateId(id)}`));
15575
+ console.log(import_picocolors19.default.green(`Review revert: ${truncateId(id)}`));
16161
15576
  });
16162
15577
  return cmd;
16163
15578
  }
@@ -16168,11 +15583,11 @@ init_skill();
16168
15583
  // src/commands/sources.ts
16169
15584
  init_commander();
16170
15585
  init_trpc();
16171
- var import_picocolors21 = __toESM(require_picocolors(), 1);
15586
+ var import_picocolors20 = __toESM(require_picocolors(), 1);
16172
15587
  function requireConfig11() {
16173
15588
  const cfg = requireLoginConfig();
16174
15589
  if (!cfg.org_id) {
16175
- console.error(import_picocolors21.default.red("Missing org config. Run 'dosu setup' to reconfigure."));
15590
+ console.error(import_picocolors20.default.red("Missing org config. Run 'dosu setup' to reconfigure."));
16176
15591
  process.exit(1);
16177
15592
  }
16178
15593
  return cfg;
@@ -16192,7 +15607,7 @@ function sourcesCommand() {
16192
15607
  }
16193
15608
  const list = dataSources ?? [];
16194
15609
  if (list.length === 0) {
16195
- console.log(import_picocolors21.default.dim("No data sources connected."));
15610
+ console.log(import_picocolors20.default.dim("No data sources connected."));
16196
15611
  return;
16197
15612
  }
16198
15613
  printTable(["ID", "Name", "Provider", "Created"], list.map((ds) => [
@@ -16211,7 +15626,7 @@ function sourcesCommand() {
16211
15626
  return;
16212
15627
  }
16213
15628
  if (!ds) {
16214
- console.log(import_picocolors21.default.dim("Data source not found."));
15629
+ console.log(import_picocolors20.default.dim("Data source not found."));
16215
15630
  return;
16216
15631
  }
16217
15632
  printInfo([
@@ -16230,7 +15645,7 @@ function sourcesCommand() {
16230
15645
  printResult({ success: true, id }, opts);
16231
15646
  return;
16232
15647
  }
16233
- console.log(import_picocolors21.default.green(`Data source sync triggered for ${id.slice(0, 8)}.`));
15648
+ console.log(import_picocolors20.default.green(`Data source sync triggered for ${id.slice(0, 8)}.`));
16234
15649
  });
16235
15650
  cmd.command("update").description("Update a data source").argument("<id>", "Data source ID").option("--name <name>", "New name").option("--description <desc>", "New description").option("--json", "Output as JSON").action(async (id, opts) => {
16236
15651
  const cfg = requireConfig11();
@@ -16244,7 +15659,7 @@ function sourcesCommand() {
16244
15659
  printResult(result, opts);
16245
15660
  return;
16246
15661
  }
16247
- console.log(import_picocolors21.default.green("Data source updated."));
15662
+ console.log(import_picocolors20.default.green("Data source updated."));
16248
15663
  });
16249
15664
  cmd.command("delete").description("Delete a data source").argument("<id>", "Data source ID").option("--json", "Output as JSON").action(async (id, opts) => {
16250
15665
  const cfg = requireConfig11();
@@ -16254,7 +15669,7 @@ function sourcesCommand() {
16254
15669
  printResult({ success: true, id }, opts);
16255
15670
  return;
16256
15671
  }
16257
- console.log(import_picocolors21.default.green("Data source deleted."));
15672
+ console.log(import_picocolors20.default.green("Data source deleted."));
16258
15673
  });
16259
15674
  return cmd;
16260
15675
  }
@@ -16262,11 +15677,11 @@ function sourcesCommand() {
16262
15677
  // src/commands/suggest.ts
16263
15678
  init_commander();
16264
15679
  init_trpc();
16265
- var import_picocolors22 = __toESM(require_picocolors(), 1);
15680
+ var import_picocolors21 = __toESM(require_picocolors(), 1);
16266
15681
  function requireConfig12() {
16267
15682
  const cfg = requireLoginConfig();
16268
15683
  if (!cfg.space_id) {
16269
- console.error(import_picocolors22.default.red("Missing space config. Run 'dosu setup' to reconfigure."));
15684
+ console.error(import_picocolors21.default.red("Missing space config. Run 'dosu setup' to reconfigure."));
16270
15685
  process.exit(1);
16271
15686
  }
16272
15687
  return cfg;
@@ -16276,7 +15691,7 @@ async function getKnowledgeStoreId3(client, spaceId) {
16276
15691
  space_id: spaceId
16277
15692
  });
16278
15693
  if (!store) {
16279
- console.error(import_picocolors22.default.red("No knowledge store found for this deployment."));
15694
+ console.error(import_picocolors21.default.red("No knowledge store found for this deployment."));
16280
15695
  process.exit(1);
16281
15696
  }
16282
15697
  return store.id;
@@ -16295,7 +15710,7 @@ function suggestCommand() {
16295
15710
  return;
16296
15711
  }
16297
15712
  if (!suggestions || suggestions.length === 0) {
16298
- console.log(import_picocolors22.default.dim("No pending suggestions."));
15713
+ console.log(import_picocolors21.default.dim("No pending suggestions."));
16299
15714
  return;
16300
15715
  }
16301
15716
  printTable(["ID", "Title"], suggestions.map((s) => [
@@ -16308,7 +15723,7 @@ function suggestCommand() {
16308
15723
  const client = createTypedClient(cfg);
16309
15724
  const ksId = await getKnowledgeStoreId3(client, cfg.space_id);
16310
15725
  if (!cfg.org_id) {
16311
- console.error(import_picocolors22.default.red("Missing org config. Run 'dosu setup' to reconfigure."));
15726
+ console.error(import_picocolors21.default.red("Missing org config. Run 'dosu setup' to reconfigure."));
16312
15727
  process.exit(1);
16313
15728
  }
16314
15729
  const dataSources = await client.dataSource.list.query({
@@ -16324,7 +15739,7 @@ function suggestCommand() {
16324
15739
  printResult(result, opts);
16325
15740
  return;
16326
15741
  }
16327
- console.log(import_picocolors22.default.green("Document suggestions are being generated."));
15742
+ console.log(import_picocolors21.default.green("Document suggestions are being generated."));
16328
15743
  });
16329
15744
  cmd.command("reject").description("Reject a suggestion").argument("<id>", "Suggestion ID").option("--json", "Output as JSON").action(async (id, opts) => {
16330
15745
  const cfg = requireConfig12();
@@ -16334,7 +15749,7 @@ function suggestCommand() {
16334
15749
  printResult({ success: true, id }, opts);
16335
15750
  return;
16336
15751
  }
16337
- console.log(import_picocolors22.default.green("Suggestion rejected."));
15752
+ console.log(import_picocolors21.default.green("Suggestion rejected."));
16338
15753
  });
16339
15754
  return cmd;
16340
15755
  }
@@ -16342,11 +15757,11 @@ function suggestCommand() {
16342
15757
  // src/commands/threads.ts
16343
15758
  init_commander();
16344
15759
  init_trpc();
16345
- var import_picocolors23 = __toESM(require_picocolors(), 1);
15760
+ var import_picocolors22 = __toESM(require_picocolors(), 1);
16346
15761
  function requireConfig13() {
16347
15762
  const cfg = requireLoginConfig();
16348
15763
  if (!cfg.space_id) {
16349
- console.error(import_picocolors23.default.red("Missing space config. Run 'dosu setup' to reconfigure."));
15764
+ console.error(import_picocolors22.default.red("Missing space config. Run 'dosu setup' to reconfigure."));
16350
15765
  process.exit(1);
16351
15766
  }
16352
15767
  return cfg;
@@ -16393,7 +15808,7 @@ function threadsCommand() {
16393
15808
  return;
16394
15809
  }
16395
15810
  if (!threads || threads.length === 0) {
16396
- console.log(import_picocolors23.default.dim("No threads found."));
15811
+ console.log(import_picocolors22.default.dim("No threads found."));
16397
15812
  return;
16398
15813
  }
16399
15814
  printTable(["ID", "Title", "Status", "Created"], threads.map((t2) => [
@@ -16418,10 +15833,10 @@ function threadsCommand() {
16418
15833
  return;
16419
15834
  }
16420
15835
  if (!thread) {
16421
- console.log(import_picocolors23.default.dim("Thread not found."));
15836
+ console.log(import_picocolors22.default.dim("Thread not found."));
16422
15837
  return;
16423
15838
  }
16424
- console.log(import_picocolors23.default.bold(thread.generated_title ?? "(untitled thread)"));
15839
+ console.log(import_picocolors22.default.bold(thread.generated_title ?? "(untitled thread)"));
16425
15840
  printInfo([
16426
15841
  ["ID", thread.id],
16427
15842
  ["Created", formatDate(thread.created_at)],
@@ -16432,13 +15847,13 @@ function threadsCommand() {
16432
15847
  if (messages && messages.length > 0) {
16433
15848
  const allMessages = messages.flatMap((group) => group.messages);
16434
15849
  console.log(`
16435
- ${import_picocolors23.default.bold("Messages")} (${allMessages.length})`);
16436
- console.log(import_picocolors23.default.dim("─".repeat(60)));
15850
+ ${import_picocolors22.default.bold("Messages")} (${allMessages.length})`);
15851
+ console.log(import_picocolors22.default.dim("─".repeat(60)));
16437
15852
  for (const msg of allMessages) {
16438
15853
  const role = msg.author_role ?? "unknown";
16439
15854
  const date = formatDate(msg.created_at);
16440
15855
  console.log(`
16441
- ${import_picocolors23.default.bold(role)} ${import_picocolors23.default.dim(date)}`);
15856
+ ${import_picocolors22.default.bold(role)} ${import_picocolors22.default.dim(date)}`);
16442
15857
  if (msg.body) {
16443
15858
  console.log(truncate(msg.body, 500));
16444
15859
  }
@@ -16453,7 +15868,7 @@ ${import_picocolors23.default.bold(role)} ${import_picocolors23.default.dim(date
16453
15868
  printResult({ success: true, id }, opts);
16454
15869
  return;
16455
15870
  }
16456
- console.log(import_picocolors23.default.green(`Thread ${id.slice(0, 8)} archived.`));
15871
+ console.log(import_picocolors22.default.green(`Thread ${id.slice(0, 8)} archived.`));
16457
15872
  });
16458
15873
  return cmd;
16459
15874
  }
@@ -16461,11 +15876,11 @@ ${import_picocolors23.default.bold(role)} ${import_picocolors23.default.dim(date
16461
15876
  // src/commands/topics.ts
16462
15877
  init_commander();
16463
15878
  init_trpc();
16464
- var import_picocolors24 = __toESM(require_picocolors(), 1);
15879
+ var import_picocolors23 = __toESM(require_picocolors(), 1);
16465
15880
  function requireConfig14() {
16466
15881
  const cfg = requireLoginConfig();
16467
15882
  if (!cfg.space_id) {
16468
- console.error(import_picocolors24.default.red("Missing space config. Run 'dosu setup' to reconfigure."));
15883
+ console.error(import_picocolors23.default.red("Missing space config. Run 'dosu setup' to reconfigure."));
16469
15884
  process.exit(1);
16470
15885
  }
16471
15886
  return cfg;
@@ -16475,7 +15890,7 @@ async function getKnowledgeStoreId4(client, spaceId) {
16475
15890
  space_id: spaceId
16476
15891
  });
16477
15892
  if (!store) {
16478
- console.error(import_picocolors24.default.red("No knowledge store found for this deployment."));
15893
+ console.error(import_picocolors23.default.red("No knowledge store found for this deployment."));
16479
15894
  process.exit(1);
16480
15895
  }
16481
15896
  return store.id;
@@ -16494,7 +15909,7 @@ function topicsCommand() {
16494
15909
  return;
16495
15910
  }
16496
15911
  if (!topics || topics.length === 0) {
16497
- console.log(import_picocolors24.default.dim("No topics found."));
15912
+ console.log(import_picocolors23.default.dim("No topics found."));
16498
15913
  return;
16499
15914
  }
16500
15915
  printTable(["ID", "Name", "Description"], topics.map((t2) => [
@@ -16519,7 +15934,7 @@ function topicsCommand() {
16519
15934
  return;
16520
15935
  }
16521
15936
  if (!pages || pages.length === 0) {
16522
- console.log(import_picocolors24.default.dim("No pages found with this topic."));
15937
+ console.log(import_picocolors23.default.dim("No pages found with this topic."));
16523
15938
  return;
16524
15939
  }
16525
15940
  printTable(["ID", "Title"], pages.map((p2) => [
@@ -16534,14 +15949,15 @@ function topicsCommand() {
16534
15949
  init_config();
16535
15950
  init_logger();
16536
15951
  init_providers();
15952
+ init_styles();
16537
15953
  init_skill_update_check();
16538
15954
 
16539
15955
  // src/version/update-check.ts
16540
15956
  init_config();
16541
15957
  init_logger();
16542
- var import_picocolors25 = __toESM(require_picocolors(), 1);
16543
- import { existsSync as existsSync18, mkdirSync as mkdirSync9, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "node:fs";
16544
- import { join as join28 } from "node:path";
15958
+ var import_picocolors24 = __toESM(require_picocolors(), 1);
15959
+ import { existsSync as existsSync17, mkdirSync as mkdirSync9, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "node:fs";
15960
+ import { join as join27 } from "node:path";
16545
15961
  var CACHE_FILENAME3 = "update-check.json";
16546
15962
  var CHECK_INTERVAL_MS3 = 24 * 60 * 60 * 1000;
16547
15963
  var FETCH_TIMEOUT_MS3 = 5000;
@@ -16564,12 +15980,12 @@ function isNewerVersion(latest, current) {
16564
15980
  return false;
16565
15981
  }
16566
15982
  function getCachePath3() {
16567
- return join28(getConfigDir(), CACHE_FILENAME3);
15983
+ return join27(getConfigDir(), CACHE_FILENAME3);
16568
15984
  }
16569
15985
  function readCache() {
16570
15986
  try {
16571
15987
  const path3 = getCachePath3();
16572
- if (!existsSync18(path3))
15988
+ if (!existsSync17(path3))
16573
15989
  return null;
16574
15990
  const data = JSON.parse(readFileSync15(path3, "utf-8"));
16575
15991
  if (typeof data.lastCheck === "number" && typeof data.latestVersion === "string") {
@@ -16583,7 +15999,7 @@ function readCache() {
16583
15999
  function writeCache(cache) {
16584
16000
  try {
16585
16001
  const dir = getConfigDir();
16586
- if (!existsSync18(dir)) {
16002
+ if (!existsSync17(dir)) {
16587
16003
  mkdirSync9(dir, { recursive: true, mode: 448 });
16588
16004
  }
16589
16005
  writeFileSync8(getCachePath3(), JSON.stringify(cache), { mode: 384 });
@@ -16614,8 +16030,8 @@ function buildUpdateHint(channel) {
16614
16030
  }
16615
16031
  function displayNotice2(current, latest) {
16616
16032
  const msg = `
16617
- ${import_picocolors25.default.yellow(` Update available: ${current} → ${latest}`)}
16618
- ` + `${import_picocolors25.default.dim(` ${buildUpdateHint(INSTALL_CHANNEL)}`)}
16033
+ ${import_picocolors24.default.yellow(` Update available: ${current} → ${latest}`)}
16034
+ ` + `${import_picocolors24.default.dim(` ${buildUpdateHint(INSTALL_CHANNEL)}`)}
16619
16035
  `;
16620
16036
  console.error(msg);
16621
16037
  }
@@ -16714,7 +16130,9 @@ function createProgram() {
16714
16130
  const { startOAuthFlow: startOAuthFlow2 } = await Promise.resolve().then(() => (init_flow(), exports_flow));
16715
16131
  let result;
16716
16132
  try {
16717
- result = await startOAuthFlow2();
16133
+ result = await startOAuthFlow2(undefined, undefined, undefined, (url) => {
16134
+ console.log(browserFallbackHint(url));
16135
+ });
16718
16136
  } catch (err) {
16719
16137
  if (err instanceof OAuthCallbackError2) {
16720
16138
  console.error(err.userMessage);