@dosu/cli 0.31.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 +302 -898
  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.31.0", INSTALL_CHANNEL = "npm";
4580
+ var VERSION = "0.32.0", INSTALL_CHANNEL = "npm";
4581
4581
 
4582
4582
  // src/debug/logger.ts
4583
4583
  import {
@@ -7628,12 +7628,6 @@ var init_open = __esm(() => {
7628
7628
  });
7629
7629
 
7630
7630
  // src/setup/github-step.ts
7631
- var exports_github_step = {};
7632
- __export(exports_github_step, {
7633
- verifyDataSourcesPersist: () => verifyDataSourcesPersist,
7634
- stepConnectGitHubRepo: () => stepConnectGitHubRepo,
7635
- detectGitRepo: () => detectGitRepo
7636
- });
7637
7631
  import { execSync } from "node:child_process";
7638
7632
  function detectGitRepo(cwd = process.cwd()) {
7639
7633
  let url;
@@ -11140,633 +11134,6 @@ var init_audit_handoff = __esm(() => {
11140
11134
  init_styles();
11141
11135
  });
11142
11136
 
11143
- // src/setup/github-doc-import-prompt.ts
11144
- async function promptGitHubDocsImport({
11145
- repositories
11146
- }) {
11147
- const prompt = new GitHubDocsImportPrompt({ repositories });
11148
- return await prompt.prompt();
11149
- }
11150
- function getSelectableFileIds(files) {
11151
- return files.filter((file) => !file.is_synced).map((file) => file.id);
11152
- }
11153
- function visibleOptions2(cursor3, totalItems, maxItems) {
11154
- const terminalRows = process.stdout.rows ? Math.max(process.stdout.rows - 8, 0) : totalItems;
11155
- const visibleCount = Math.min(terminalRows || totalItems, Math.max(maxItems ?? Infinity, 5));
11156
- if (visibleCount >= totalItems) {
11157
- return Array.from({ length: totalItems }, (_2, index) => ({ kind: "option", index }));
11158
- }
11159
- let start = 0;
11160
- if (cursor3 >= start + visibleCount - 3) {
11161
- start = Math.max(Math.min(cursor3 - visibleCount + 3, totalItems - visibleCount), 0);
11162
- } else if (cursor3 < start + 2) {
11163
- start = Math.max(cursor3 - 2, 0);
11164
- }
11165
- const hasTopEllipsis = visibleCount < totalItems && start > 0;
11166
- const hasBottomEllipsis = visibleCount < totalItems && start + visibleCount < totalItems;
11167
- return Array.from({ length: visibleCount }, (_2, index) => {
11168
- const isTopEllipsis = index === 0 && hasTopEllipsis;
11169
- const isBottomEllipsis = index === visibleCount - 1 && hasBottomEllipsis;
11170
- if (isTopEllipsis || isBottomEllipsis) {
11171
- return { kind: "ellipsis" };
11172
- }
11173
- return { kind: "option", index: start + index };
11174
- });
11175
- }
11176
- function wrapIndex(index, length) {
11177
- if (length === 0)
11178
- return 0;
11179
- if (index < 0)
11180
- return length - 1;
11181
- if (index >= length)
11182
- return 0;
11183
- return index;
11184
- }
11185
- function isPrintableKey(key) {
11186
- return key.length === 1 && key >= " " && key !== "";
11187
- }
11188
- var import_picocolors14, CHECKBOX_PARTIAL, MAX_VISIBLE_FILE_ITEMS = 15, GitHubDocsImportPrompt;
11189
- var init_github_doc_import_prompt = __esm(() => {
11190
- init_dist7();
11191
- init_prompt_symbols();
11192
- import_picocolors14 = __toESM(require_picocolors(), 1);
11193
- CHECKBOX_PARTIAL = symbol2("◧", "[-]");
11194
- GitHubDocsImportPrompt = class GitHubDocsImportPrompt extends V {
11195
- repositories;
11196
- mode = "repos";
11197
- repoCursor = 0;
11198
- fileCursor = 0;
11199
- searchQuery = "";
11200
- searchActive = false;
11201
- selectedIds = new Set;
11202
- constructor({ repositories }) {
11203
- super({
11204
- render() {
11205
- return this.renderPrompt();
11206
- }
11207
- }, false);
11208
- this.repositories = repositories;
11209
- this.selectedIds = new Set(repositories.flatMap((repository) => getSelectableFileIds(repository.files)));
11210
- this.syncValue();
11211
- this.onKeypress = this.handleRawKeypress.bind(this);
11212
- }
11213
- handleRawKeypress(key, info2) {
11214
- this.handleKeypress(key, info2);
11215
- this.syncValue();
11216
- if (this.rl) {
11217
- this.render();
11218
- }
11219
- if ((this.state === "submit" || this.state === "cancel") && this.rl) {
11220
- this.close();
11221
- }
11222
- }
11223
- handleKeypress(key, info2) {
11224
- if (info2?.ctrl && info2.name === "c") {
11225
- this.state = "cancel";
11226
- return;
11227
- }
11228
- if (this.mode === "repos") {
11229
- this.handleRepoModeKey(info2);
11230
- return;
11231
- }
11232
- this.handleFileModeKey(key, info2);
11233
- }
11234
- handleRepoModeKey(info2) {
11235
- switch (info2?.name) {
11236
- case "up":
11237
- this.moveRepoCursor(-1);
11238
- return;
11239
- case "down":
11240
- this.moveRepoCursor(1);
11241
- return;
11242
- case "right":
11243
- this.enterRepository();
11244
- return;
11245
- case "space":
11246
- this.toggleCurrentRepository();
11247
- return;
11248
- case "return":
11249
- this.state = "submit";
11250
- return;
11251
- case "left":
11252
- return;
11253
- case "escape":
11254
- this.state = "cancel";
11255
- return;
11256
- default:
11257
- return;
11258
- }
11259
- }
11260
- handleFileModeKey(key, info2) {
11261
- switch (info2?.name) {
11262
- case "up":
11263
- this.moveFileCursor(-1);
11264
- return;
11265
- case "down":
11266
- this.moveFileCursor(1);
11267
- return;
11268
- case "left":
11269
- this.leaveRepository();
11270
- return;
11271
- case "space":
11272
- this.toggleCurrentFile();
11273
- return;
11274
- case "backspace":
11275
- this.searchQuery = this.searchQuery.slice(0, -1);
11276
- this.searchActive = this.searchQuery.length > 0;
11277
- this.resetFileCursor();
11278
- return;
11279
- case "return":
11280
- this.leaveRepository();
11281
- return;
11282
- case "escape":
11283
- if (this.searchQuery || this.searchActive) {
11284
- this.searchQuery = "";
11285
- this.searchActive = false;
11286
- this.resetFileCursor();
11287
- return;
11288
- }
11289
- this.state = "cancel";
11290
- return;
11291
- default:
11292
- break;
11293
- }
11294
- if (!key)
11295
- return;
11296
- if (key === "/") {
11297
- this.searchActive = true;
11298
- return;
11299
- }
11300
- if (key === "a" && !this.searchActive && this.searchQuery.length === 0) {
11301
- this.toggleAllVisibleFiles();
11302
- return;
11303
- }
11304
- if (!isPrintableKey(key))
11305
- return;
11306
- this.searchActive = true;
11307
- this.searchQuery += key;
11308
- this.resetFileCursor();
11309
- }
11310
- get currentRepository() {
11311
- return this.repositories[this.repoCursor];
11312
- }
11313
- get filteredFiles() {
11314
- const files = this.currentRepository?.files ?? [];
11315
- const query = this.searchQuery.trim().toLowerCase();
11316
- if (!query)
11317
- return files;
11318
- return files.filter((file) => file.path.toLowerCase().includes(query));
11319
- }
11320
- syncValue() {
11321
- this.value = Array.from(this.selectedIds);
11322
- }
11323
- moveRepoCursor(delta) {
11324
- if (this.repositories.length === 0)
11325
- return;
11326
- this.repoCursor = wrapIndex(this.repoCursor + delta, this.repositories.length);
11327
- }
11328
- moveFileCursor(delta) {
11329
- if (this.filteredFiles.length === 0)
11330
- return;
11331
- this.fileCursor = wrapIndex(this.fileCursor + delta, this.filteredFiles.length);
11332
- }
11333
- enterRepository() {
11334
- if (!this.currentRepository)
11335
- return;
11336
- this.mode = "files";
11337
- this.searchQuery = "";
11338
- this.searchActive = false;
11339
- this.resetFileCursor();
11340
- }
11341
- leaveRepository() {
11342
- this.mode = "repos";
11343
- this.searchQuery = "";
11344
- this.searchActive = false;
11345
- this.fileCursor = 0;
11346
- }
11347
- resetFileCursor() {
11348
- this.fileCursor = 0;
11349
- }
11350
- toggleCurrentRepository() {
11351
- const repo = this.currentRepository;
11352
- if (!repo)
11353
- return;
11354
- const selectableIds = getSelectableFileIds(repo.files);
11355
- if (selectableIds.length === 0)
11356
- return;
11357
- const allSelected = selectableIds.every((id) => this.selectedIds.has(id));
11358
- if (allSelected) {
11359
- for (const id of selectableIds) {
11360
- this.selectedIds.delete(id);
11361
- }
11362
- return;
11363
- }
11364
- for (const id of selectableIds) {
11365
- this.selectedIds.add(id);
11366
- }
11367
- }
11368
- toggleCurrentFile() {
11369
- const file = this.filteredFiles[this.fileCursor];
11370
- if (!file || file.is_synced)
11371
- return;
11372
- if (this.selectedIds.has(file.id)) {
11373
- this.selectedIds.delete(file.id);
11374
- return;
11375
- }
11376
- this.selectedIds.add(file.id);
11377
- }
11378
- toggleAllVisibleFiles() {
11379
- const selectableIds = getSelectableFileIds(this.filteredFiles);
11380
- if (selectableIds.length === 0)
11381
- return;
11382
- const allSelected = selectableIds.every((id) => this.selectedIds.has(id));
11383
- if (allSelected) {
11384
- for (const id of selectableIds) {
11385
- this.selectedIds.delete(id);
11386
- }
11387
- return;
11388
- }
11389
- for (const id of selectableIds) {
11390
- this.selectedIds.add(id);
11391
- }
11392
- }
11393
- getRepositorySelectionState(repo) {
11394
- const selectableIds = getSelectableFileIds(repo.files);
11395
- if (selectableIds.length === 0)
11396
- return "locked";
11397
- let selectedCount = 0;
11398
- for (const id of selectableIds) {
11399
- if (this.selectedIds.has(id))
11400
- selectedCount += 1;
11401
- }
11402
- if (selectedCount === 0)
11403
- return "none";
11404
- if (selectedCount === selectableIds.length)
11405
- return "all";
11406
- return "partial";
11407
- }
11408
- renderPrompt() {
11409
- 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);
11410
- const title = this.mode === "repos" ? "Select docs to import" : this.currentRepository?.slug ?? "Files";
11411
- const header = `${import_picocolors14.default.gray(BAR)}
11412
- ${promptSymbol} ${title}
11413
- `;
11414
- if (this.state === "submit") {
11415
- return `${header}${import_picocolors14.default.gray(BAR)} ${import_picocolors14.default.dim(this.submitLabel())}`;
11416
- }
11417
- if (this.state === "cancel") {
11418
- return `${header}${import_picocolors14.default.gray(BAR)}`;
11419
- }
11420
- return this.mode === "repos" ? this.renderRepositoryMode(header) : this.renderFileMode(header);
11421
- }
11422
- renderRepositoryMode(header) {
11423
- const help = `${import_picocolors14.default.gray(BAR)} ${import_picocolors14.default.dim("space: import all docs in a repo →: browse repo docs Enter: confirm")}`;
11424
- const body = visibleOptions2(this.repoCursor, this.repositories.length).map((option) => {
11425
- if (option.kind === "ellipsis") {
11426
- return `${import_picocolors14.default.gray(BAR)} ${import_picocolors14.default.dim(ELLIPSIS)}`;
11427
- }
11428
- const repo = this.repositories[option.index];
11429
- const isActive = option.index === this.repoCursor;
11430
- const state = this.getRepositorySelectionState(repo);
11431
- const marker = this.renderRepositoryMarker(state, isActive);
11432
- const label = isActive ? import_picocolors14.default.cyan(repo.slug) : repo.slug;
11433
- const hint = state === "locked" ? ` ${import_picocolors14.default.dim("(All docs already imported)")}` : "";
11434
- return `${import_picocolors14.default.gray(BAR)} ${marker} ${label}${hint}`;
11435
- });
11436
- return `${header}${help}
11437
- ${import_picocolors14.default.gray(BAR)}
11438
- ${body.join(`
11439
- `)}
11440
- ${import_picocolors14.default.cyan(FOOTER)}`;
11441
- }
11442
- renderFileMode(header) {
11443
- const back = `${import_picocolors14.default.gray(BAR)} ${import_picocolors14.default.dim("←: back / Enter")}`;
11444
- const searchValue = this.searchQuery || import_picocolors14.default.dim(this.searchActive ? "" : "type to filter");
11445
- const search = `${import_picocolors14.default.gray(BAR)} Search: ${searchValue}`;
11446
- const help = `${import_picocolors14.default.gray(BAR)} ${import_picocolors14.default.dim("space: toggle doc type: search a: select all visible ←: back / Enter")}`;
11447
- const body = visibleOptions2(this.fileCursor, this.filteredFiles.length, MAX_VISIBLE_FILE_ITEMS).map((option) => {
11448
- if (option.kind === "ellipsis") {
11449
- return `${import_picocolors14.default.gray(BAR)} ${import_picocolors14.default.dim(ELLIPSIS)}`;
11450
- }
11451
- const file = this.filteredFiles[option.index];
11452
- const isActive = option.index === this.fileCursor;
11453
- const isSelected = this.selectedIds.has(file.id);
11454
- 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;
11455
- 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;
11456
- const hint = file.is_synced ? ` ${import_picocolors14.default.dim("(Already imported)")}` : "";
11457
- return `${import_picocolors14.default.gray(BAR)} ${marker} ${label}${hint}`;
11458
- });
11459
- const content = body.length > 0 ? body.join(`
11460
- `) : `${import_picocolors14.default.gray(BAR)} ${import_picocolors14.default.dim("No docs match your search.")}`;
11461
- return `${header}${back}
11462
- ${import_picocolors14.default.gray(BAR)}
11463
- ${search}
11464
- ${import_picocolors14.default.gray(BAR)}
11465
- ${content}
11466
- ${import_picocolors14.default.gray(BAR)}
11467
- ${help}
11468
- ${import_picocolors14.default.cyan(FOOTER)}`;
11469
- }
11470
- renderRepositoryMarker(state, isActive) {
11471
- if (state === "all") {
11472
- return isActive ? import_picocolors14.default.cyan(CHECKBOX_ON) : CHECKBOX_ON;
11473
- }
11474
- if (state === "partial") {
11475
- return isActive ? import_picocolors14.default.cyan(CHECKBOX_PARTIAL) : CHECKBOX_PARTIAL;
11476
- }
11477
- if (state === "locked") {
11478
- return isActive ? import_picocolors14.default.cyan(CHECKBOX_OFF) : import_picocolors14.default.dim(CHECKBOX_OFF);
11479
- }
11480
- return isActive ? import_picocolors14.default.cyan(CHECKBOX_OFF) : CHECKBOX_OFF;
11481
- }
11482
- submitLabel() {
11483
- const count = this.selectedIds.size;
11484
- if (count === 0) {
11485
- return "Skip for now";
11486
- }
11487
- return `${count} doc${count === 1 ? "" : "s"} selected`;
11488
- }
11489
- };
11490
- });
11491
-
11492
- // src/setup/github-doc-import-step.ts
11493
- var exports_github_doc_import_step = {};
11494
- __export(exports_github_doc_import_step, {
11495
- stepImportGitHubDocs: () => stepImportGitHubDocs
11496
- });
11497
- async function stepImportGitHubDocs(cfg, opts = {}) {
11498
- logger.info("setup", "Step: import GitHub docs");
11499
- if (!cfg.org_id || !cfg.space_id) {
11500
- log.warn("Cannot import GitHub docs: your Dosu workspace is missing org/space context. " + "Re-run `dosu setup` from a fresh state.");
11501
- return { advance: false };
11502
- }
11503
- const trpc = createTypedClient(cfg);
11504
- const files = opts.waitForFreshDocs ? await waitForImportableGithubFiles(trpc, cfg.org_id, cfg.space_id, opts.expectedDataSourceIds) : await fetchImportableGithubFiles(trpc, cfg.space_id);
11505
- if (files === null) {
11506
- return { advance: false };
11507
- }
11508
- if (files.length === 0) {
11509
- log.info("No markdown docs available to import right now. You can import them later.");
11510
- return { advance: true, imported: false, imported_count: 0 };
11511
- }
11512
- const repositories = buildRepositories(files);
11513
- const selected = await promptGitHubDocsImport({ repositories });
11514
- if (isCancel(selected)) {
11515
- logger.info("setup", "GitHub doc import selection cancelled");
11516
- return { advance: false };
11517
- }
11518
- const fileIDs = selected;
11519
- if (fileIDs.length === 0) {
11520
- log.info("Skipped importing docs for now. You can import them later.");
11521
- return { advance: true, imported: false, imported_count: 0 };
11522
- }
11523
- const knowledgeStoreID = await getKnowledgeStoreID(trpc, cfg.space_id);
11524
- if (!knowledgeStoreID) {
11525
- return { advance: false };
11526
- }
11527
- const spinner2 = spinner();
11528
- spinner2.start(`Queueing import for ${fileIDs.length} doc${fileIDs.length === 1 ? "" : "s"}...`);
11529
- try {
11530
- const result = await trpc.docImports.importGithubFiles.mutate({
11531
- knowledge_store_id: knowledgeStoreID,
11532
- space_id: cfg.space_id,
11533
- file_ids: fileIDs
11534
- });
11535
- const taskID = result?.task_id;
11536
- if (!taskID) {
11537
- spinner2.stop("Import task started");
11538
- log.success("Import task started.");
11539
- log.info("Your docs should finish importing in a few minutes.");
11540
- return { advance: true, imported: false, imported_count: 0, queued: true };
11541
- }
11542
- spinner2.stop("Import task started");
11543
- logger.info("setup", `Watching import task ${taskID}`);
11544
- log.info("This can take a few minutes. We'll keep watching until it finishes.");
11545
- const progressSpinner = spinner();
11546
- progressSpinner.start(`Preparing document import... 0/${fileIDs.length} complete`);
11547
- const finalStatus = await waitForImportTaskCompletion(trpc, taskID, progressSpinner, fileIDs.length);
11548
- if (!finalStatus) {
11549
- progressSpinner.stop("Stopped watching import progress");
11550
- log.info(`The import is still running in the background.
11551
- Check status later with: dosu docs import-status ${taskID}`);
11552
- return {
11553
- advance: true,
11554
- imported: false,
11555
- imported_count: 0,
11556
- queued: true,
11557
- task_id: taskID
11558
- };
11559
- }
11560
- handleImportCompletion(finalStatus, progressSpinner);
11561
- const importedCount = finalStatus.detail?.completed ?? 0;
11562
- return {
11563
- advance: true,
11564
- imported: importedCount > 0,
11565
- imported_count: importedCount,
11566
- failed_count: finalStatus.detail?.failed ?? 0,
11567
- task_id: taskID
11568
- };
11569
- } catch (err) {
11570
- spinner2.stop("Failed");
11571
- const msg = err instanceof Error ? err.message : String(err);
11572
- logger.error("setup", `Failed to import GitHub docs: ${msg}`);
11573
- log.error("Could not start the GitHub doc import.");
11574
- return { advance: false };
11575
- }
11576
- }
11577
- async function waitForImportTaskCompletion(trpc, taskID, spinner2, expectedTotal) {
11578
- let consecutiveErrors = 0;
11579
- while (true) {
11580
- try {
11581
- const status = await trpc.docImports.getImportStatus.query(taskID);
11582
- if (!status) {
11583
- consecutiveErrors += 1;
11584
- if (consecutiveErrors >= IMPORT_STATUS_MAX_ERRORS) {
11585
- return null;
11586
- }
11587
- } else {
11588
- consecutiveErrors = 0;
11589
- spinner2.message(buildImportProgressMessage(status, expectedTotal));
11590
- if (status.state !== "PROGRESS") {
11591
- return status;
11592
- }
11593
- }
11594
- } catch (err) {
11595
- consecutiveErrors += 1;
11596
- const msg = err instanceof Error ? err.message : String(err);
11597
- logger.warn("setup", `getImportStatus failed for ${taskID}: ${msg}`);
11598
- if (consecutiveErrors >= IMPORT_STATUS_MAX_ERRORS) {
11599
- return null;
11600
- }
11601
- }
11602
- await sleep5(IMPORT_STATUS_POLL_INTERVAL_MS);
11603
- }
11604
- }
11605
- function buildImportProgressMessage(status, expectedTotal) {
11606
- const detail = status.detail;
11607
- if (!detail) {
11608
- return `Importing documents... 0/${expectedTotal} complete`;
11609
- }
11610
- const processed = detail.completed + detail.failed;
11611
- const total = detail.total > 0 ? detail.total : expectedTotal;
11612
- if (status.state === "SUCCESS") {
11613
- return `Import complete (${processed}/${total})`;
11614
- }
11615
- if (status.state === "FAILURE") {
11616
- return `Import finished with issues (${processed}/${total}, ${detail.failed} failed)`;
11617
- }
11618
- const prefix = detail.message === "STARTING" ? "Preparing document import" : "Importing documents";
11619
- const failureSuffix = detail.failed > 0 ? `, ${detail.failed} failed` : "";
11620
- return `${prefix}... ${processed}/${total} complete${failureSuffix}`;
11621
- }
11622
- function handleImportCompletion(status, spinner2) {
11623
- const detail = status.detail;
11624
- const processed = detail ? detail.completed + detail.failed : 0;
11625
- const total = detail?.total ?? processed;
11626
- const failed = detail?.failed ?? 0;
11627
- if (status.state === "SUCCESS") {
11628
- spinner2.stop("Import complete");
11629
- log.success(`Imported ${total} doc${total === 1 ? "" : "s"}.
11630
- Your GitHub docs are ready, and onboarding is complete.`);
11631
- return;
11632
- }
11633
- spinner2.stop("Import completed with issues");
11634
- log.warn(`Imported ${processed - failed} of ${total} doc${total === 1 ? "" : "s"}; ${failed} failed.
11635
- You can review the failed docs later, but onboarding is complete.`);
11636
- }
11637
- async function waitForImportableGithubFiles(trpc, orgID, spaceID, expectedDataSourceIds) {
11638
- while (true) {
11639
- const spinner2 = spinner();
11640
- spinner2.start("Scanning repositories for markdown documents...");
11641
- log.info("This usually takes a few seconds.");
11642
- const startedAt = Date.now();
11643
- let latestFiles = [];
11644
- const waitsForExpectedDataSources = expectedDataSourceIds !== undefined && expectedDataSourceIds.length > 0;
11645
- while (Date.now() - startedAt < DOC_SCAN_POLL_TIMEOUT_MS) {
11646
- const dataSources = await fetchGitHubDataSources(trpc, orgID);
11647
- if (waitsForExpectedDataSources) {
11648
- if (isScanComplete(dataSources, expectedDataSourceIds)) {
11649
- latestFiles = await fetchImportableGithubFiles(trpc, spaceID);
11650
- spinner2.stop(latestFiles.length > 0 ? "Docs ready" : "No markdown docs found");
11651
- return latestFiles;
11652
- }
11653
- await sleep5(DOC_SCAN_POLL_INTERVAL_MS);
11654
- continue;
11655
- }
11656
- latestFiles = await fetchImportableGithubFiles(trpc, spaceID);
11657
- if (latestFiles.length > 0) {
11658
- spinner2.stop("Docs ready");
11659
- return latestFiles;
11660
- }
11661
- if (isScanComplete(dataSources, expectedDataSourceIds)) {
11662
- spinner2.stop("No markdown docs found");
11663
- return [];
11664
- }
11665
- await sleep5(DOC_SCAN_POLL_INTERVAL_MS);
11666
- }
11667
- spinner2.stop("Timed out");
11668
- const choice = await select({
11669
- message: "Still waiting for GitHub docs to become available",
11670
- options: [
11671
- { value: "retry", label: "Retry" },
11672
- { value: "skip", label: "Skip for now" }
11673
- ]
11674
- });
11675
- if (isCancel(choice)) {
11676
- return null;
11677
- }
11678
- if (choice === "skip") {
11679
- log.info("Skipped importing docs for now. You can import them later.");
11680
- return [];
11681
- }
11682
- }
11683
- }
11684
- function isScanComplete(dataSources, expectedDataSourceIds) {
11685
- if (expectedDataSourceIds && expectedDataSourceIds.length > 0) {
11686
- const byId = new Map;
11687
- for (const ds of dataSources) {
11688
- if (ds.data_source_id)
11689
- byId.set(ds.data_source_id, ds);
11690
- }
11691
- for (const id of expectedDataSourceIds) {
11692
- const ds = byId.get(id);
11693
- if (!ds)
11694
- continue;
11695
- if (ds.is_indexed !== true)
11696
- return false;
11697
- }
11698
- return true;
11699
- }
11700
- return dataSources.length > 0 && dataSources.every((ds) => ds.is_indexed === true);
11701
- }
11702
- async function fetchGitHubDataSources(trpc, orgID) {
11703
- try {
11704
- const dataSources = await trpc.dataSource.list.query({
11705
- org_id: orgID,
11706
- excluded_provider_slugs: []
11707
- });
11708
- return dataSources.filter((dataSource) => dataSource.provider_slug === "github");
11709
- } catch (err) {
11710
- const msg = err instanceof Error ? err.message : String(err);
11711
- logger.warn("setup", `dataSource.list failed while waiting for docs: ${msg}`);
11712
- return [];
11713
- }
11714
- }
11715
- async function fetchImportableGithubFiles(trpc, spaceID) {
11716
- try {
11717
- return await trpc.docImports.listImportableGithubFiles.query(spaceID);
11718
- } catch (err) {
11719
- const msg = err instanceof Error ? err.message : String(err);
11720
- logger.warn("setup", `listImportableGithubFiles failed: ${msg}`);
11721
- return [];
11722
- }
11723
- }
11724
- function buildRepositories(files) {
11725
- const repositories = new Map;
11726
- for (const file of files) {
11727
- const slug = file.repository_slug ?? "unknown";
11728
- if (!repositories.has(slug)) {
11729
- repositories.set(slug, { slug, files: [] });
11730
- }
11731
- repositories.get(slug)?.files.push({
11732
- id: file.id,
11733
- path: file.file_path,
11734
- is_synced: file.is_synced
11735
- });
11736
- }
11737
- return Array.from(repositories.values()).map((repository) => ({
11738
- ...repository,
11739
- files: [...repository.files].sort((a3, b2) => a3.path.localeCompare(b2.path))
11740
- })).sort((a3, b2) => a3.slug.localeCompare(b2.slug));
11741
- }
11742
- async function getKnowledgeStoreID(trpc, spaceID) {
11743
- try {
11744
- const store = await trpc.knowledgeStore.getBySpaceId.query({
11745
- space_id: spaceID
11746
- });
11747
- if (!store?.id) {
11748
- log.error("No knowledge store found for this deployment.");
11749
- return null;
11750
- }
11751
- return store.id;
11752
- } catch (err) {
11753
- const msg = err instanceof Error ? err.message : String(err);
11754
- logger.error("setup", `knowledgeStore.getBySpaceId failed: ${msg}`);
11755
- log.error("Could not load the knowledge store for this deployment.");
11756
- return null;
11757
- }
11758
- }
11759
- function sleep5(ms) {
11760
- return new Promise((resolve) => setTimeout(resolve, ms));
11761
- }
11762
- var DOC_SCAN_POLL_INTERVAL_MS = 2000, DOC_SCAN_POLL_TIMEOUT_MS = 60000, IMPORT_STATUS_POLL_INTERVAL_MS = 2000, IMPORT_STATUS_MAX_ERRORS = 3;
11763
- var init_github_doc_import_step = __esm(() => {
11764
- init_dist8();
11765
- init_trpc();
11766
- init_logger();
11767
- init_github_doc_import_prompt();
11768
- });
11769
-
11770
11137
  // src/auth/errors.ts
11771
11138
  var exports_errors = {};
11772
11139
  __export(exports_errors, {
@@ -11846,14 +11213,53 @@ code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; background:
11846
11213
  </body>
11847
11214
  </html>`;
11848
11215
  }
11849
- 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;
11850
11256
  const emailLine = email ? `<p class="email">Signed in as <strong>${email.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")}</strong></p>` : "";
11851
11257
  return `<!DOCTYPE html>
11852
11258
  <html lang="en">
11853
11259
  <head>
11854
11260
  <meta charset="UTF-8">
11855
11261
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
11856
- <title>Dosu CLI - Authentication Successful</title>
11262
+ <title>${copy2.title}</title>
11857
11263
  <style>
11858
11264
  * { margin: 0; padding: 0; box-sizing: border-box; }
11859
11265
  body {
@@ -11955,31 +11361,47 @@ h1 {
11955
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"/>
11956
11362
  </svg>
11957
11363
  </div>
11958
- <h1>Authentication Successful</h1>
11364
+ <h1 id="heading">${copy2.heading}</h1>
11959
11365
  ${emailLine}
11960
- <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>
11961
11367
  </div>
11962
11368
  <div class="tip">
11963
11369
  <div class="tip-rule" aria-hidden="true"><span class="tip-dot"></span></div>
11964
11370
  <span class="tip-label">Did you know?</span>
11965
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.
11966
11372
  </div>
11373
+ ${withNextPoll ? buildNextPollScript(copy2.close) : ""}
11967
11374
  </body>
11968
11375
  </html>`;
11969
11376
  }
11970
- async function startCallbackServer() {
11377
+ async function startCallbackServer(opts = {}) {
11971
11378
  let resolveToken;
11972
11379
  let rejectToken;
11973
11380
  const tokenPromise = new Promise((resolve, reject) => {
11974
11381
  resolveToken = resolve;
11975
11382
  rejectToken = reject;
11976
11383
  });
11384
+ let nextTarget;
11977
11385
  const http = __require("node:http");
11978
11386
  const httpServer = http.createServer((req, res) => {
11979
11387
  const url = new URL(req.url ?? "/", `http://localhost`);
11980
11388
  const cookieLen = (req.headers.cookie ?? "").length;
11981
11389
  const ua = req.headers["user-agent"] ?? "none";
11982
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
+ }
11983
11405
  if (url.pathname !== "/callback") {
11984
11406
  logger.debug("auth.server", `404: ${url.pathname}`);
11985
11407
  res.writeHead(404, { "Content-Type": "text/plain" });
@@ -12027,17 +11449,24 @@ async function startCallbackServer() {
12027
11449
  });
12028
11450
  logger.info("auth.server", "Served success HTML");
12029
11451
  res.writeHead(200, { "Content-Type": "text/html" });
12030
- res.end(buildSuccessHtml(email ?? undefined));
11452
+ res.end(buildSuccessHtml(email ?? undefined, opts.successVariant ?? "auth", Boolean(opts.nextHold)));
12031
11453
  });
12032
11454
  await new Promise((resolve) => {
12033
11455
  httpServer.listen(0, "localhost", () => resolve());
12034
11456
  });
11457
+ httpServer.unref();
12035
11458
  const addr = httpServer.address();
12036
11459
  logger.info("auth.server", `Callback server listening on port ${addr.port}`);
12037
11460
  return {
12038
11461
  server: {
12039
11462
  port: addr.port,
12040
- close: () => httpServer.close()
11463
+ close: () => {
11464
+ httpServer.close();
11465
+ httpServer.closeAllConnections?.();
11466
+ },
11467
+ setNext: (url) => {
11468
+ nextTarget = url;
11469
+ }
12041
11470
  },
12042
11471
  tokenPromise
12043
11472
  };
@@ -12106,10 +11535,22 @@ if (hash) {
12106
11535
  }
12107
11536
  </script>
12108
11537
  </body>
12109
- </html>`;
11538
+ </html>`, SUCCESS_COPY;
12110
11539
  var init_server = __esm(() => {
12111
11540
  init_logger();
12112
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
+ };
12113
11554
  });
12114
11555
 
12115
11556
  // src/auth/flow.ts
@@ -12117,25 +11558,35 @@ var exports_flow = {};
12117
11558
  __export(exports_flow, {
12118
11559
  startOAuthFlow: () => startOAuthFlow
12119
11560
  });
12120
- async function startOAuthFlow(signal, path3 = "/cli/auth", params = {}, onAuthURL) {
12121
- 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
+ });
12122
11566
  let timeoutId;
11567
+ let handedOver = false;
12123
11568
  try {
12124
11569
  const callbackURL = `http://localhost:${server.port}/callback`;
12125
11570
  logger.debug("auth.flow", `Callback URL: ${callbackURL}`);
12126
11571
  const authURL = buildAuthURL(callbackURL, path3, params);
12127
11572
  logger.info("auth.flow", `Auth URL: ${authURL}`);
12128
- const open2 = await Promise.resolve().then(() => (init_open(), exports_open));
11573
+ options.onAuthURL?.(authURL);
12129
11574
  let browserOpened = false;
12130
- try {
12131
- await open2.default(authURL);
11575
+ if (options.suppressBrowserOpen) {
12132
11576
  browserOpened = true;
12133
- logger.info("auth.flow", "Browser open command executed");
12134
- onAuthURL?.(authURL);
12135
- } catch (openErr) {
12136
- 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
+ }
12137
11588
  }
12138
- if (!browserOpened) {
11589
+ if (!browserOpened && !options.waitWithoutBrowser) {
12139
11590
  logger.debug("auth.flow", "Browser unavailable — returning to caller for fallback");
12140
11591
  return { browserOpened: false };
12141
11592
  }
@@ -12153,11 +11604,17 @@ async function startOAuthFlow(signal, path3 = "/cli/auth", params = {}, onAuthUR
12153
11604
  }) : new Promise(() => {});
12154
11605
  const token = await Promise.race([tokenPromise, timeout, abort]);
12155
11606
  logger.info("auth.flow", "Token received");
11607
+ if (options.holdNext) {
11608
+ handedOver = true;
11609
+ return { browserOpened: true, token, server };
11610
+ }
12156
11611
  return { browserOpened: true, token };
12157
11612
  } finally {
12158
11613
  clearTimeout(timeoutId);
12159
- server.close();
12160
- 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
+ }
12161
11618
  }
12162
11619
  }
