@dosu/cli 0.31.0 → 0.32.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/dosu.js +343 -900
- 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.
|
|
4580
|
+
var VERSION = "0.32.1", 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
|
|
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, "&").replace(/</g, "<").replace(/>/g, ">")}</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
|
|
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
|
|
11364
|
+
<h1 id="heading">${copy2.heading}</h1>
|
|
11959
11365
|
${emailLine}
|
|
11960
|
-
<p class="close-msg"
|
|
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: () =>
|
|
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
|
-
|
|
11573
|
+
options.onAuthURL?.(authURL);
|
|
12129
11574
|
let browserOpened = false;
|
|
12130
|
-
|
|
12131
|
-
await open2.default(authURL);
|
|
11575
|
+
if (options.suppressBrowserOpen) {
|
|
12132
11576
|
browserOpened = true;
|
|
12133
|
-
logger.info("auth.flow", "Browser open
|
|
12134
|
-
|
|
12135
|
-
|
|
12136
|
-
|
|
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
|
-
|
|
12160
|
-
|
|
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
|
|
12202
|
-
if (!
|
|
11655
|
+
const authed = await stepAuthenticate(cfg, onboardingRunID);
|
|
11656
|
+
if (!authed)
|
|
12203
11657
|
return;
|
|
12204
|
-
cfg =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
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 } : {},
|
|
12507
|
-
|
|
12508
|
-
|
|
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
|
|
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
|
|
12869
|
-
import { dirname as dirname5, join as
|
|
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${
|
|
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 ?
|
|
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
|
|
12377
|
+
return join26(getConfigDir(), "insights");
|
|
12974
12378
|
}
|
|
12975
12379
|
function reportPath(timestamp) {
|
|
12976
12380
|
const dir = insightsDir();
|
|
12977
12381
|
if (!timestamp)
|
|
12978
|
-
return
|
|
12382
|
+
return join26(dir, "latest.html");
|
|
12979
12383
|
const iso = timestamp.toISOString().slice(0, 19).replace(/:/g, "-");
|
|
12980
|
-
return
|
|
12384
|
+
return join26(dir, `report-${iso}Z.html`);
|
|
12981
12385
|
}
|
|
12982
12386
|
function pruneOldReports(dir, keepN) {
|
|
12983
|
-
if (!
|
|
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(
|
|
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(
|
|
12451
|
+
console.log(import_picocolors14.default.bold(`\uD83D\uDCCA Dosu Insights · ${report.spaceName}`));
|
|
13048
12452
|
if (report.cheers[0]) {
|
|
13049
|
-
console.log(
|
|
12453
|
+
console.log(import_picocolors14.default.green(` ${report.cheers[0]}`));
|
|
13050
12454
|
}
|
|
13051
12455
|
console.log("");
|
|
13052
|
-
console.log(` Snapshot: ${
|
|
13053
|
-
console.log(` Latest: ${
|
|
13054
|
-
console.log(
|
|
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(
|
|
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 (!
|
|
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(
|
|
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(
|
|
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
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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 ?
|
|
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}: ${
|
|
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 ?
|
|
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}: ${
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
15117
|
+
console.log(import_picocolors16.default.dim("No knowledge store found for this deployment."));
|
|
15714
15118
|
return;
|
|
15715
15119
|
}
|
|
15716
|
-
console.log(
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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
|
-
${
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
15320
|
+
return import_picocolors19.default.green(line);
|
|
15917
15321
|
if (line.startsWith("-"))
|
|
15918
|
-
return
|
|
15322
|
+
return import_picocolors19.default.red(line);
|
|
15919
15323
|
if (line.startsWith("@@"))
|
|
15920
|
-
return
|
|
15921
|
-
return
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
16009
|
-
console.log(
|
|
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(
|
|
16021
|
-
console.log(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
15836
|
+
console.log(import_picocolors22.default.dim("Thread not found."));
|
|
16433
15837
|
return;
|
|
16434
15838
|
}
|
|
16435
|
-
console.log(
|
|
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
|
-
${
|
|
16447
|
-
console.log(
|
|
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
|
-
${
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
16555
|
-
import { existsSync as
|
|
16556
|
-
import { join as
|
|
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
|
|
15983
|
+
return join27(getConfigDir(), CACHE_FILENAME3);
|
|
16580
15984
|
}
|
|
16581
15985
|
function readCache() {
|
|
16582
15986
|
try {
|
|
16583
15987
|
const path3 = getCachePath3();
|
|
16584
|
-
if (!
|
|
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 (!
|
|
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
|
-
${
|
|
16630
|
-
` + `${
|
|
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
|
}
|
|
@@ -16662,9 +16066,35 @@ function isHookEntrypointInvocation(argv) {
|
|
|
16662
16066
|
const i2 = argv.indexOf("hooks");
|
|
16663
16067
|
return i2 >= 0 && HOOK_ENTRYPOINTS.has(argv[i2 + 1] ?? "");
|
|
16664
16068
|
}
|
|
16069
|
+
function suggestClosestCommand(input, program2) {
|
|
16070
|
+
let best;
|
|
16071
|
+
let bestDistance = Infinity;
|
|
16072
|
+
const candidates = ["help", ...program2.commands.flatMap((c3) => [c3.name(), ...c3.aliases()])];
|
|
16073
|
+
for (const name of candidates) {
|
|
16074
|
+
const d = editDistance2(input.toLowerCase(), name.toLowerCase());
|
|
16075
|
+
if (d < bestDistance) {
|
|
16076
|
+
bestDistance = d;
|
|
16077
|
+
best = name;
|
|
16078
|
+
}
|
|
16079
|
+
}
|
|
16080
|
+
return best !== undefined && bestDistance <= 3 && bestDistance < best.length ? best : undefined;
|
|
16081
|
+
}
|
|
16082
|
+
function editDistance2(a3, b2) {
|
|
16083
|
+
const prev = Array.from({ length: b2.length + 1 }, (_2, i2) => i2);
|
|
16084
|
+
for (let i2 = 1;i2 <= a3.length; i2++) {
|
|
16085
|
+
let diag = prev[0];
|
|
16086
|
+
prev[0] = i2;
|
|
16087
|
+
for (let j = 1;j <= b2.length; j++) {
|
|
16088
|
+
const tmp = prev[j];
|
|
16089
|
+
prev[j] = Math.min(prev[j] + 1, prev[j - 1] + 1, diag + (a3[i2 - 1] === b2[j - 1] ? 0 : 1));
|
|
16090
|
+
diag = tmp;
|
|
16091
|
+
}
|
|
16092
|
+
}
|
|
16093
|
+
return prev[b2.length];
|
|
16094
|
+
}
|
|
16665
16095
|
function createProgram() {
|
|
16666
16096
|
const program2 = new Command;
|
|
16667
|
-
program2.name("dosu").description("Dosu CLI - Manage MCP servers for AI tools").version(getVersionString(), "-v, --version").option("--debug", "Enable debug logging to stderr", false).hook("preAction", (thisCommand) => {
|
|
16097
|
+
program2.name("dosu").description("Dosu CLI - Manage MCP servers for AI tools").version(getVersionString(), "-v, --version").helpCommand("help [command]", "Show help for a command").option("--debug", "Enable debug logging to stderr", false).hook("preAction", (thisCommand) => {
|
|
16668
16098
|
const opts = thisCommand.optsWithGlobals();
|
|
16669
16099
|
logger.init({ debug: opts.debug });
|
|
16670
16100
|
if (!isHookEntrypointInvocation(process.argv)) {
|
|
@@ -16672,7 +16102,20 @@ function createProgram() {
|
|
|
16672
16102
|
checkForSkillUpdates();
|
|
16673
16103
|
checkForReadyTasks();
|
|
16674
16104
|
}
|
|
16675
|
-
}).action(async () => {
|
|
16105
|
+
}).allowExcessArguments(true).action(async () => {
|
|
16106
|
+
const command = program2.args[0];
|
|
16107
|
+
if (command !== undefined) {
|
|
16108
|
+
let message = `error: unknown command '${command}'`;
|
|
16109
|
+
const suggestion = suggestClosestCommand(command, program2);
|
|
16110
|
+
if (suggestion)
|
|
16111
|
+
message += `
|
|
16112
|
+
(Did you mean '${suggestion}'?)`;
|
|
16113
|
+
message += `
|
|
16114
|
+
Run 'dosu --help' to see available commands.`;
|
|
16115
|
+
console.error(message);
|
|
16116
|
+
process.exitCode = 1;
|
|
16117
|
+
return;
|
|
16118
|
+
}
|
|
16676
16119
|
const { runTUI: runTUI2 } = await Promise.resolve().then(() => (init_tui(), exports_tui));
|
|
16677
16120
|
await runTUI2();
|
|
16678
16121
|
});
|