@dosu/cli 0.49.3 → 0.49.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +3 -3
  2. package/bin/dosu.js +237 -168
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -120,10 +120,10 @@ Once authenticated against a deployment, you can drive the Dosu platform without
120
120
  | `dosu review` | Document review workflow |
121
121
  | `dosu sources` | Manage connected data sources (list, sync, update) |
122
122
  | `dosu integrations` | List and inspect platform integrations (Slack, GitHub, …) |
123
- | `dosu tags` | List knowledge base tags and tagged pages |
124
- | `dosu members` | Manage team members and access requests |
123
+ | `dosu topics` | List knowledge base topics and their pages |
124
+ | `dosu members` | Invite organization members |
125
125
  | `dosu org` | Show organization information |
126
- | `dosu deployments` | List / show / switch deployments |
126
+ | `dosu deployments` | List / show / switch Dosu MCP deployments |
127
127
  | `dosu analytics` | View usage statistics |
128
128
  | `dosu insights` | Open a visual report of your Dosu space activity |
129
129
  | `dosu skill` | Install / update / remove the Dosu agent skill |
package/bin/dosu.js CHANGED
@@ -5000,7 +5000,7 @@ function isNpxInvocation(channel = INSTALL_CHANNEL, env = process.env) {
5000
5000
  function getVersionString() {
5001
5001
  return `v${VERSION}`;
5002
5002
  }
5003
- var VERSION = "0.49.3", INSTALL_CHANNEL = "npm";
5003
+ var VERSION = "0.49.4", INSTALL_CHANNEL = "npm";
5004
5004
 
5005
5005
  // src/debug/logger.ts
5006
5006
  import {
@@ -8935,7 +8935,7 @@ var init_skill = __esm(() => {
8935
8935
  });
8936
8936
 
8937
8937
  // src/mcp/constants.ts
8938
- var MCP_PROVIDER_SLUG = "dosu_mcp";
8938
+ var MCP_PROVIDER_SLUG2 = "dosu_mcp";
8939
8939
 
8940
8940
  // node_modules/signal-exit/dist/cjs/signals.js
8941
8941
  var require_signals = __commonJS((exports) => {
@@ -10593,7 +10593,7 @@ var init_settings = __esm(() => {
10593
10593
  });
10594
10594
 
10595
10595
  // src/telemetry/debug-id.ts
10596
- var BUNDLE_DEBUG_ID_PLACEHOLDER = "d08d0e8f-b86e-9699-6475-6e2164756e21";
10596
+ var BUNDLE_DEBUG_ID_PLACEHOLDER = "0e1efd83-4f86-ddb7-6475-6e2164756e21";
10597
10597
 
10598
10598
  // src/telemetry/telemetry.ts
10599
10599
  import { randomUUID as randomUUID3 } from "node:crypto";
@@ -11133,8 +11133,8 @@ function safeUuid(generate) {
11133
11133
  }
11134
11134
  }
11135
11135
  function eventId(generate) {
11136
- const uuid = safeUuid(generate);
11137
- return uuid?.replaceAll("-", "");
11136
+ const uuid2 = safeUuid(generate);
11137
+ return uuid2?.replaceAll("-", "");
11138
11138
  }
11139
11139
  function createCommandTelemetry(settings2, dependencies = {}) {
11140
11140
  const env = dependencies.env ?? process.env;
@@ -12728,7 +12728,7 @@ async function stepSelectDeployment(apiClient, org) {
12728
12728
  ${dim(deployments[0].name)}`);
12729
12729
  return deployments[0];
12730
12730
  }
12731
- const mcpDeployments = deployments.filter((d2) => d2.provider_slug === MCP_PROVIDER_SLUG);
12731
+ const mcpDeployments = deployments.filter((d2) => d2.provider_slug === MCP_PROVIDER_SLUG2);
12732
12732
  if (mcpDeployments.length === 1) {
12733
12733
  logger.info("setup", `Selected deployment: ${mcpDeployments[0].name} (auto, single MCP)`);
12734
12734
  log.success(`Using MCP
@@ -13813,7 +13813,7 @@ async function resolveDeployment2(client, cfg, opts) {
13813
13813
  });
13814
13814
  return { code: 1, cfg };
13815
13815
  }
13816
- const mcpDeployments = allDeployments.filter((d) => d.provider_slug === MCP_PROVIDER_SLUG);
13816
+ const mcpDeployments = allDeployments.filter((d) => d.provider_slug === MCP_PROVIDER_SLUG2);
13817
13817
  if (mcpDeployments.length === 0) {
13818
13818
  emitError({
13819
13819
  step: "deployment",
@@ -13939,6 +13939,38 @@ init_commander();
13939
13939
  init_trpc();
13940
13940
  var import_picocolors4 = __toESM(require_picocolors(), 1);
13941
13941
 
13942
+ // src/commands/arguments.ts
13943
+ init_commander();
13944
+ function positiveInteger(value) {
13945
+ const parsed = Number(value);
13946
+ if (!Number.isSafeInteger(parsed) || parsed <= 0) {
13947
+ throw new InvalidArgumentError("must be a positive integer");
13948
+ }
13949
+ return parsed;
13950
+ }
13951
+ function positiveIntegerAtMost(maximum) {
13952
+ return (value) => {
13953
+ const parsed = positiveInteger(value);
13954
+ if (parsed > maximum) {
13955
+ throw new InvalidArgumentError(`must be at most ${maximum}`);
13956
+ }
13957
+ return parsed;
13958
+ };
13959
+ }
13960
+ function messageLimit(value) {
13961
+ const parsed = Number(value);
13962
+ if (!Number.isSafeInteger(parsed) || parsed !== -1 && parsed <= 0) {
13963
+ throw new InvalidArgumentError("must be -1 or a positive integer");
13964
+ }
13965
+ return parsed;
13966
+ }
13967
+ function uuid(value) {
13968
+ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value)) {
13969
+ throw new InvalidArgumentError("must be a UUID");
13970
+ }
13971
+ return value;
13972
+ }
13973
+
13942
13974
  // src/commands/auth.ts
13943
13975
  init_config();
13944
13976
  var import_picocolors2 = __toESM(require_picocolors(), 1);
@@ -14027,12 +14059,12 @@ function requireConfig() {
14027
14059
  return cfg;
14028
14060
  }
14029
14061
  function analyticsCommand() {
14030
- const cmd = new Command("analytics").description("View usage statistics").option("--days <n>", "Number of days to analyze (default: 30)", "30").option("--json", "Output as JSON").action(async (opts) => {
14062
+ const cmd = new Command("analytics").description("View usage statistics").addOption(new Option("--days <n>", "Number of days to analyze (default: 30)").argParser(positiveInteger).default(30)).option("--json", "Output as JSON").action(async (opts) => {
14031
14063
  const cfg = requireConfig();
14032
14064
  const client = createTypedClient(cfg);
14033
14065
  const stats = await client.analytics.getUsageStats.query({
14034
14066
  spaceId: cfg.active_account.target.space_id,
14035
- days: Number.parseInt(opts.days ?? "30", 10)
14067
+ days: opts.days
14036
14068
  });
14037
14069
  if (opts.json) {
14038
14070
  printResult(stats, opts);
@@ -14666,6 +14698,26 @@ var REPO_REFRESH_POLL_TIMEOUT_MS = 1e4;
14666
14698
  var REPO_MULTISELECT_MAX_ITEMS = 10;
14667
14699
  var DATA_SOURCE_VERIFY_POLL_INTERVAL_MS = 1000;
14668
14700
  var DATA_SOURCE_VERIFY_POLL_TIMEOUT_MS = 1e4;
14701
+ function parseAvailableRepos(value) {
14702
+ if (!Array.isArray(value))
14703
+ throw new Error("githubRepository.listForOrg returned a non-array");
14704
+ return value.map((repository, index) => {
14705
+ if (repository === null || typeof repository !== "object" || !("repository_id" in repository) || typeof repository.repository_id !== "number" || !("name" in repository) || typeof repository.name !== "string" || !("slug" in repository) || typeof repository.slug !== "string" || !("is_deployed" in repository) || typeof repository.is_deployed !== "boolean" || "created_at" in repository && repository.created_at !== undefined && typeof repository.created_at !== "string") {
14706
+ throw new Error(`githubRepository.listForOrg returned an invalid repository at index ${index}`);
14707
+ }
14708
+ return repository;
14709
+ });
14710
+ }
14711
+ function parseDeploymentIds(value) {
14712
+ if (!Array.isArray(value))
14713
+ throw new Error("workspaces.listForSpace returned a non-array");
14714
+ return value.map((deployment, index) => {
14715
+ if (deployment === null || typeof deployment !== "object" || !("deployment_id" in deployment) || typeof deployment.deployment_id !== "string") {
14716
+ throw new Error(`workspaces.listForSpace returned an invalid deployment at index ${index}`);
14717
+ }
14718
+ return deployment.deployment_id;
14719
+ });
14720
+ }
14669
14721
  function detectGitRepo(cwd = process.cwd()) {
14670
14722
  let url;
14671
14723
  try {
@@ -14689,9 +14741,9 @@ function detectGitRepo(cwd = process.cwd()) {
14689
14741
  }
14690
14742
  async function fetchListForOrg(trpc, orgID) {
14691
14743
  try {
14692
- const repos = await trpc.githubRepository.listForOrg.query({
14744
+ const repos = parseAvailableRepos(await trpc.githubRepository.listForOrg.query({
14693
14745
  org_id: orgID
14694
- });
14746
+ }));
14695
14747
  return sortReposByRecency(repos);
14696
14748
  } catch (err) {
14697
14749
  const msg = err instanceof Error ? err.message : String(err);
@@ -14831,9 +14883,9 @@ async function createDeploymentForRepo(trpc, orgID, spaceID, repo) {
14831
14883
  space_id: spaceID,
14832
14884
  data_source_ids: [dataSourceID]
14833
14885
  });
14834
- const spaceDeployments = await trpc.workspaces.listForSpace.query(spaceID);
14835
- await Promise.all(spaceDeployments.map((d) => trpc.deploymentDataSource.create.mutate({
14836
- deployment_id: d.deployment_id,
14886
+ const spaceDeploymentIds = parseDeploymentIds(await trpc.workspaces.listForSpace.query(spaceID));
14887
+ await Promise.all(spaceDeploymentIds.map((deploymentID) => trpc.deploymentDataSource.create.mutate({
14888
+ deployment_id: deploymentID,
14837
14889
  data_source_id: dataSourceID
14838
14890
  })));
14839
14891
  return {
@@ -15435,18 +15487,28 @@ function auditCommand() {
15435
15487
 
15436
15488
  // src/commands/deployments.ts
15437
15489
  init_commander();
15490
+ init_client();
15438
15491
  init_trpc();
15439
15492
  init_config();
15440
15493
  var import_picocolors10 = __toESM(require_picocolors(), 1);
15494
+ var MCP_PROVIDER_SLUG = "dosu_mcp";
15441
15495
  function requireConfig4() {
15442
15496
  return requireLoginConfig();
15443
15497
  }
15498
+ async function listAccessibleDeployments(client, activeOrgId) {
15499
+ if (activeOrgId)
15500
+ return client.workspaces.listForOrg.query(activeOrgId);
15501
+ const orgs = await client.organization.getOrganizations.query({});
15502
+ const deployments = await Promise.all(orgs.map((org) => client.workspaces.listForOrg.query(org.org_id)));
15503
+ return deployments.flat();
15504
+ }
15444
15505
  function deploymentsCommand() {
15445
15506
  const cmd = new Command("deployments").description("Manage deployments");
15446
15507
  cmd.command("list").description("List all deployments").option("--json", "Output as JSON").action(async (opts) => {
15447
15508
  const cfg = requireConfig4();
15448
15509
  const client = createTypedClient(cfg);
15449
- const deployments = cfg.active_account?.target?.org_id ? await client.workspaces.listForOrg.query(cfg.active_account?.target?.org_id) : await client.workspaces.listAll.query({});
15510
+ const allDeployments = await listAccessibleDeployments(client, cfg.active_account?.target?.org_id);
15511
+ const deployments = allDeployments.filter((deployment) => deployment.provider_slug === MCP_PROVIDER_SLUG);
15450
15512
  if (opts.json) {
15451
15513
  printResult(deployments, opts);
15452
15514
  return;
@@ -15501,11 +15563,17 @@ ${import_picocolors10.default.dim(`Current: ${cfg.active_account?.target?.deploy
15501
15563
  console.error(import_picocolors10.default.red(`Deployment not found: ${id}`));
15502
15564
  process.exit(1);
15503
15565
  }
15566
+ if (deployment.provider_slug !== MCP_PROVIDER_SLUG) {
15567
+ console.error(import_picocolors10.default.red(`Not a Dosu MCP deployment: ${id}`));
15568
+ process.exit(1);
15569
+ }
15570
+ const apiKey = await new Client(cfg).createAPIKey(deployment.deployment_id, "dosu-cli");
15504
15571
  updateTarget(cfg, {
15505
15572
  deployment_id: deployment.deployment_id,
15506
15573
  deployment_name: deployment.name,
15507
15574
  org_id: deployment.org_id,
15508
- space_id: deployment.space_id
15575
+ space_id: deployment.space_id,
15576
+ api_key: apiKey.api_key
15509
15577
  });
15510
15578
  saveConfig(cfg);
15511
15579
  if (opts.json) {
@@ -15521,10 +15589,47 @@ ${import_picocolors10.default.dim(`Current: ${cfg.active_account?.target?.deploy
15521
15589
  init_dist8();
15522
15590
  init_dist();
15523
15591
  init_commander();
15592
+ init_client();
15524
15593
  init_trpc();
15525
15594
  init_logger();
15526
15595
  var import_picocolors11 = __toESM(require_picocolors(), 1);
15527
15596
  import { readFileSync as readFileSync6 } from "node:fs";
15597
+
15598
+ // src/commands/doc-import.ts
15599
+ var IMPORT_PLATFORMS = [
15600
+ "github",
15601
+ "gitlab",
15602
+ "azure_devops",
15603
+ "confluence",
15604
+ "notion",
15605
+ "coda"
15606
+ ];
15607
+ async function importDocuments(client, platform2, context, ids) {
15608
+ const baseInput = {
15609
+ knowledge_store_id: context.knowledgeStoreId,
15610
+ space_id: context.spaceId
15611
+ };
15612
+ switch (platform2) {
15613
+ case "github":
15614
+ return client.docImports.importGithubFiles.mutate({ ...baseInput, file_ids: ids });
15615
+ case "gitlab":
15616
+ return client.docImports.importGitlabFiles.mutate({ ...baseInput, file_ids: ids });
15617
+ case "azure_devops":
15618
+ return client.docImports.importAzureDevopsFiles.mutate({ ...baseInput, file_ids: ids });
15619
+ case "confluence":
15620
+ return client.docImports.importConfluencePages.mutate({ ...baseInput, page_ids: ids });
15621
+ case "notion":
15622
+ return client.docImports.importNotionPages.mutate({ ...baseInput, page_ids: ids });
15623
+ case "coda":
15624
+ return client.docImports.importCodaPages.mutate({ ...baseInput, page_ids: ids });
15625
+ default: {
15626
+ const unsupported = platform2;
15627
+ throw new Error(`Unsupported import platform: ${unsupported}`);
15628
+ }
15629
+ }
15630
+ }
15631
+
15632
+ // src/commands/docs.ts
15528
15633
  function requireConfig5() {
15529
15634
  const cfg = requireLoginConfig();
15530
15635
  if (!cfg.active_account?.target?.space_id) {
@@ -15614,6 +15719,9 @@ async function backendPost2(path3, apiKey, body) {
15614
15719
  headers: { "Content-Type": "application/json", "X-Dosu-API-Key": apiKey },
15615
15720
  body: JSON.stringify(body)
15616
15721
  });
15722
+ return parseBackendResponse2(resp);
15723
+ }
15724
+ async function parseBackendResponse2(resp) {
15617
15725
  if (!resp.ok) {
15618
15726
  let detail = `Request failed with status ${resp.status}`;
15619
15727
  try {
@@ -15626,15 +15734,15 @@ async function backendPost2(path3, apiKey, body) {
15626
15734
  }
15627
15735
  function docsCommand() {
15628
15736
  const cmd = new Command("docs").description("Document management");
15629
- cmd.command("list").description("List documents").option("--search <query>", "Search documents").option("--tag <id>", "Filter by tag ID").option("--limit <n>", "Maximum results", "20").option("--json", "Output as JSON").action(async (opts) => {
15737
+ cmd.command("list").description("List documents").option("--search <query>", "Search documents").option("--topic <id>", "Filter by topic ID").addOption(new Option("--limit <n>", "Maximum results").argParser(positiveInteger).default(20)).option("--json", "Output as JSON").action(async (opts) => {
15630
15738
  const cfg = requireConfig5();
15631
15739
  const client = createTypedClient(cfg);
15632
15740
  const ksId = await getKnowledgeStoreId(client, cfg.active_account.target.space_id);
15633
15741
  const result = await client.page.listWithTags.query({
15634
15742
  knowledge_store_id: ksId,
15635
15743
  searchTerm: opts.search,
15636
- topic_id: opts.tag,
15637
- limit: Number.parseInt(opts.limit ?? "20", 10)
15744
+ topic_id: opts.topic,
15745
+ limit: opts.limit
15638
15746
  });
15639
15747
  const pages = result.data;
15640
15748
  if (opts.json) {
@@ -15652,12 +15760,12 @@ function docsCommand() {
15652
15760
  formatDate(p2.created_at)
15653
15761
  ]), { rawData: pages });
15654
15762
  });
15655
- cmd.command("get").description("Get a document").argument("<id>", "Page ID").option("--version <v>", "Specific version number").option("--json", "Output as JSON").action(async (id, opts) => {
15763
+ cmd.command("get").description("Get a document").argument("<id>", "Page ID").addOption(new Option("--revision <n>", "Specific revision number").argParser(positiveInteger)).option("--json", "Output as JSON").action(async (id, opts) => {
15656
15764
  const cfg = requireConfig5();
15657
15765
  const client = createTypedClient(cfg);
15658
15766
  const page = await client.page.get.query({
15659
15767
  page_id: id,
15660
- version: opts.version ? Number.parseInt(opts.version, 10) : undefined
15768
+ version: opts.revision
15661
15769
  });
15662
15770
  if (opts.json) {
15663
15771
  printResult(page, opts);
@@ -15678,7 +15786,7 @@ function docsCommand() {
15678
15786
  ${page.body}`);
15679
15787
  }
15680
15788
  });
15681
- cmd.command("create").description("Create a new document").requiredOption("--title <title>", "Document title").option("--body <markdown>", "Document body (markdown)").option("--body-file <path>", "Read body from file").option("--json", "Output as JSON").action(async (opts) => {
15789
+ cmd.command("create").description("Create a new document").requiredOption("--title <title>", "Document title").option("--body <markdown>", "Document body (markdown)").addOption(new Option("--body-file <path>", "Read body from file").conflicts("body")).option("--json", "Output as JSON").action(async (opts) => {
15682
15790
  const cfg = requireConfig5();
15683
15791
  const client = createTypedClient(cfg);
15684
15792
  const ksId = await getKnowledgeStoreId(client, cfg.active_account.target.space_id);
@@ -15694,19 +15802,22 @@ ${page.body}`);
15694
15802
  }
15695
15803
  console.log(import_picocolors11.default.green(`Document "${opts.title}" created.`));
15696
15804
  });
15697
- cmd.command("update").description("Update a document").argument("<id>", "Page ID").option("--title <title>", "New title").option("--body <markdown>", "New body (markdown)").option("--body-file <path>", "Read body from file").option("--json", "Output as JSON").action(async (id, opts) => {
15805
+ cmd.command("update").description("Update a document").argument("<id>", "Page ID").option("--title <title>", "New title").option("--body <markdown>", "New body (markdown)").addOption(new Option("--body-file <path>", "Read body from file").conflicts("body")).option("--json", "Output as JSON").action(async (id, opts) => {
15806
+ if (opts.title === undefined && opts.body === undefined && opts.bodyFile === undefined) {
15807
+ throw new Error("Specify at least one of --title, --body, or --body-file.");
15808
+ }
15698
15809
  const cfg = requireConfig5();
15699
15810
  const client = createTypedClient(cfg);
15700
15811
  const ksId = await getKnowledgeStoreId(client, cfg.active_account.target.space_id);
15701
15812
  const body = readBody(opts);
15702
- const result = await client.page.update.mutate({
15813
+ await client.page.update.mutate({
15703
15814
  id,
15704
15815
  knowledge_store_id: ksId,
15705
15816
  title: opts.title,
15706
15817
  body
15707
15818
  });
15708
15819
  if (opts.json) {
15709
- printResult(result, opts);
15820
+ printResult({ success: true, id }, opts);
15710
15821
  return;
15711
15822
  }
15712
15823
  console.log(import_picocolors11.default.green("Document updated."));
@@ -15751,18 +15862,18 @@ ${page.body}`);
15751
15862
  formatDate(v.created_at)
15752
15863
  ]), { rawData: versions });
15753
15864
  });
15754
- cmd.command("restore").description("Restore a document version").argument("<id>", "Page ID").requiredOption("--version <n>", "Version number to restore").option("--json", "Output as JSON").action(async (id, opts) => {
15865
+ cmd.command("restore").description("Restore a document version").argument("<id>", "Page ID").addOption(new Option("--revision <n>", "Revision number to restore").argParser(positiveInteger).makeOptionMandatory()).option("--json", "Output as JSON").action(async (id, opts) => {
15755
15866
  const cfg = requireConfig5();
15756
15867
  const client = createTypedClient(cfg);
15757
15868
  await client.page.restoreVersion.mutate({
15758
15869
  page_id: id,
15759
- version_to_restore: Number.parseInt(opts.version, 10)
15870
+ version_to_restore: opts.revision
15760
15871
  });
15761
15872
  if (opts.json) {
15762
- printResult({ success: true, id, version: opts.version }, opts);
15873
+ printResult({ success: true, id, revision: opts.revision }, opts);
15763
15874
  return;
15764
15875
  }
15765
- console.log(import_picocolors11.default.green(`Document restored to version ${opts.version}.`));
15876
+ console.log(import_picocolors11.default.green(`Document restored to version ${opts.revision}.`));
15766
15877
  });
15767
15878
  cmd.command("generate").description("Generate a document using AI").requiredOption("--title <title>", "Document title").option("--instructions <text>", "Custom generation instructions").option("--json", "Output as JSON").action(async (opts) => {
15768
15879
  const cfg = requireConfig5();
@@ -15788,31 +15899,19 @@ ${page.body}`);
15788
15899
  }
15789
15900
  console.log(import_picocolors11.default.green("Auto-tagging started."));
15790
15901
  });
15791
- cmd.command("import").description("Import documents from an external platform").argument("<platform>", "Platform: github, gitlab, azure_devops, confluence, notion, coda").requiredOption("--files <ids>", "Comma-separated file/page IDs to import").option("--json", "Output as JSON").action(async (platform2, opts) => {
15902
+ cmd.command("import").description("Import documents from an external platform").addArgument(new Argument("<platform>", "Import platform").choices([...IMPORT_PLATFORMS])).requiredOption("--files <ids>", "Comma-separated file/page IDs to import").option("--json", "Output as JSON").action(async (platform2, opts) => {
15792
15903
  const cfg = requireConfig5();
15793
15904
  const client = createTypedClient(cfg);
15794
15905
  const ksId = await getKnowledgeStoreId(client, cfg.active_account.target.space_id);
15795
- const fileIds = opts.files.split(",").map((id) => id.trim());
15796
- const importFn = {
15797
- github: (input) => client.docImports.importGithubFiles.mutate(input),
15798
- gitlab: (input) => client.docImports.importGitlabFiles.mutate(input),
15799
- azure_devops: (input) => client.docImports.importAzureDevopsFiles.mutate(input),
15800
- confluence: (input) => client.docImports.importConfluencePages.mutate(input),
15801
- notion: (input) => client.docImports.importNotionPages.mutate(input),
15802
- coda: (input) => client.docImports.importCodaPages.mutate(input)
15803
- };
15804
- const fn = importFn[platform2.toLowerCase()];
15805
- if (!fn) {
15806
- console.error(import_picocolors11.default.red(`Unknown platform: ${platform2}. Use: github, gitlab, azure_devops, confluence, notion, coda`));
15807
- process.exit(1);
15906
+ const fileIds = opts.files.split(",").map((id) => id.trim()).filter(Boolean);
15907
+ if (fileIds.length === 0) {
15908
+ throw new Error("--files must contain at least one file or page ID.");
15808
15909
  }
15809
- const idField = ["confluence", "notion", "coda"].includes(platform2.toLowerCase()) ? "page_ids" : "file_ids";
15810
15910
  try {
15811
- const result = await fn({
15812
- knowledge_store_id: ksId,
15813
- space_id: cfg.active_account.target.space_id,
15814
- [idField]: fileIds
15815
- });
15911
+ const result = await importDocuments(client, platform2, {
15912
+ knowledgeStoreId: ksId,
15913
+ spaceId: cfg.active_account.target.space_id
15914
+ }, fileIds);
15816
15915
  if (opts.json) {
15817
15916
  printResult(result, opts);
15818
15917
  return;
@@ -15836,10 +15935,10 @@ ${page.body}`);
15836
15935
  process.exit(1);
15837
15936
  }
15838
15937
  });
15839
- cmd.command("import-status").description("Check import task status").argument("<task-id>", "Import task ID").option("--json", "Output as JSON").action(async (taskId, opts) => {
15938
+ cmd.command("import-status").description("Check import task status").addArgument(new Argument("<task-id>", "Import task ID").argParser(uuid)).option("--json", "Output as JSON").action(async (taskId, opts) => {
15840
15939
  const cfg = requireConfig5();
15841
- const client = createTypedClient(cfg);
15842
- const status = await client.docImports.getImportStatus.query(taskId);
15940
+ const response = await new Client(cfg).get(`/doc-imports/status/${encodeURIComponent(taskId)}`);
15941
+ const status = response.status === 404 ? null : await parseBackendResponse2(response);
15843
15942
  if (opts.json) {
15844
15943
  printResult(status, opts);
15845
15944
  return;
@@ -15946,17 +16045,25 @@ function requireConfig6() {
15946
16045
  }
15947
16046
  return cfg;
15948
16047
  }
16048
+ var DISPLAY_PLATFORMS = [
16049
+ "github",
16050
+ "gitlab",
16051
+ "azure_devops",
16052
+ "slack",
16053
+ "confluence",
16054
+ "notion",
16055
+ "coda",
16056
+ "teams"
16057
+ ];
15949
16058
  var NANGO_PROBES = {
15950
16059
  gitlab: [
15951
16060
  { provider: "gitlab", providerConfigKey: "gitlab" },
15952
16061
  { provider: "gitlab", providerConfigKey: "gitlab-pat" }
15953
16062
  ],
15954
- "gitlab-pat": [{ provider: "gitlab", providerConfigKey: "gitlab-pat" }],
15955
16063
  confluence: [
15956
16064
  { provider: "confluence", providerConfigKey: "confluence" },
15957
16065
  { provider: "confluence", providerConfigKey: "confluence-basic" }
15958
16066
  ],
15959
- "confluence-basic": [{ provider: "confluence", providerConfigKey: "confluence-basic" }],
15960
16067
  notion: [{ provider: "notion", providerConfigKey: "notion" }],
15961
16068
  coda: [{ provider: "coda", providerConfigKey: "coda" }],
15962
16069
  azure_devops: [
@@ -15964,32 +16071,20 @@ var NANGO_PROBES = {
15964
16071
  { provider: "azure_devops", providerConfigKey: "azure-devops" }
15965
16072
  ]
15966
16073
  };
15967
- var DISPLAY_PLATFORMS = [
15968
- "github",
15969
- "gitlab",
15970
- "azure_devops",
15971
- "slack",
15972
- "confluence",
15973
- "notion",
15974
- "coda",
15975
- "teams"
15976
- ];
15977
16074
  async function probeConnection(client, orgId, platform4) {
15978
16075
  const probes = NANGO_PROBES[platform4];
15979
16076
  if (!probes) {
15980
- return { queryable: false, connected: false, connection: null };
16077
+ return { queryable: false, connected: null, connection: null };
15981
16078
  }
15982
16079
  for (const probe of probes) {
15983
- try {
15984
- const conn = await client.nango.getConnection.query({
15985
- provider: probe.provider,
15986
- providerConfigKey: probe.providerConfigKey,
15987
- orgId
15988
- });
15989
- if (conn != null) {
15990
- return { queryable: true, connected: true, connection: conn };
15991
- }
15992
- } catch {}
16080
+ const conn = await client.nango.getConnection.query({
16081
+ provider: probe.provider,
16082
+ providerConfigKey: probe.providerConfigKey,
16083
+ orgId
16084
+ });
16085
+ if (conn != null) {
16086
+ return { queryable: true, connected: true, connection: conn };
16087
+ }
15993
16088
  }
15994
16089
  return { queryable: true, connected: false, connection: null };
15995
16090
  }
@@ -16008,19 +16103,19 @@ function integrationsCommand() {
16008
16103
  }
16009
16104
  printTable(["Platform", "Status"], results.map((r2) => [
16010
16105
  r2.platform,
16011
- r2.connected ? import_picocolors15.default.green("connected") : import_picocolors15.default.dim("not connected")
16106
+ r2.connected === null ? import_picocolors15.default.dim("status unavailable") : r2.connected ? import_picocolors15.default.green("connected") : import_picocolors15.default.dim("not connected")
16012
16107
  ]), { rawData: results });
16013
16108
  });
16014
- 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) => {
16109
+ cmd.command("status").description("Check connection status of a specific platform").addArgument(new Argument("<platform>", "Integration platform").choices([...DISPLAY_PLATFORMS])).option("--json", "Output as JSON").action(async (platform4, opts) => {
16015
16110
  const cfg = requireConfig6();
16016
16111
  const client = createTypedClient(cfg);
16017
16112
  const { queryable, connected, connection } = await probeConnection(client, cfg.active_account.target.org_id, platform4);
16018
16113
  if (!queryable) {
16019
16114
  if (opts.json) {
16020
- printResult({ platform: platform4, connected: false, note: "not queryable via nango" }, opts);
16115
+ printResult({ platform: platform4, connected: null, note: "connection status unavailable via CLI" }, opts);
16021
16116
  return;
16022
16117
  }
16023
- console.log(`${platform4}: ${import_picocolors15.default.dim("not connected (not queryable)")}`);
16118
+ console.log(`${platform4}: ${import_picocolors15.default.dim("connection status unavailable via CLI")}`);
16024
16119
  return;
16025
16120
  }
16026
16121
  if (opts.json) {
@@ -16056,10 +16151,10 @@ function integrationsCommand() {
16056
16151
  }
16057
16152
  console.log(import_picocolors15.default.green(`Joined Slack channel ${channelId}.`));
16058
16153
  });
16059
- cmd.command("github-collaborators").description("List GitHub repository collaborators").option("--json", "Output as JSON").action(async (opts) => {
16154
+ cmd.command("github-collaborators").description("List GitHub repository collaborators").addArgument(new Argument("<repository-id>", "Numeric GitHub repository ID").argParser(positiveInteger)).option("--json", "Output as JSON").action(async (repositoryId, opts) => {
16060
16155
  const cfg = requireConfig6();
16061
16156
  const client = createTypedClient(cfg);
16062
- const collaborators = await client.githubRepository.getCollaborators.query(0);
16157
+ const collaborators = await client.githubRepository.getCollaborators.query(repositoryId);
16063
16158
  if (opts.json) {
16064
16159
  printResult(collaborators, opts);
16065
16160
  return;
@@ -16087,7 +16182,7 @@ function requireConfig7() {
16087
16182
  }
16088
16183
  function knowledgeCommand() {
16089
16184
  const cmd = new Command("knowledge").description("Search and browse your knowledge base");
16090
- cmd.command("search").description("Search the knowledge base").argument("<query>", "Search query").option("--json", "Output as JSON").option("--limit <n>", "Maximum results", "10").action(async (query, opts) => {
16185
+ cmd.command("search").description("Search the knowledge base").argument("<query>", "Search query").option("--json", "Output as JSON").addOption(new Option("--limit <n>", "Maximum results").argParser(positiveInteger).default(10)).action(async (query, opts) => {
16091
16186
  const cfg = requireConfig7();
16092
16187
  const client = createTypedClient(cfg);
16093
16188
  const dataSources = await client.dataSource.list.query({
@@ -16113,15 +16208,14 @@ function knowledgeCommand() {
16113
16208
  console.log(import_picocolors16.default.dim("No results found."));
16114
16209
  return;
16115
16210
  }
16116
- const limit = Number.parseInt(opts.limit ?? "10", 10);
16117
- const limited = results.slice(0, limit);
16211
+ const limited = results.slice(0, opts.limit);
16118
16212
  printTable(["Title", "Type"], limited.map((r2) => [
16119
16213
  truncate(r2.title ?? "(untitled)", 60),
16120
16214
  r2.entity_type ?? "—"
16121
16215
  ]), { json: false, rawData: limited });
16122
- if (results.length > limit) {
16216
+ if (results.length > opts.limit) {
16123
16217
  console.log(import_picocolors16.default.dim(`
16124
- ${results.length - limit} more results not shown.`));
16218
+ ${results.length - opts.limit} more results not shown.`));
16125
16219
  }
16126
16220
  });
16127
16221
  cmd.command("list").description("Show knowledge store information").option("--json", "Output as JSON").action(async (opts) => {
@@ -16156,28 +16250,11 @@ function requireConfig8() {
16156
16250
  return cfg;
16157
16251
  }
16158
16252
  function membersCommand() {
16159
- const cmd = new Command("members").description("Manage team members");
16160
- cmd.command("list").description("List team members and invitations").option("--json", "Output as JSON").action(async (opts) => {
16253
+ const cmd = new Command("members").description("Invite organization members");
16254
+ cmd.command("invite").description("Invite a member to the organization").argument("<email>", "Email address to invite").addOption(new Option("--role <role>", "Organization role").choices(["admin", "member"]).default("member")).option("--json", "Output as JSON").action(async (email, opts) => {
16161
16255
  const cfg = requireConfig8();
16162
16256
  const client = createTypedClient(cfg);
16163
- const data = await client.invitations.getInvitations.query();
16164
- if (opts.json) {
16165
- printResult(data, opts);
16166
- return;
16167
- }
16168
- if (!data.items || data.items.length === 0) {
16169
- console.log(import_picocolors17.default.dim("No members or invitations found."));
16170
- return;
16171
- }
16172
- printTable(["Email", "Org"], data.items.map((m3) => [
16173
- m3.email ?? "—",
16174
- m3.org?.name ?? "—"
16175
- ]), { rawData: data });
16176
- });
16177
- cmd.command("invite").description("Invite a member to the organization").argument("<email>", "Email address to invite").option("--role <role>", "Role: admin or member", "member").option("--json", "Output as JSON").action(async (email, opts) => {
16178
- const cfg = requireConfig8();
16179
- const client = createTypedClient(cfg);
16180
- const role = opts.role.toUpperCase() === "ADMIN" ? "ADMIN" : "MEMBER";
16257
+ const role = opts.role === "admin" ? "ADMIN" : "MEMBER";
16181
16258
  await client.invitations.invite.mutate({
16182
16259
  orgId: cfg.active_account.target.org_id,
16183
16260
  email,
@@ -16189,49 +16266,6 @@ function membersCommand() {
16189
16266
  }
16190
16267
  console.log(import_picocolors17.default.green(`Invitation sent to ${email} as ${role}.`));
16191
16268
  });
16192
- cmd.command("requests").description("List pending access requests").option("--json", "Output as JSON").action(async (opts) => {
16193
- const cfg = requireConfig8();
16194
- const client = createTypedClient(cfg);
16195
- const data = await client.invitations.getInvitations.query();
16196
- if (opts.json) {
16197
- printResult(data, opts);
16198
- return;
16199
- }
16200
- if (!data.items || data.items.length === 0) {
16201
- console.log(import_picocolors17.default.dim("No pending access requests."));
16202
- return;
16203
- }
16204
- printTable(["Email", "Org"], data.items.map((r2) => [
16205
- r2.email ?? "—",
16206
- r2.org?.name ?? "—"
16207
- ]), { rawData: data });
16208
- });
16209
- cmd.command("approve").description("Approve an access request").argument("<email>", "Email of requester").option("--json", "Output as JSON").action(async (email, opts) => {
16210
- const cfg = requireConfig8();
16211
- const client = createTypedClient(cfg);
16212
- await client.invitations.acceptInvitation.mutate({
16213
- orgId: cfg.active_account.target.org_id,
16214
- email
16215
- });
16216
- if (opts.json) {
16217
- printResult({ success: true, email, action: "approved" }, opts);
16218
- return;
16219
- }
16220
- console.log(import_picocolors17.default.green(`Access request from ${email} approved.`));
16221
- });
16222
- cmd.command("deny").description("Deny an access request").argument("<email>", "Email of requester").option("--json", "Output as JSON").action(async (email, opts) => {
16223
- const cfg = requireConfig8();
16224
- const client = createTypedClient(cfg);
16225
- await client.invitations.rejectInvitation.mutate({
16226
- orgId: cfg.active_account.target.org_id,
16227
- email
16228
- });
16229
- if (opts.json) {
16230
- printResult({ success: true, email, action: "denied" }, opts);
16231
- return;
16232
- }
16233
- console.log(import_picocolors17.default.green(`Access request from ${email} denied.`));
16234
- });
16235
16269
  return cmd;
16236
16270
  }
16237
16271
 
@@ -16445,7 +16479,7 @@ function reviewCommand() {
16445
16479
  console.log("");
16446
16480
  console.log(change.diff);
16447
16481
  });
16448
- cmd.command("edit").description("Edit a pending review item in place (doc body/title, or draft reply body)").argument("<id>", "Review item ID (from `dosu review list`)").option("--title <title>", "New title").option("--body <markdown>", "New body (markdown)").option("--body-file <path>", "Read body from file").option("--json", "Output as JSON").action(async (id, opts) => {
16482
+ cmd.command("edit").description("Edit a pending doc or Dosu App draft in place").argument("<id>", "Review item ID (from `dosu review list`)").option("--title <title>", "New title").option("--body <markdown>", "New body (markdown)").option("--body-file <path>", "Read body from file").option("--json", "Output as JSON").action(async (id, opts) => {
16449
16483
  const cfg = requireConfig10();
16450
16484
  const client = createTypedClient(cfg);
16451
16485
  if (opts.body !== undefined && opts.bodyFile !== undefined) {
@@ -16470,6 +16504,10 @@ function reviewCommand() {
16470
16504
  console.error(import_picocolors19.default.red("Draft replies support --body only (no --title)."));
16471
16505
  process.exit(1);
16472
16506
  }
16507
+ if (body === undefined) {
16508
+ console.error(import_picocolors19.default.red("Draft replies require --body or --body-file."));
16509
+ process.exit(1);
16510
+ }
16473
16511
  await requireDraft(client, id);
16474
16512
  await client.messages.saveDraft.mutate({
16475
16513
  messageId: bareMessageId(id),
@@ -16574,7 +16612,7 @@ function reviewCommand() {
16574
16612
  console.log(import_picocolors19.default.green(`Review ${name}: ${truncateId(id)}`));
16575
16613
  });
16576
16614
  }
16577
- 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) => {
16615
+ cmd.command("revert").description("Reopen a previously accepted or declined doc change for review").argument("<id>", "Page version ID (not a pending item from `dosu review list`)").option("--json", "Output as JSON").action(async (id, opts) => {
16578
16616
  const cfg = requireConfig10();
16579
16617
  const client = createTypedClient(cfg);
16580
16618
  if (isDraftId(id)) {
@@ -16667,6 +16705,9 @@ function sourcesCommand() {
16667
16705
  console.log(import_picocolors20.default.green(`Data source sync triggered for ${id.slice(0, 8)}.`));
16668
16706
  });
16669
16707
  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) => {
16708
+ if (opts.name === undefined && opts.description === undefined) {
16709
+ throw new Error("Specify at least one of --name or --description.");
16710
+ }
16670
16711
  const cfg = requireConfig11();
16671
16712
  const client = createTypedClient(cfg);
16672
16713
  const result = await client.dataSource.update.mutate({
@@ -16695,8 +16736,37 @@ function sourcesCommand() {
16695
16736
 
16696
16737
  // src/commands/suggest.ts
16697
16738
  init_commander();
16698
- init_trpc();
16699
16739
  var import_picocolors21 = __toESM(require_picocolors(), 1);
16740
+
16741
+ // src/client/supabase.ts
16742
+ async function listSpaceDataSourceIds(config, spaceId) {
16743
+ const accessToken = config.active_account?.session.access_token;
16744
+ if (!accessToken)
16745
+ throw new Error("Not logged in. Run 'dosu login' first.");
16746
+ const endpoint = new URL("/rest/v1/space_data_source", getSupabaseURL());
16747
+ endpoint.searchParams.set("select", "data_source_id");
16748
+ endpoint.searchParams.set("space_id", `eq.${spaceId}`);
16749
+ const response = await fetch(endpoint, {
16750
+ headers: {
16751
+ apikey: getSupabaseAnonKey(),
16752
+ Authorization: `Bearer ${accessToken}`
16753
+ }
16754
+ });
16755
+ if (!response.ok) {
16756
+ throw new Error(`Failed to list this deployment's data sources (status ${response.status}).`);
16757
+ }
16758
+ const rows = await response.json();
16759
+ if (!Array.isArray(rows) || rows.some((row) => !isDataSourceLink(row))) {
16760
+ throw new Error("Supabase returned an invalid space_data_source response.");
16761
+ }
16762
+ return rows.map((row) => row.data_source_id);
16763
+ }
16764
+ function isDataSourceLink(value) {
16765
+ return value !== null && typeof value === "object" && "data_source_id" in value && typeof value.data_source_id === "string";
16766
+ }
16767
+
16768
+ // src/commands/suggest.ts
16769
+ init_trpc();
16700
16770
  function requireConfig12() {
16701
16771
  const cfg = requireLoginConfig();
16702
16772
  if (!cfg.active_account?.target?.space_id) {
@@ -16741,15 +16811,10 @@ function suggestCommand() {
16741
16811
  const cfg = requireConfig12();
16742
16812
  const client = createTypedClient(cfg);
16743
16813
  const ksId = await getKnowledgeStoreId3(client, cfg.active_account.target.space_id);
16744
- if (!cfg.active_account?.target?.org_id) {
16745
- console.error(import_picocolors21.default.red("Missing org config. Run 'dosu setup' to reconfigure."));
16746
- process.exit(1);
16814
+ const dataSourceIds = await listSpaceDataSourceIds(cfg, cfg.active_account.target.space_id);
16815
+ if (dataSourceIds.length === 0) {
16816
+ throw new Error("No data sources are connected to the active deployment.");
16747
16817
  }
16748
- const dataSources = await client.dataSource.list.query({
16749
- org_id: cfg.active_account?.target?.org_id,
16750
- excluded_provider_slugs: []
16751
- });
16752
- const dataSourceIds = dataSources.map((ds) => ds.id).filter((id) => id !== null);
16753
16818
  const result = await client.suggestedDoc.generate.mutate({
16754
16819
  knowledgeStoreId: ksId,
16755
16820
  dataSourceIds
@@ -16852,7 +16917,11 @@ function requireConfig13() {
16852
16917
  }
16853
16918
  function threadsCommand() {
16854
16919
  const cmd = new Command("threads").description("List and manage conversation threads");
16855
- cmd.command("list").description("List threads").option("--status <status>", "Filter by status: pending, resolved, archived").option("--search <query>", "Search threads").option("--limit <n>", "Maximum results (default: 20)", "20").option("--json", "Output as JSON").action(async (opts) => {
16920
+ cmd.command("list").description("List threads").addOption(new Option("--status <status>", "Filter by status").choices([
16921
+ "pending",
16922
+ "resolved",
16923
+ "archived"
16924
+ ])).option("--search <query>", "Search threads").addOption(new Option("--limit <n>", "Maximum results (default: 20; max: 100)").argParser(positiveIntegerAtMost(100)).default(20)).option("--json", "Output as JSON").action(async (opts) => {
16856
16925
  const cfg = requireConfig13();
16857
16926
  const client = createTypedClient(cfg);
16858
16927
  const input = {
@@ -16870,7 +16939,7 @@ function threadsCommand() {
16870
16939
  search: undefined,
16871
16940
  space_id: cfg.active_account.target.space_id,
16872
16941
  workspaces: undefined,
16873
- limit: Math.min(Number.parseInt(opts.limit ?? "20", 10), 100)
16942
+ limit: opts.limit
16874
16943
  };
16875
16944
  if (opts.search)
16876
16945
  input.search = opts.search;
@@ -16902,14 +16971,14 @@ function threadsCommand() {
16902
16971
  formatDate(t2.created_at)
16903
16972
  ]), { rawData: threads });
16904
16973
  });
16905
- cmd.command("get").description("View a thread and its messages").argument("<id>", "Thread ID").option("--limit <n>", "Number of messages to show (default: 20)", "20").option("--json", "Output as JSON").action(async (id, opts) => {
16974
+ cmd.command("get").description("View a thread and its messages").argument("<id>", "Thread ID").addOption(new Option("--limit <n>", "Number of messages to show (default: 20; -1 for all)").argParser(messageLimit).default(20)).option("--json", "Output as JSON").action(async (id, opts) => {
16906
16975
  const cfg = requireConfig13();
16907
16976
  const client = createTypedClient(cfg);
16908
16977
  const [thread, messagesData] = await Promise.all([
16909
16978
  client.thread.get.query(id),
16910
16979
  client.messages.list.query({
16911
16980
  thread_id: id,
16912
- limit: Number.parseInt(opts.limit ?? "20", 10)
16981
+ limit: opts.limit
16913
16982
  })
16914
16983
  ]);
16915
16984
  if (opts.json) {
@@ -16980,7 +17049,7 @@ async function getKnowledgeStoreId4(client, spaceId) {
16980
17049
  return store.id;
16981
17050
  }
16982
17051
  function topicsCommand() {
16983
- const cmd = new Command("topics").alias("tags").description("Browse Topics in your knowledge base");
17052
+ const cmd = new Command("topics").description("Browse Topics in your knowledge base");
16984
17053
  cmd.command("list").description("List all topics").option("--json", "Output as JSON").action(async (opts) => {
16985
17054
  const cfg = requireConfig14();
16986
17055
  const client = createTypedClient(cfg);
@@ -17002,7 +17071,7 @@ function topicsCommand() {
17002
17071
  t2.description ?? "—"
17003
17072
  ]), { rawData: topics });
17004
17073
  });
17005
- cmd.command("pages").description("List pages with a specific topic").argument("<topic-id>", "Topic ID").option("--search <query>", "Search within the topic's pages").option("--limit <n>", "Maximum results", "10").option("--json", "Output as JSON").action(async (topicId, opts) => {
17074
+ cmd.command("pages").description("List pages with a specific topic").argument("<topic-id>", "Topic ID").option("--search <query>", "Search within the topic's pages").addOption(new Option("--limit <n>", "Maximum results").argParser(positiveInteger).default(10)).option("--json", "Output as JSON").action(async (topicId, opts) => {
17006
17075
  const cfg = requireConfig14();
17007
17076
  const client = createTypedClient(cfg);
17008
17077
  const ksId = await getKnowledgeStoreId4(client, cfg.active_account.target.space_id);
@@ -17010,7 +17079,7 @@ function topicsCommand() {
17010
17079
  knowledge_store_id: ksId,
17011
17080
  topic_id: topicId,
17012
17081
  searchTerm: opts.search,
17013
- limit: Number.parseInt(opts.limit ?? "10", 10)
17082
+ limit: opts.limit
17014
17083
  });
17015
17084
  const pages = result.data;
17016
17085
  if (opts.json) {
@@ -17884,4 +17953,4 @@ execute().catch((err) => {
17884
17953
  process.exit(1);
17885
17954
  });
17886
17955
 
17887
- //# debugId=d08d0e8f-b86e-9699-6475-6e2164756e21
17956
+ //# debugId=0e1efd83-4f86-ddb7-6475-6e2164756e21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dosu/cli",
3
- "version": "0.49.3",
3
+ "version": "0.49.4",
4
4
  "type": "module",
5
5
  "description": "Dosu CLI - Manage MCP servers for AI tools",
6
6
  "license": "MIT",