12163
11620
  function buildAuthURL(callbackURL, path3, extraParams) {
@@ -12176,14 +11633,11 @@ __export(exports_flow2, {
12176
11633
  stepShowSummary: () => stepShowSummary,
12177
11634
  stepDetectTools: () => stepDetectTools,
12178
11635
  stepConfigureTools: () => stepConfigureTools,
12179
- showTryItOutPrompt: () => showTryItOutPrompt,
12180
11636
  runSetup: () => runSetup,
12181
11637
  runInstallSkill: () => runInstallSkill,
12182
11638
  isStdioOnly: () => isStdioOnly
12183
11639
  });
12184
11640
  import { randomUUID } from "node:crypto";
12185
- import { existsSync as existsSync16 } from "node:fs";
12186
- import { join as join26 } from "node:path";
12187
11641
  async function runSetup(opts = {}) {
12188
11642
  const onboardingRunID = randomUUID();
12189
11643
  logger.info("setup", `Setup flow started${opts.deploymentID ? ` deployment=${opts.deploymentID}` : ""}${opts.mode ? ` mode=${opts.mode}` : ""}`);
@@ -12198,10 +11652,15 @@ async function runSetup(opts = {}) {
12198
11652
  cfg.mode = undefined;
12199
11653
  saveConfig(cfg);
12200
11654
  }
12201
- const authedCfg = await stepAuthenticate(cfg, onboardingRunID);
12202
- if (!authedCfg)
11655
+ const authed = await stepAuthenticate(cfg, onboardingRunID);
11656
+ if (!authed)
12203
11657
  return;
12204
- cfg = authedCfg;
11658
+ cfg = authed.cfg;
11659
+ const authTab = authed.authTab;
11660
+ const releaseAuthTab = () => {
11661
+ authTab?.setNext(null);
11662
+ authTab?.close();
11663
+ };
12205
11664
  await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_auth_completed");
12206
11665
  const apiClient = new Client(cfg);
12207
11666
  let cloudSetupContext = null;
@@ -12214,6 +11673,7 @@ async function runSetup(opts = {}) {
12214
11673
  reason: "cloud_setup_context_failed"
12215
11674
  });
12216
11675
  s.stop("Workspace load failed");
11676
+ releaseAuthTab();
12217
11677
  return;
12218
11678
  }
12219
11679
  s.stop("Workspace loaded");
@@ -12221,7 +11681,18 @@ async function runSetup(opts = {}) {
12221
11681
  await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_started", {
12222
11682
  flow_kind: cloudSetupContext?.kind ?? "oss"
12223
11683
  });
12224
- 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
+ }
12225
11696
  const ok = await bindOnboardingDeployment(apiClient, cfg, cloudSetupContext.targetOrg ?? null);
12226
11697
  if (!ok) {
12227
11698
  await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_failed", {
@@ -12247,9 +11718,7 @@ async function runSetup(opts = {}) {
12247
11718
  }
12248
11719
  cfg.api_key = apiKey;
12249
11720
  saveConfig(cfg);
12250
- const choices = await stepOneShotConfirm({
12251
- includeGitHub: cloudSetupContext?.kind === "onboarding"
12252
- });
11721
+ const choices = await stepOneShotConfirm();
12253
11722
  if (!choices) {
12254
11723
  await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_cancelled", {
12255
11724
  reason: "options_cancelled"
@@ -12258,13 +11727,11 @@ async function runSetup(opts = {}) {
12258
11727
  }
12259
11728
  await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_options_selected", {
12260
11729
  configure_mcp: choices.configureMcp,
12261
- install_skill: choices.installSkill,
12262
- connect_github: choices.connectGitHub
11730
+ install_skill: choices.installSkill
12263
11731
  });
12264
11732
  let mcpConfiguredThisRun = false;
12265
11733
  let mcpCompleted = false;
12266
11734
  let skillCompleted = false;
12267
- let docsImported = false;
12268
11735
  if (choices.configureMcp) {
12269
11736
  const configured = await stepConfigureMcpTools(cfg);
12270
11737
  if (configured === null) {
@@ -12289,84 +11756,14 @@ async function runSetup(opts = {}) {
12289
11756
  await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_skill_installed");
12290
11757
  }
12291
11758
  }
12292
- let githubOnboardingDone = !choices.connectGitHub;
12293
- if (choices.connectGitHub && cloudSetupContext?.kind === "onboarding") {
12294
- const { stepConnectGitHubRepo: stepConnectGitHubRepo2 } = await Promise.resolve().then(() => (init_github_step(), exports_github_step));
12295
- const connectResult = await stepConnectGitHubRepo2(cfg);
12296
- if (!connectResult.advance) {
12297
- await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_cancelled", {
12298
- reason: "github_connect_not_advanced",
12299
- has_connected_repo: connectResult.has_connected_repo
12300
- });
12301
- return;
12302
- }
12303
- if (connectResult.has_connected_repo || (connectResult.created_data_source_ids?.length ?? 0) > 0) {
12304
- await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_github_connected", {
12305
- created_data_source_count: connectResult.created_data_source_ids?.length ?? 0,
12306
- created_repository_slugs: connectResult.created_repository_slugs
12307
- });
12308
- }
12309
- if (connectResult.space_id && !cfg.space_id) {
12310
- cfg.space_id = connectResult.space_id;
12311
- saveConfig(cfg);
12312
- }
12313
- const { stepImportGitHubDocs: stepImportGitHubDocs2 } = await Promise.resolve().then(() => (init_github_doc_import_step(), exports_github_doc_import_step));
12314
- const importResult = await stepImportGitHubDocs2(cfg, {
12315
- waitForFreshDocs: Boolean(connectResult.deployment_id),
12316
- expectedDataSourceIds: connectResult.created_data_source_ids
12317
- });
12318
- if (!importResult.advance) {
12319
- await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_failed", {
12320
- reason: "github_docs_import_failed"
12321
- });
12322
- return;
12323
- }
12324
- docsImported = importResult.imported === true && (importResult.imported_count ?? 0) > 0;
12325
- if (docsImported) {
12326
- await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_docs_imported", {
12327
- imported_count: importResult.imported_count ?? 0,
12328
- failed_count: importResult.failed_count ?? 0,
12329
- task_id: importResult.task_id
12330
- });
12331
- await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_activated", {
12332
- imported_count: importResult.imported_count ?? 0,
12333
- failed_count: importResult.failed_count ?? 0
12334
- });
12335
- }
12336
- githubOnboardingDone = true;
12337
- }
12338
- const shouldCompleteRemoteOnboarding = cloudSetupContext?.kind === "onboarding" && githubOnboardingDone;
12339
- if (shouldCompleteRemoteOnboarding && cloudSetupContext) {
12340
- const profileUserID = cloudSetupContext.profileUserID;
12341
- try {
12342
- const { createTypedClient: createTypedClient2 } = await Promise.resolve().then(() => (init_trpc(), exports_trpc));
12343
- const trpc = createTypedClient2(cfg);
12344
- await trpc.user.updateProfile.mutate({
12345
- user_id: profileUserID,
12346
- finished_onboarding: true
12347
- });
12348
- logger.info("setup", "Server onboarding marked complete");
12349
- } catch (err) {
12350
- logger.warn("setup", `completeOnboarding failed: ${err instanceof Error ? err.message : String(err)}`);
12351
- log.warn("Could not mark onboarding complete on the server — you can retry later by running `dosu setup` again.");
12352
- }
12353
- }
12354
11759
  let handoffToAudit = false;
12355
- if (mcpConfiguredThisRun) {
12356
- showTryItOutPrompt({
12357
- mode: cfg.mode,
12358
- docsImported: choices.connectGitHub && githubOnboardingDone,
12359
- hasAgentsMd: existsSync16(join26(process.cwd(), "AGENTS.md"))
12360
- });
12361
- if (cfg.mode !== MODE_OSS) {
12362
- handoffToAudit = await offerAuditHandoff();
12363
- }
11760
+ if (mcpConfiguredThisRun && cfg.mode !== MODE_OSS) {
11761
+ handoffToAudit = await offerAuditHandoff();
12364
11762
  }
12365
- if (mcpCompleted || skillCompleted || docsImported) {
11763
+ if (mcpCompleted || skillCompleted) {
12366
11764
  await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_completed", {
12367
11765
  completed_mcp: mcpCompleted,
12368
- completed_skill: skillCompleted,
12369
- imported_docs: docsImported
11766
+ completed_skill: skillCompleted
12370
11767
  });
12371
11768
  }
12372
11769
  if (cfg.mode === MODE_OSS) {
@@ -12395,17 +11792,11 @@ function applyModeOverride(cfg, opts) {
12395
11792
  }
12396
11793
  saveConfig(cfg);
12397
11794
  }
12398
- async function stepOneShotConfirm(opts) {
11795
+ async function stepOneShotConfirm() {
12399
11796
  const items = [
12400
11797
  { value: "configureMcp", label: "Install Dosu MCP" },
12401
11798
  { value: "installSkill", label: "Install Dosu skill" }
12402
11799
  ];
12403
- if (opts.includeGitHub) {
12404
- items.push({
12405
- value: "connectGitHub",
12406
- label: `Import docs from GitHub ${dim("(Keep them up to date)")}`
12407
- });
12408
- }
12409
11800
  const selected = await multiselect({
12410
11801
  message: "Dosu will set these up — press Enter to accept, space to toggle",
12411
11802
  options: items.map((it) => ({ value: it.value, label: it.label })),
@@ -12419,8 +11810,7 @@ async function stepOneShotConfirm(opts) {
12419
11810
  const chosen = new Set(selected);
12420
11811
  return {
12421
11812
  configureMcp: chosen.has("configureMcp"),
12422
- installSkill: chosen.has("installSkill"),
12423
- connectGitHub: chosen.has("connectGitHub")
11813
+ installSkill: chosen.has("installSkill")
12424
11814
  };
12425
11815
  }
12426
11816
  async function stepConfigureMcpTools(cfg) {
@@ -12467,7 +11857,7 @@ async function stepAuthenticate(existingCfg, onboardingRunID) {
12467
11857
  if (resp.status === 200) {
12468
11858
  logger.info("setup", `Session verified, status=${resp.status}`);
12469
11859
  s.stop("Authenticated");
12470
- return cfg;
11860
+ return { cfg };
12471
11861
  }
12472
11862
  try {
12473
11863
  logger.debug("setup", "Attempting token refresh");
@@ -12475,7 +11865,7 @@ async function stepAuthenticate(existingCfg, onboardingRunID) {
12475
11865
  const resp2 = await apiClient.doRequestRaw("GET", "/v1/mcp/deployments");
12476
11866
  if (resp2.status === 200) {
12477
11867
  s.stop("Authenticated");
12478
- return cfg;
11868
+ return { cfg };
12479
11869
  }
12480
11870
  } catch {}
12481
11871
  s.stop("Session expired");
@@ -12485,15 +11875,6 @@ async function stepAuthenticate(existingCfg, onboardingRunID) {
12485
11875
  s.stop("Session verification failed");
12486
11876
  }
12487
11877
  }
12488
- const shouldLogin = await confirm({ message: "Open browser to log in?" });
12489
- if (isCancel(shouldLogin) || !shouldLogin) {
12490
- if (onboardingRunID) {
12491
- await trackCliOnboardingPreAuthEvent(onboardingRunID, "cli_onboarding_auth_cancelled", {
12492
- reason: isCancel(shouldLogin) ? "prompt_cancelled" : "login_declined"
12493
- });
12494
- }
12495
- return null;
12496
- }
12497
11878
  if (onboardingRunID) {
12498
11879
  await trackCliOnboardingPreAuthEvent(onboardingRunID, "cli_onboarding_auth_started");
12499
11880
  }
@@ -12503,13 +11884,16 @@ async function openBrowserForSetup(cfg, onboardingRunID) {
12503
11884
  try {
12504
11885
  const { startOAuthFlow: startOAuthFlow2 } = await Promise.resolve().then(() => (init_flow(), exports_flow));
12505
11886
  const s = spinner();
12506
- const result = await startOAuthFlow2(undefined, "/cli/auth", onboardingRunID ? { onboarding_run_id: onboardingRunID } : {}, (url) => {
12507
- log.message(browserFallbackHint(url));
12508
- s.start("Waiting for authentication...");
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
+ }
12509
11894
  });
12510
11895
  if (!result.browserOpened) {
12511
11896
  s.stop("Could not open a browser");
12512
- log.error("Run 'dosu login --no-browser' from the terminal to authenticate over SSH.");
12513
11897
  return null;
12514
11898
  }
12515
11899
  const token = result.token;
@@ -12519,7 +11903,7 @@ async function openBrowserForSetup(cfg, onboardingRunID) {
12519
11903
  cfg.refresh_token = token.refresh_token;
12520
11904
  cfg.expires_at = Math.floor(Date.now() / 1000) + token.expires_in;
12521
11905
  saveConfig(cfg);
12522
- return cfg;
11906
+ return { cfg, authTab: result.server };
12523
11907
  } catch (err) {
12524
11908
  const msg = err instanceof Error ? err.stack ?? err.message : String(err);
12525
11909
  logger.error("setup", `Auth failed: ${msg}`);
@@ -12542,6 +11926,43 @@ async function openBrowserForSetup(cfg, onboardingRunID) {
12542
11926
  return null;
12543
11927
  }
12544
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
+ }
12545
11966
  async function resolveCloudSetupContext(cfg) {
12546
11967
  try {
12547
11968
  const { createTypedClient: createTypedClient2 } = await Promise.resolve().then(() => (init_trpc(), exports_trpc));
@@ -12551,7 +11972,7 @@ async function resolveCloudSetupContext(cfg) {
12551
11972
  log.error("Could not load your profile.");
12552
11973
  return null;
12553
11974
  }
12554
- if (profile.finished_onboarding === true || profile.cli_onboarding_enabled !== true) {
11975
+ if (profile.finished_onboarding === true) {
12555
11976
  return {
12556
11977
  kind: "setup",
12557
11978
  profileUserID: profile.user_id
@@ -12835,23 +12256,6 @@ ${lines}`);
12835
12256
  log.success("All agents already configured. No changes needed.");
12836
12257
  }
12837
12258
  }
12838
- function showTryItOutPrompt(opts = {}) {
12839
- const prompt = (() => {
12840
- if (opts.mode === MODE_OSS) {
12841
- return `What can Dosu help me with? Pick an open source library related to my project and explain how it works.`;
12842
- }
12843
- if (opts.docsImported) {
12844
- return `Use Dosu to summarize the most important docs in my repo.`;
12845
- }
12846
- if (opts.hasAgentsMd) {
12847
- return `Please use Dosu to host my AGENTS.md`;
12848
- }
12849
- return `Ask Dosu to draft an AGENTS.md for this project.`;
12850
- })();
12851
- log.message(`Try it out! Paste this into your agent:
12852
-
12853
- ${info(prompt)}`);
12854
- }
12855
12259
  var init_flow2 = __esm(() => {
12856
12260
  init_dist8();
12857
12261
  init_client();
@@ -12865,8 +12269,8 @@ var init_flow2 = __esm(() => {
12865
12269
  });
12866
12270
 
12867
12271
  // src/commands/insights.ts
12868
- import { existsSync as existsSync17, mkdirSync as mkdirSync8, readdirSync, unlinkSync, writeFileSync as writeFileSync7 } from "node:fs";
12869
- 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";
12870
12274
  function shuffled(arr) {
12871
12275
  const copy2 = [...arr];
12872
12276
  for (let i2 = copy2.length - 1;i2 > 0; i2--) {
@@ -12881,7 +12285,7 @@ function createDotsSpinner() {
12881
12285
  let current = "";
12882
12286
  const isTTY = Boolean(process.stdout.isTTY) && process.env.CI !== "true";
12883
12287
  const draw = () => {
12884
- 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}`);
12885
12289
  frameIdx = (frameIdx + 1) % SPINNER_FRAMES.length;
12886
12290
  };
12887
12291
  return {
@@ -12903,7 +12307,7 @@ function createDotsSpinner() {
12903
12307
  clearInterval(timer);
12904
12308
  timer = undefined;
12905
12309
  }
12906
- 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("✗");
12907
12311
  if (isTTY) {
12908
12312
  process.stdout.write(`\r\x1B[2K${symbol3} ${msg}
12909
12313
  `);
@@ -12970,17 +12374,17 @@ function makeAskFn(cfg) {
12970
12374
  };
12971
12375
  }
12972
12376
  function insightsDir() {
12973
- return join27(getConfigDir(), "insights");
12377
+ return join26(getConfigDir(), "insights");
12974
12378
  }
12975
12379
  function reportPath(timestamp) {
12976
12380
  const dir = insightsDir();
12977
12381
  if (!timestamp)
12978
- return join27(dir, "latest.html");
12382
+ return join26(dir, "latest.html");
12979
12383
  const iso = timestamp.toISOString().slice(0, 19).replace(/:/g, "-");
12980
- return join27(dir, `report-${iso}Z.html`);
12384
+ return join26(dir, `report-${iso}Z.html`);
12981
12385
  }
12982
12386
  function pruneOldReports(dir, keepN) {
12983
- if (!existsSync17(dir))
12387
+ if (!existsSync16(dir))
12984
12388
  return;
12985
12389
  let entries;
12986
12390
  try {
@@ -12992,7 +12396,7 @@ function pruneOldReports(dir, keepN) {
12992
12396
  const reports = entries.filter((f2) => REPORT_FILE_PATTERN.test(f2)).sort().reverse();
12993
12397
  for (const f2 of reports.slice(keepN)) {
12994
12398
  try {
12995
- unlinkSync(join27(dir, f2));
12399
+ unlinkSync(join26(dir, f2));
12996
12400
  } catch (err) {
12997
12401
  logger.debug("insights", `failed to prune ${f2}: ${err instanceof Error ? err.message : err}`);
12998
12402
  }
@@ -13044,18 +12448,18 @@ async function runInsights(cfg, runner) {
13044
12448
  runner.writeFile(latestPath, html);
13045
12449
  runner.prune(insightsDir(), KEEP_REPORTS);
13046
12450
  console.log("");
13047
- 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}`));
13048
12452
  if (report.cheers[0]) {
13049
- console.log(import_picocolors15.default.green(` ${report.cheers[0]}`));
12453
+ console.log(import_picocolors14.default.green(` ${report.cheers[0]}`));
13050
12454
  }
13051
12455
  console.log("");
13052
- console.log(` Snapshot: ${import_picocolors15.default.cyan(`file://${snapshotPath}`)}`);
13053
- console.log(` Latest: ${import_picocolors15.default.cyan(`file://${latestPath}`)}`);
13054
- 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..."));
13055
12459
  try {
13056
12460
  await runner.openInBrowser(snapshotPath);
13057
12461
  } catch {
13058
- 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.)"));
13059
12463
  }
13060
12464
  return snapshotPath;
13061
12465
  }
@@ -13065,7 +12469,7 @@ function defaultRunner(cfg) {
13065
12469
  render: renderHTML,
13066
12470
  writeFile: (path3, content) => {
13067
12471
  const dir = dirname5(path3);
13068
- if (!existsSync17(dir))
12472
+ if (!existsSync16(dir))
13069
12473
  mkdirSync8(dir, { recursive: true, mode: 448 });
13070
12474
  writeFileSync7(path3, content, { mode: 384 });
13071
12475
  },
@@ -13082,7 +12486,7 @@ async function executeInsights(cfg) {
13082
12486
  try {
13083
12487
  await runInsights(cfg, defaultRunner(cfg));
13084
12488
  } catch (err) {
13085
- 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)}`));
13086
12490
  }
13087
12491
  }
13088
12492
  function insightsCommand() {
@@ -13093,12 +12497,12 @@ function insightsCommand() {
13093
12497
  try {
13094
12498
  await runInsights(cfg, defaultRunner(cfg));
13095
12499
  } catch (err) {
13096
- 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)}`));
13097
12501
  process.exit(1);
13098
12502
  }
13099
12503
  });
13100
12504
  }
13101
- 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;
13102
12506
  var init_insights3 = __esm(() => {
13103
12507
  init_dist8();
13104
12508
  init_commander();
@@ -13107,7 +12511,7 @@ var init_insights3 = __esm(() => {
13107
12511
  init_logger();
13108
12512
  init_insights2();
13109
12513
  init_flow2();
13110
- import_picocolors15 = __toESM(require_picocolors(), 1);
12514
+ import_picocolors14 = __toESM(require_picocolors(), 1);
13111
12515
  REPORT_FILE_PATTERN = /^report-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}Z\.html$/;
13112
12516
  NARRATIVE_HINTS = [
13113
12517
  "Reading your reactions and confidence levels",
@@ -13136,7 +12540,7 @@ __export(exports_tui, {
13136
12540
  handleLogout: () => handleLogout
13137
12541
  });
13138
12542
  async function runTUI() {
13139
- console.log(import_picocolors26.default.magenta(LOGO));
12543
+ console.log(import_picocolors25.default.magenta(LOGO));
13140
12544
  const cfg = loadConfig();
13141
12545
  while (true) {
13142
12546
  const insightsReady = Boolean(cfg.space_id && cfg.deployment_id && cfg.api_key);
@@ -13250,7 +12654,7 @@ function handleLogout(cfg) {
13250
12654
  saveConfig(cfg);
13251
12655
  log.success("Credentials cleared.");
13252
12656
  }
13253
- var import_picocolors26, LOGO = `
12657
+ var import_picocolors25, LOGO = `
13254
12658
  /$$$$$$$
13255
12659
  | $$__ $$
13256
12660
  | $$ \\ $$ /$$$$$$ /$$$$$$$ /$$ /$$
@@ -13267,7 +12671,7 @@ var init_tui = __esm(() => {
13267
12671
  init_config();
13268
12672
  init_flow2();
13269
12673
  init_styles();
13270
- import_picocolors26 = __toESM(require_picocolors(), 1);
12674
+ import_picocolors25 = __toESM(require_picocolors(), 1);
13271
12675
  });
13272
12676
 
13273
12677
  // src/auth/ticket.ts
@@ -13471,7 +12875,7 @@ Could not open a browser automatically.`);
13471
12875
  while (Date.now() < deadline) {
13472
12876
  if (signal?.aborted)
13473
12877
  throw new Error("authentication cancelled");
13474
- await sleep6(POLL_INTERVAL_MS);
12878
+ await sleep5(POLL_INTERVAL_MS);
13475
12879
  if (signal?.aborted)
13476
12880
  throw new Error("authentication cancelled");
13477
12881
  const result = await exchangeTicket(minted.ticket);
@@ -13488,7 +12892,7 @@ Could not open a browser automatically.`);
13488
12892
  }
13489
12893
  throw new Error("Authentication timed out. Run 'dosu login' to try again.");
13490
12894
  }
13491
- function sleep6(ms) {
12895
+ function sleep5(ms) {
13492
12896
  return new Promise((resolve) => setTimeout(resolve, ms));
13493
12897
  }
13494
12898
  var POLL_INTERVAL_MS = 5000;
@@ -15516,11 +14920,11 @@ init_insights3();
15516
14920
  // src/commands/integrations.ts
15517
14921
  init_commander();
15518
14922
  init_trpc();
15519
- var import_picocolors16 = __toESM(require_picocolors(), 1);
14923
+ var import_picocolors15 = __toESM(require_picocolors(), 1);
15520
14924
  function requireConfig6() {
15521
14925
  const cfg = requireLoginConfig();
15522
14926
  if (!cfg.org_id) {
15523
- 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."));
15524
14928
  process.exit(1);
15525
14929
  }
15526
14930
  return cfg;
@@ -15571,7 +14975,7 @@ function integrationsCommand() {
15571
14975
  }
15572
14976
  printTable(["Platform", "Status"], results.map((r2) => [
15573
14977
  r2.platform,
15574
- 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")
15575
14979
  ]), { rawData: results });
15576
14980
  });
15577
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) => {
@@ -15583,7 +14987,7 @@ function integrationsCommand() {
15583
14987
  printResult({ platform: platform4, connected: false, note: "not queryable via nango" }, opts);
15584
14988
  return;
15585
14989
  }
15586
- console.log(`${platform4}: ${import_picocolors16.default.dim("not connected (not queryable)")}`);
14990
+ console.log(`${platform4}: ${import_picocolors15.default.dim("not connected (not queryable)")}`);
15587
14991
  return;
15588
14992
  }
15589
14993
  try {
@@ -15597,13 +15001,13 @@ function integrationsCommand() {
15597
15001
  printResult({ platform: platform4, connected, connection: conn }, opts);
15598
15002
  return;
15599
15003
  }
15600
- 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")}`);
15601
15005
  } catch {
15602
15006
  if (opts.json) {
15603
15007
  printResult({ platform: platform4, connected: false }, opts);
15604
15008
  return;
15605
15009
  }
15606
- console.log(`${platform4}: ${import_picocolors16.default.dim("not connected")}`);
15010
+ console.log(`${platform4}: ${import_picocolors15.default.dim("not connected")}`);
15607
15011
  }
15608
15012
  });
15609
15013
  cmd.command("slack-channels").description("List Slack channels").option("--json", "Output as JSON").action(async (opts) => {
@@ -15615,7 +15019,7 @@ function integrationsCommand() {
15615
15019
  return;
15616
15020
  }
15617
15021
  if (!channels || channels.length === 0) {
15618
- console.log(import_picocolors16.default.dim("No Slack channels found."));
15022
+ console.log(import_picocolors15.default.dim("No Slack channels found."));
15619
15023
  return;
15620
15024
  }
15621
15025
  printTable(["ID", "Name"], channels.map((c3) => [
@@ -15631,7 +15035,7 @@ function integrationsCommand() {
15631
15035
  printResult({ success: true, channelId }, opts);
15632
15036
  return;
15633
15037
  }
15634
- console.log(import_picocolors16.default.green(`Joined Slack channel ${channelId}.`));
15038
+ console.log(import_picocolors15.default.green(`Joined Slack channel ${channelId}.`));
15635
15039
  });
15636
15040
  cmd.command("github-collaborators").description("List GitHub repository collaborators").option("--json", "Output as JSON").action(async (opts) => {
15637
15041
  const cfg = requireConfig6();
@@ -15642,7 +15046,7 @@ function integrationsCommand() {
15642
15046
  return;
15643
15047
  }
15644
15048
  if (!collaborators || collaborators.length === 0) {
15645
- console.log(import_picocolors16.default.dim("No collaborators found."));
15049
+ console.log(import_picocolors15.default.dim("No collaborators found."));
15646
15050
  return;
15647
15051
  }
15648
15052
  printTable(["Username", "Name", "Email"], collaborators.map((c3) => [c3.user_name ?? "—", c3.full_name ?? "—", c3.email ?? "—"]), { rawData: collaborators });
@@ -15653,11 +15057,11 @@ function integrationsCommand() {
15653
15057
  // src/commands/knowledge.ts
15654
15058
  init_commander();
15655
15059
  init_trpc();
15656
- var import_picocolors17 = __toESM(require_picocolors(), 1);
15060
+ var import_picocolors16 = __toESM(require_picocolors(), 1);
15657
15061
  function requireConfig7() {
15658
15062
  const cfg = requireLoginConfig();
15659
15063
  if (!cfg.org_id || !cfg.space_id) {
15660
- 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."));
15661
15065
  process.exit(1);
15662
15066
  }
15663
15067
  return cfg;
@@ -15673,7 +15077,7 @@ function knowledgeCommand() {
15673
15077
  });
15674
15078
  const dataSourceIds = dataSources.map((ds) => ds.id).filter((id) => id !== null);
15675
15079
  if (dataSourceIds.length === 0) {
15676
- 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."));
15677
15081
  return;
15678
15082
  }
15679
15083
  const data = await client.search.getMentions.query({
@@ -15687,7 +15091,7 @@ function knowledgeCommand() {
15687
15091
  return;
15688
15092
  }
15689
15093
  if (!results || results.length === 0) {
15690
- console.log(import_picocolors17.default.dim("No results found."));
15094
+ console.log(import_picocolors16.default.dim("No results found."));
15691
15095
  return;
15692
15096
  }
15693
15097
  const limit = Number.parseInt(opts.limit ?? "10", 10);
@@ -15697,7 +15101,7 @@ function knowledgeCommand() {
15697
15101
  r2.entity_type ?? "—"
15698
15102
  ]), { json: false, rawData: limited });
15699
15103
  if (results.length > limit) {
15700
- console.log(import_picocolors17.default.dim(`
15104
+ console.log(import_picocolors16.default.dim(`
15701
15105
  ${results.length - limit} more results not shown.`));
15702
15106
  }
15703
15107
  });
@@ -15710,10 +15114,10 @@ ${results.length - limit} more results not shown.`));
15710
15114
  return;
15711
15115
  }
15712
15116
  if (!store) {
15713
- 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."));
15714
15118
  return;
15715
15119
  }
15716
- console.log(import_picocolors17.default.bold("Knowledge Store"));
15120
+ console.log(import_picocolors16.default.bold("Knowledge Store"));
15717
15121
  console.log(` ID: ${store.id}`);
15718
15122
  console.log(` Space ID: ${store.space_id}`);
15719
15123
  });
@@ -15723,11 +15127,11 @@ ${results.length - limit} more results not shown.`));
15723
15127
  // src/commands/members.ts
15724
15128
  init_commander();
15725
15129
  init_trpc();
15726
- var import_picocolors18 = __toESM(require_picocolors(), 1);
15130
+ var import_picocolors17 = __toESM(require_picocolors(), 1);
15727
15131
  function requireConfig8() {
15728
15132
  const cfg = requireLoginConfig();
15729
15133
  if (!cfg.org_id) {
15730
- 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."));
15731
15135
  process.exit(1);
15732
15136
  }
15733
15137
  return cfg;
@@ -15743,7 +15147,7 @@ function membersCommand() {
15743
15147
  return;
15744
15148
  }
15745
15149
  if (!data.items || data.items.length === 0) {
15746
- console.log(import_picocolors18.default.dim("No members or invitations found."));
15150
+ console.log(import_picocolors17.default.dim("No members or invitations found."));
15747
15151
  return;
15748
15152
  }
15749
15153
  printTable(["Email", "Org"], data.items.map((m3) => [
@@ -15764,7 +15168,7 @@ function membersCommand() {
15764
15168
  printResult({ success: true, email, role }, opts);
15765
15169
  return;
15766
15170
  }
15767
- 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}.`));
15768
15172
  });
15769
15173
  cmd.command("requests").description("List pending access requests").option("--json", "Output as JSON").action(async (opts) => {
15770
15174
  const cfg = requireConfig8();
@@ -15775,7 +15179,7 @@ function membersCommand() {
15775
15179
  return;
15776
15180
  }
15777
15181
  if (!data.items || data.items.length === 0) {
15778
- console.log(import_picocolors18.default.dim("No pending access requests."));
15182
+ console.log(import_picocolors17.default.dim("No pending access requests."));
15779
15183
  return;
15780
15184
  }
15781
15185
  printTable(["Email", "Org"], data.items.map((r2) => [
@@ -15794,7 +15198,7 @@ function membersCommand() {
15794
15198
  printResult({ success: true, email, action: "approved" }, opts);
15795
15199
  return;
15796
15200
  }
15797
- console.log(import_picocolors18.default.green(`Access request from ${email} approved.`));
15201
+ console.log(import_picocolors17.default.green(`Access request from ${email} approved.`));
15798
15202
  });
15799
15203
  cmd.command("deny").description("Deny an access request").argument("<email>", "Email of requester").option("--json", "Output as JSON").action(async (email, opts) => {
15800
15204
  const cfg = requireConfig8();
@@ -15807,7 +15211,7 @@ function membersCommand() {
15807
15211
  printResult({ success: true, email, action: "denied" }, opts);
15808
15212
  return;
15809
15213
  }
15810
- console.log(import_picocolors18.default.green(`Access request from ${email} denied.`));
15214
+ console.log(import_picocolors17.default.green(`Access request from ${email} denied.`));
15811
15215
  });
15812
15216
  return cmd;
15813
15217
  }
@@ -15815,7 +15219,7 @@ function membersCommand() {
15815
15219
  // src/commands/org.ts
15816
15220
  init_commander();
15817
15221
  init_trpc();
15818
- var import_picocolors19 = __toESM(require_picocolors(), 1);
15222
+ var import_picocolors18 = __toESM(require_picocolors(), 1);
15819
15223
  function requireConfig9() {
15820
15224
  return requireLoginConfig();
15821
15225
  }
@@ -15830,7 +15234,7 @@ function orgCommand() {
15830
15234
  return;
15831
15235
  }
15832
15236
  if (!orgs || orgs.length === 0) {
15833
- console.log(import_picocolors19.default.dim("No organizations found."));
15237
+ console.log(import_picocolors18.default.dim("No organizations found."));
15834
15238
  return;
15835
15239
  }
15836
15240
  if (orgs.length === 1) {
@@ -15844,7 +15248,7 @@ function orgCommand() {
15844
15248
  printTable(["ID", "Name"], orgs.map((o2) => [o2.org_id.slice(0, 8), o2.name]), { rawData: orgs });
15845
15249
  if (cfg.org_id) {
15846
15250
  console.log(`
15847
- ${import_picocolors19.default.dim(`Current: ${cfg.org_id}`)}`);
15251
+ ${import_picocolors18.default.dim(`Current: ${cfg.org_id}`)}`);
15848
15252
  }
15849
15253
  });
15850
15254
  return cmd;
@@ -15855,7 +15259,7 @@ init_dist8();
15855
15259
  init_dist();
15856
15260
  init_commander();
15857
15261
  init_trpc();
15858
- var import_picocolors20 = __toESM(require_picocolors(), 1);
15262
+ var import_picocolors19 = __toESM(require_picocolors(), 1);
15859
15263
  import { readFileSync as readFileSync14 } from "node:fs";
15860
15264
  function requireConfig10() {
15861
15265
  return requireLoginConfig();
@@ -15881,7 +15285,7 @@ async function requireChange(client, id) {
15881
15285
  return await client.review.getChange.query({ id });
15882
15286
  } catch (err) {
15883
15287
  if (isNotFound(err) || isInvalidId(err)) {
15884
- 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.`));
15885
15289
  process.exit(1);
15886
15290
  }
15887
15291
  throw err;
@@ -15890,7 +15294,7 @@ async function requireChange(client, id) {
15890
15294
  async function requireDraft(client, id) {
15891
15295
  const draft = await client.messages.getMessage.query(bareMessageId(id));
15892
15296
  if (!draft) {
15893
- 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.`));
15894
15298
  process.exit(1);
15895
15299
  }
15896
15300
  return draft;
@@ -15913,12 +15317,12 @@ function colorizeDiff(diff) {
15913
15317
  return diff.split(`
15914
15318
  `).map((line) => {
15915
15319
  if (line.startsWith("+"))
15916
- return import_picocolors20.default.green(line);
15320
+ return import_picocolors19.default.green(line);
15917
15321
  if (line.startsWith("-"))
15918
- return import_picocolors20.default.red(line);
15322
+ return import_picocolors19.default.red(line);
15919
15323
  if (line.startsWith("@@"))
15920
- return import_picocolors20.default.cyan(line);
15921
- return import_picocolors20.default.dim(line);
15324
+ return import_picocolors19.default.cyan(line);
15325
+ return import_picocolors19.default.dim(line);
15922
15326
  }).join(`
15923
15327
  `);
15924
15328
  }
@@ -15932,7 +15336,7 @@ function printChangePreview(change) {
15932
15336
  ]
15933
15337
  ]);
15934
15338
  if (!change.hasChanges) {
15935
- console.log(import_picocolors20.default.dim("No content changes."));
15339
+ console.log(import_picocolors19.default.dim("No content changes."));
15936
15340
  return;
15937
15341
  }
15938
15342
  console.log();
@@ -15949,7 +15353,7 @@ function printDraftPreview(draft) {
15949
15353
  async function getKnowledgeStoreId2(client, spaceId) {
15950
15354
  const store = await client.knowledgeStore.getBySpaceId.query({ space_id: spaceId });
15951
15355
  if (!store) {
15952
- 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."));
15953
15357
  process.exit(1);
15954
15358
  }
15955
15359
  return store.id;
@@ -15959,7 +15363,7 @@ function reviewCommand() {
15959
15363
  cmd.command("list").description("List pending review items (doc changes and draft replies)").option("--json", "Output as JSON").action(async (opts) => {
15960
15364
  const cfg = requireConfig10();
15961
15365
  if (!cfg.space_id) {
15962
- 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."));
15963
15367
  process.exit(1);
15964
15368
  }
15965
15369
  const client = createTypedClient(cfg);
@@ -15974,7 +15378,7 @@ function reviewCommand() {
15974
15378
  return;
15975
15379
  }
15976
15380
  if (!items || items.length === 0) {
15977
- console.log(import_picocolors20.default.dim("No pending review items."));
15381
+ console.log(import_picocolors19.default.dim("No pending review items."));
15978
15382
  return;
15979
15383
  }
15980
15384
  printTable(["ID", "Kind", "Title", "Source", "Status", "Created"], items.map((i2) => i2.kind === "draft_message" ? [
@@ -15993,7 +15397,7 @@ function reviewCommand() {
15993
15397
  formatDate(i2.createdAt)
15994
15398
  ]), { rawData: items });
15995
15399
  if (truncated) {
15996
- 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).`));
15997
15401
  }
15998
15402
  });
15999
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) => {
@@ -16005,8 +15409,8 @@ function reviewCommand() {
16005
15409
  printResult({ id, kind: "draft_message", title: draft.title, body: draft.body }, opts);
16006
15410
  return;
16007
15411
  }
16008
- console.log(import_picocolors20.default.bold(draft.title ?? "(untitled)"));
16009
- 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"));
16010
15414
  console.log("");
16011
15415
  console.log(draft.body ?? "");
16012
15416
  return;
@@ -16017,8 +15421,8 @@ function reviewCommand() {
16017
15421
  return;
16018
15422
  }
16019
15423
  const versions = change.publishedVersion != null ? `v${change.publishedVersion} → v${change.version}` : `v${change.version}`;
16020
- console.log(import_picocolors20.default.bold(change.title));
16021
- 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}`));
16022
15426
  console.log("");
16023
15427
  console.log(change.diff);
16024
15428
  });
@@ -16026,7 +15430,7 @@ function reviewCommand() {
16026
15430
  const cfg = requireConfig10();
16027
15431
  const client = createTypedClient(cfg);
16028
15432
  if (opts.body !== undefined && opts.bodyFile !== undefined) {
16029
- 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."));
16030
15434
  process.exit(1);
16031
15435
  }
16032
15436
  let body = opts.body;
@@ -16034,17 +15438,17 @@ function reviewCommand() {
16034
15438
  try {
16035
15439
  body = readFileSync14(opts.bodyFile, "utf-8");
16036
15440
  } catch (err) {
16037
- 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}`));
16038
15442
  process.exit(1);
16039
15443
  }
16040
15444
  }
16041
15445
  if (body === undefined && opts.title === undefined) {
16042
- 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."));
16043
15447
  process.exit(1);
16044
15448
  }
16045
15449
  if (isDraftId(id)) {
16046
15450
  if (opts.title !== undefined) {
16047
- 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)."));
16048
15452
  process.exit(1);
16049
15453
  }
16050
15454
  await requireDraft(client, id);
@@ -16061,7 +15465,7 @@ function reviewCommand() {
16061
15465
  });
16062
15466
  } catch (err) {
16063
15467
  if (isNotFound(err)) {
16064
- 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.`));
16065
15469
  process.exit(1);
16066
15470
  }
16067
15471
  throw err;
@@ -16071,7 +15475,7 @@ function reviewCommand() {
16071
15475
  printResult({ success: true, id }, opts);
16072
15476
  return;
16073
15477
  }
16074
- console.log(import_picocolors20.default.green(`Review edited: ${truncateId(id)}`));
15478
+ console.log(import_picocolors19.default.green(`Review edited: ${truncateId(id)}`));
16075
15479
  });
16076
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) => {
16077
15481
  const cfg = requireConfig10();
@@ -16118,7 +15522,7 @@ function reviewCommand() {
16118
15522
  initialValue: false
16119
15523
  });
16120
15524
  if (isCancel(answer)) {
16121
- console.log(import_picocolors20.default.dim("Cancelled."));
15525
+ console.log(import_picocolors19.default.dim("Cancelled."));
16122
15526
  return;
16123
15527
  }
16124
15528
  proceed = answer === true;
@@ -16133,7 +15537,7 @@ function reviewCommand() {
16133
15537
  };
16134
15538
  printResult({ ...preview, applied: false, confirmRequired: true }, opts);
16135
15539
  } else {
16136
- 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."));
16137
15541
  }
16138
15542
  return;
16139
15543
  }
@@ -16148,7 +15552,7 @@ function reviewCommand() {
16148
15552
  printResult({ success: true, id, action }, opts);
16149
15553
  return;
16150
15554
  }
16151
- console.log(import_picocolors20.default.green(`Review ${name}: ${truncateId(id)}`));
15555
+ console.log(import_picocolors19.default.green(`Review ${name}: ${truncateId(id)}`));
16152
15556
  });
16153
15557
  }
16154
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) => {
@@ -16156,7 +15560,7 @@ function reviewCommand() {
16156
15560
  const client = createTypedClient(cfg);
16157
15561
  if (isDraftId(id)) {
16158
15562
  await requireDraft(client, id);
16159
- 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."));
16160
15564
  process.exit(1);
16161
15565
  }
16162
15566
  await requireChange(client, id);
@@ -16168,7 +15572,7 @@ function reviewCommand() {
16168
15572
  printResult({ success: true, id, action: "revert_to_pending" }, opts);
16169
15573
  return;
16170
15574
  }
16171
- console.log(import_picocolors20.default.green(`Review revert: ${truncateId(id)}`));
15575
+ console.log(import_picocolors19.default.green(`Review revert: ${truncateId(id)}`));
16172
15576
  });
16173
15577
  return cmd;
16174
15578
  }
@@ -16179,11 +15583,11 @@ init_skill();
16179
15583
  // src/commands/sources.ts
16180
15584
  init_commander();
16181
15585
  init_trpc();
16182
- var import_picocolors21 = __toESM(require_picocolors(), 1);
15586
+ var import_picocolors20 = __toESM(require_picocolors(), 1);
16183
15587
  function requireConfig11() {
16184
15588
  const cfg = requireLoginConfig();
16185
15589
  if (!cfg.org_id) {
16186
- 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."));
16187
15591
  process.exit(1);
16188
15592
  }
16189
15593
  return cfg;
@@ -16203,7 +15607,7 @@ function sourcesCommand() {
16203
15607
  }
16204
15608
  const list = dataSources ?? [];
16205
15609
  if (list.length === 0) {
16206
- console.log(import_picocolors21.default.dim("No data sources connected."));
15610
+ console.log(import_picocolors20.default.dim("No data sources connected."));
16207
15611
  return;
16208
15612
  }
16209
15613
  printTable(["ID", "Name", "Provider", "Created"], list.map((ds) => [
@@ -16222,7 +15626,7 @@ function sourcesCommand() {
16222
15626
  return;
16223
15627
  }
16224
15628
  if (!ds) {
16225
- console.log(import_picocolors21.default.dim("Data source not found."));
15629
+ console.log(import_picocolors20.default.dim("Data source not found."));
16226
15630
  return;
16227
15631
  }
16228
15632
  printInfo([
@@ -16241,7 +15645,7 @@ function sourcesCommand() {
16241
15645
  printResult({ success: true, id }, opts);
16242
15646
  return;
16243
15647
  }
16244
- 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)}.`));
16245
15649
  });
16246
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) => {
16247
15651
  const cfg = requireConfig11();
@@ -16255,7 +15659,7 @@ function sourcesCommand() {
16255
15659
  printResult(result, opts);
16256
15660
  return;
16257
15661
  }
16258
- console.log(import_picocolors21.default.green("Data source updated."));
15662
+ console.log(import_picocolors20.default.green("Data source updated."));
16259
15663
  });
16260
15664
  cmd.command("delete").description("Delete a data source").argument("<id>", "Data source ID").option("--json", "Output as JSON").action(async (id, opts) => {
16261
15665
  const cfg = requireConfig11();
@@ -16265,7 +15669,7 @@ function sourcesCommand() {
16265
15669
  printResult({ success: true, id }, opts);
16266
15670
  return;
16267
15671
  }
16268
- console.log(import_picocolors21.default.green("Data source deleted."));
15672
+ console.log(import_picocolors20.default.green("Data source deleted."));
16269
15673
  });
16270
15674
  return cmd;
16271
15675
  }
@@ -16273,11 +15677,11 @@ function sourcesCommand() {
16273
15677
  // src/commands/suggest.ts
16274
15678
  init_commander();
16275
15679
  init_trpc();
16276
- var import_picocolors22 = __toESM(require_picocolors(), 1);
15680
+ var import_picocolors21 = __toESM(require_picocolors(), 1);
16277
15681
  function requireConfig12() {
16278
15682
  const cfg = requireLoginConfig();
16279
15683
  if (!cfg.space_id) {
16280
- 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."));
16281
15685
  process.exit(1);
16282
15686
  }
16283
15687
  return cfg;
@@ -16287,7 +15691,7 @@ async function getKnowledgeStoreId3(client, spaceId) {
16287
15691
  space_id: spaceId
16288
15692
  });
16289
15693
  if (!store) {
16290
- 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."));
16291
15695
  process.exit(1);
16292
15696
  }
16293
15697
  return store.id;
@@ -16306,7 +15710,7 @@ function suggestCommand() {
16306
15710
  return;
16307
15711
  }
16308
15712
  if (!suggestions || suggestions.length === 0) {
16309
- console.log(import_picocolors22.default.dim("No pending suggestions."));
15713
+ console.log(import_picocolors21.default.dim("No pending suggestions."));
16310
15714
  return;
16311
15715
  }
16312
15716
  printTable(["ID", "Title"], suggestions.map((s) => [
@@ -16319,7 +15723,7 @@ function suggestCommand() {
16319
15723
  const client = createTypedClient(cfg);
16320
15724
  const ksId = await getKnowledgeStoreId3(client, cfg.space_id);
16321
15725
  if (!cfg.org_id) {
16322
- 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."));
16323
15727
  process.exit(1);
16324
15728
  }
16325
15729
  const dataSources = await client.dataSource.list.query({
@@ -16335,7 +15739,7 @@ function suggestCommand() {
16335
15739
  printResult(result, opts);
16336
15740
  return;
16337
15741
  }
16338
- console.log(import_picocolors22.default.green("Document suggestions are being generated."));
15742
+ console.log(import_picocolors21.default.green("Document suggestions are being generated."));
16339
15743
  });
16340
15744
  cmd.command("reject").description("Reject a suggestion").argument("<id>", "Suggestion ID").option("--json", "Output as JSON").action(async (id, opts) => {
16341
15745
  const cfg = requireConfig12();
@@ -16345,7 +15749,7 @@ function suggestCommand() {
16345
15749
  printResult({ success: true, id }, opts);
16346
15750
  return;
16347
15751
  }
16348
- console.log(import_picocolors22.default.green("Suggestion rejected."));
15752
+ console.log(import_picocolors21.default.green("Suggestion rejected."));
16349
15753
  });
16350
15754
  return cmd;
16351
15755
  }
@@ -16353,11 +15757,11 @@ function suggestCommand() {
16353
15757
  // src/commands/threads.ts
16354
15758
  init_commander();
16355
15759
  init_trpc();
16356
- var import_picocolors23 = __toESM(require_picocolors(), 1);
15760
+ var import_picocolors22 = __toESM(require_picocolors(), 1);
16357
15761
  function requireConfig13() {
16358
15762
  const cfg = requireLoginConfig();
16359
15763
  if (!cfg.space_id) {
16360
- 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."));
16361
15765
  process.exit(1);
16362
15766
  }
16363
15767
  return cfg;
@@ -16404,7 +15808,7 @@ function threadsCommand() {
16404
15808
  return;
16405
15809
  }
16406
15810
  if (!threads || threads.length === 0) {
16407
- console.log(import_picocolors23.default.dim("No threads found."));
15811
+ console.log(import_picocolors22.default.dim("No threads found."));
16408
15812
  return;
16409
15813
  }
16410
15814
  printTable(["ID", "Title", "Status", "Created"], threads.map((t2) => [
@@ -16429,10 +15833,10 @@ function threadsCommand() {
16429
15833
  return;
16430
15834
  }
16431
15835
  if (!thread) {
16432
- console.log(import_picocolors23.default.dim("Thread not found."));
15836
+ console.log(import_picocolors22.default.dim("Thread not found."));
16433
15837
  return;
16434
15838
  }
16435
- console.log(import_picocolors23.default.bold(thread.generated_title ?? "(untitled thread)"));
15839
+ console.log(import_picocolors22.default.bold(thread.generated_title ?? "(untitled thread)"));
16436
15840
  printInfo([
16437
15841
  ["ID", thread.id],
16438
15842
  ["Created", formatDate(thread.created_at)],
@@ -16443,13 +15847,13 @@ function threadsCommand() {
16443
15847
  if (messages && messages.length > 0) {
16444
15848
  const allMessages = messages.flatMap((group) => group.messages);
16445
15849
  console.log(`
16446
- ${import_picocolors23.default.bold("Messages")} (${allMessages.length})`);
16447
- 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)));
16448
15852
  for (const msg of allMessages) {
16449
15853
  const role = msg.author_role ?? "unknown";
16450
15854
  const date = formatDate(msg.created_at);
16451
15855
  console.log(`
16452
- ${import_picocolors23.default.bold(role)} ${import_picocolors23.default.dim(date)}`);
15856
+ ${import_picocolors22.default.bold(role)} ${import_picocolors22.default.dim(date)}`);
16453
15857
  if (msg.body) {
16454
15858
  console.log(truncate(msg.body, 500));
16455
15859
  }
@@ -16464,7 +15868,7 @@ ${import_picocolors23.default.bold(role)} ${import_picocolors23.default.dim(date
16464
15868
  printResult({ success: true, id }, opts);
16465
15869
  return;
16466
15870
  }
16467
- 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.`));
16468
15872
  });
16469
15873
  return cmd;
16470
15874
  }
@@ -16472,11 +15876,11 @@ ${import_picocolors23.default.bold(role)} ${import_picocolors23.default.dim(date
16472
15876
  // src/commands/topics.ts
16473
15877
  init_commander();
16474
15878
  init_trpc();
16475
- var import_picocolors24 = __toESM(require_picocolors(), 1);
15879
+ var import_picocolors23 = __toESM(require_picocolors(), 1);
16476
15880
  function requireConfig14() {
16477
15881
  const cfg = requireLoginConfig();
16478
15882
  if (!cfg.space_id) {
16479
- 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."));
16480
15884
  process.exit(1);
16481
15885
  }
16482
15886
  return cfg;
@@ -16486,7 +15890,7 @@ async function getKnowledgeStoreId4(client, spaceId) {
16486
15890
  space_id: spaceId
16487
15891
  });
16488
15892
  if (!store) {
16489
- 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."));
16490
15894
  process.exit(1);
16491
15895
  }
16492
15896
  return store.id;
@@ -16505,7 +15909,7 @@ function topicsCommand() {
16505
15909
  return;
16506
15910
  }
16507
15911
  if (!topics || topics.length === 0) {
16508
- console.log(import_picocolors24.default.dim("No topics found."));
15912
+ console.log(import_picocolors23.default.dim("No topics found."));
16509
15913
  return;
16510
15914
  }
16511
15915
  printTable(["ID", "Name", "Description"], topics.map((t2) => [
@@ -16530,7 +15934,7 @@ function topicsCommand() {
16530
15934
  return;
16531
15935
  }
16532
15936
  if (!pages || pages.length === 0) {
16533
- 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."));
16534
15938
  return;
16535
15939
  }
16536
15940
  printTable(["ID", "Title"], pages.map((p2) => [
@@ -16551,9 +15955,9 @@ init_skill_update_check();
16551
15955
  // src/version/update-check.ts
16552
15956
  init_config();
16553
15957
  init_logger();
16554
- var import_picocolors25 = __toESM(require_picocolors(), 1);
16555
- import { existsSync as existsSync18, mkdirSync as mkdirSync9, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "node:fs";
16556
- 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";
16557
15961
  var CACHE_FILENAME3 = "update-check.json";
16558
15962
  var CHECK_INTERVAL_MS3 = 24 * 60 * 60 * 1000;
16559
15963
  var FETCH_TIMEOUT_MS3 = 5000;
@@ -16576,12 +15980,12 @@ function isNewerVersion(latest, current) {
16576
15980
  return false;
16577
15981
  }
16578
15982
  function getCachePath3() {
16579
- return join28(getConfigDir(), CACHE_FILENAME3);
15983
+ return join27(getConfigDir(), CACHE_FILENAME3);
16580
15984
  }
16581
15985
  function readCache() {
16582
15986
  try {
16583
15987
  const path3 = getCachePath3();
16584
- if (!existsSync18(path3))
15988
+ if (!existsSync17(path3))
16585
15989
  return null;
16586
15990
  const data = JSON.parse(readFileSync15(path3, "utf-8"));
16587
15991
  if (typeof data.lastCheck === "number" && typeof data.latestVersion === "string") {
@@ -16595,7 +15999,7 @@ function readCache() {
16595
15999
  function writeCache(cache) {
16596
16000
  try {
16597
16001
  const dir = getConfigDir();
16598
- if (!existsSync18(dir)) {
16002
+ if (!existsSync17(dir)) {
16599
16003
  mkdirSync9(dir, { recursive: true, mode: 448 });
16600
16004
  }
16601
16005
  writeFileSync8(getCachePath3(), JSON.stringify(cache), { mode: 384 });
@@ -16626,8 +16030,8 @@ function buildUpdateHint(channel) {
16626
16030
  }
16627
16031
  function displayNotice2(current, latest) {
16628
16032
  const msg = `
16629
- ${import_picocolors25.default.yellow(` Update available: ${current} → ${latest}`)}
16630
- ` + `${import_picocolors25.default.dim(` ${buildUpdateHint(INSTALL_CHANNEL)}`)}
16033
+ ${import_picocolors24.default.yellow(` Update available: ${current} → ${latest}`)}
16034
+ ` + `${import_picocolors24.default.dim(` ${buildUpdateHint(INSTALL_CHANNEL)}`)}
16631
16035
  `;
16632
16036
  console.error(msg);
16633
16037
  }