@dosu/cli 0.58.1 → 0.59.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +8 -2
  2. package/bin/dosu.js +1159 -345
  3. package/package.json +2 -1
package/bin/dosu.js CHANGED
@@ -1083,7 +1083,7 @@ function isNpxInvocation(channel = INSTALL_CHANNEL, env = process.env) {
1083
1083
  function getVersionString() {
1084
1084
  return `v${VERSION}`;
1085
1085
  }
1086
- var VERSION = "0.58.1", INSTALL_CHANNEL = "npm";
1086
+ var VERSION = "0.59.0", INSTALL_CHANNEL = "npm";
1087
1087
 
1088
1088
  // src/debug/logger.ts
1089
1089
  import {
@@ -13742,7 +13742,7 @@ var init_sync = __esm(() => {
13742
13742
  });
13743
13743
 
13744
13744
  // src/telemetry/debug-id.ts
13745
- var BUNDLE_DEBUG_ID_PLACEHOLDER = "9cb59d41-7339-0702-6475-6e2164756e21";
13745
+ var BUNDLE_DEBUG_ID_PLACEHOLDER = "ecb91fd5-693a-ffc0-6475-6e2164756e21";
13746
13746
 
13747
13747
  // src/telemetry/telemetry.ts
13748
13748
  import { randomUUID as randomUUID2 } from "node:crypto";
@@ -59799,255 +59799,1036 @@ var init_review = __esm(() => {
59799
59799
  import_picocolors25 = __toESM(require_picocolors(), 1);
59800
59800
  });
59801
59801
 
59802
- // src/version/skill-update-check.ts
59803
- import { existsSync as existsSync19, mkdirSync as mkdirSync11, readFileSync as readFileSync19, writeFileSync as writeFileSync12 } from "node:fs";
59804
- import { join as join22 } from "node:path";
59805
- function getCachePath2() {
59806
- return join22(getConfigDir(), CACHE_FILENAME3);
59802
+ // src/generated/skills.ts
59803
+ var BUNDLED_SKILLS;
59804
+ var init_skills = __esm(() => {
59805
+ BUNDLED_SKILLS = [
59806
+ {
59807
+ name: "dosu",
59808
+ files: [
59809
+ {
59810
+ path: "SKILL.md",
59811
+ content: "---\nname: dosu\ndescription: 'Use the Dosu CLI to authenticate and configure coding agents; manage Libraries, Agents, sources, Monitor, documents, reviews, threads, topics, members, integrations, and deployments; query knowledge; or audit a repository for Dosu-generated docs. Use for Dosu platform work that should be done from a terminal instead of the web app.'\n---\n\n# Use the Dosu CLI\n\nOperate Dosu through `dosu`. Prefer structured output and let the CLI and App validate product rules.\n\n## Start correctly\n\n1. Run `dosu --version`. Do not probe installation with unrelated package-manager commands.\n2. If it is unavailable and Node is present, try `npx -y @dosu/cli --version` and use `npx -y @dosu/cli` as the command prefix for this session. Otherwise ask before installing anything.\n3. Run `dosu --help` or the relevant nested `--help` before using a command not covered by [the command reference](references/commands.md).\n4. Pass `--json` whenever that leaf command exposes it. Parse the result; do not scrape the human table.\n\n## Satisfy the right prerequisite\n\n- `dosu login` supplies the JWT used by tRPC-backed commands.\n- `dosu setup` selects an organization, Library context, and MCP deployment, creates an API key, and can configure an agent tool.\n- `dosu ask` needs an API key. `docs generate`, `docs auto-tag`, and `docs publish` need both JWT login and the API key. Other platform commands generally need JWT login; commands scoped to an organization or current Library also need the corresponding setup selection.\n- For coding-agent setup, follow the nonblocking `dosu setup --agent --tool <id>` workflow in [workflows.md](references/workflows.md). Relay its URL and execute its returned `resume_command`; never invent ticket commands.\n\n## Use current product terms\n\n- **Organization** is the account and permission boundary.\n- **Library** is the knowledge container shown in the App. Older APIs may call it a `space`; do not present that internal name to users.\n- **Data source** is an organization-level connection such as a repository, Slack channel, or Notion workspace. A Library can use already-connected sources.\n- **Agent** is a configurable GitHub, GitLab, Slack, or Teams deployment serving exactly one Library.\n- **Monitor** is per Library and source. It supports GitHub, GitLab, and Azure DevOps sources.\n- `dosu deployments` manages selectable **MCP deployments**. Do not use it as an Agent CRUD command.\n\n## Route by intent\n\n| Intent | Route |\n|---|---|\n| Set up Dosu end-to-end (\"set up dosu\", new Library from scratch) | Read the guided onboarding flow in [workflows.md](references/workflows.md) first; it is checkpoint-driven — ask, wait, then act |\n| Create or configure a Library | `dosu libraries ...` |\n| Attach existing organization sources | `dosu sources list` → `dosu libraries sources attach` |\n| Create or configure an Agent | `dosu agents ...` |\n| Ask for a synthesized answer | `dosu ask` |\n| Find source documents | `dosu knowledge search`, then `dosu docs get` |\n| Create, import, or publish docs | `dosu docs ...` |\n| Review a pending doc change or draft reply | Read [review-workflow.md](references/review-workflow.md) first |\n| Inspect conversations | `dosu threads ...` |\n| Browse managed topics | `dosu topics ...` |\n| Audit agent docs, README, architecture, or dependencies | Read [audit.md](references/audit.md) first |\n\nUse [commands.md](references/commands.md) as the sole detailed command and flag reference. Use [workflows.md](references/workflows.md) only for multi-command composition.\n\n## Apply Library and Agent semantics\n\n- To assemble a Library, list organization sources, create the Library, attach the chosen source IDs, then verify with `libraries info` and `libraries sources list`. The CLI cannot establish a brand-new OAuth connection.\n- `libraries sources config` resolves the provider on the App side. Read the command reference before choosing provider-specific options.\n- When creating a Library with a GitHub repository, or newly attaching one to an existing Library, treat Monitor as part of that setup unless the user opts out. Enable it with the whole-repository and `emoji` defaults, verify it, and explain that Monitor reviews pull requests to keep the Library's knowledge up to date. Follow [the Library workflow](references/workflows.md); do not ask the user to choose defaults.\n- Create an Agent from an existing source ID and let the App choose its defaults; do not synthesize config in shell commands. Each data source can back at most one Agent: a `CONFLICT` (409) from `agents create` means the source already has one — offer a different source or an authorized `agents move` instead of retrying.\n- Read Agent config before changing one existing leaf. Values are JSON. If a concurrent write returns `CONFLICT`, read again, re-evaluate the requested change, and retry only if it is still correct.\n- Moving an Agent replaces its Library. Verify the returned `space_id`; do not infer migration behavior for historical data from the move receipt.\n\n## Respect write boundaries\n\n- Treat an explicit, unambiguous user request for the exact mutation as authorization. Otherwise show the intended change and wait for confirmation.\n- For commands exposing `--confirm`, omit it first when a preview is useful; `{ \"confirmRequired\": true, \"applied\": false }` means nothing changed. Pass `--confirm` only after authorization.\n- Never batch-approve or batch-reject review items. Diff one item, explain it, and decide only the ID the user authorized.\n- Before deleting a Library, Agent, source, or document, state the exact target and impact. Before detaching a source, read and state the impact documented in the command reference. Some older delete commands do not enforce `--confirm`; the absence of a CLI prompt is not user approval.\n- Before attaching a source to a public Library, warn that its content becomes available to everyone who can access that Library.\n- OAuth connection and billing remain web-only. Report the boundary instead of claiming success.\n\n## Handle failures literally\n\n- `Not logged in` or an unrecoverable expired session: run `dosu login` (agent setup may instead return a ticket flow).\n- Missing organization, Library, deployment, or API-key context: run the appropriate `dosu setup` flow.\n- `confirmRequired`: no write occurred.\n- `CONFLICT` on config: reread before retrying.\n- A tRPC or backend error is a failed operation. Surface the code/path/status and do not imply the requested state exists.\n\n## References\n\n- [commands.md](references/commands.md): authoritative CLI syntax, choices, defaults, conflicts, and prerequisites\n- [workflows.md](references/workflows.md): reusable multi-command flows\n- [review-workflow.md](references/review-workflow.md): review safety and context\n- [audit.md](references/audit.md): repository audit procedure\n- [audit-findings-schema.md](references/audit-findings-schema.md): `.dosu/audit.json` contract\n",
59812
+ executable: false
59813
+ },
59814
+ {
59815
+ path: "references/audit-findings-schema.md",
59816
+ content: `# \`.dosu/audit.json\` — audit findings schema
59817
+
59818
+ The codebase audit (see [audit.md](audit.md)) writes its result to \`.dosu/audit.json\` at the
59819
+ repo root. This file is the contract between the audit you run in the coding agent and the
59820
+ \`dosu audit\` CLI command, which reads it, asks the user which docs to generate, and kicks off
59821
+ generation on Dosu cloud.
59822
+
59823
+ Write valid JSON matching this shape exactly. Do not add fields the CLI doesn't expect.
59824
+
59825
+ \`\`\`json
59826
+ {
59827
+ "version": 1,
59828
+ "generated_at": "2026-06-24T12:00:00Z",
59829
+ "repo": {
59830
+ "remote": "git@github.com:org/repo.git",
59831
+ "slug": "org/repo"
59832
+ },
59833
+ "items": [
59834
+ {
59835
+ "task": "generate-agents-md",
59836
+ "type": "agents",
59837
+ "file": "AGENTS.md",
59838
+ "status": "missing",
59839
+ "action": "create",
59840
+ "can_help": true,
59841
+ "confidence": "high",
59842
+ "rationale": "No AGENTS.md found; the repo has a clear src/ layout, a documented test command, and commit conventions worth capturing for agents.",
59843
+ "evidence": ["package.json", "src/cli/cli.ts", "CONTRIBUTING.md"]
59844
+ }
59845
+ ]
59846
+ }
59847
+ \`\`\`
59848
+
59849
+ ## Top-level fields
59850
+
59851
+ | Field | Type | Notes |
59852
+ |---|---|---|
59853
+ | \`version\` | number | Always \`1\`. The CLI rejects other versions. |
59854
+ | \`generated_at\` | string | ISO 8601 timestamp of when the audit ran. |
59855
+ | \`repo.remote\` | string | The \`git remote origin\` URL, verbatim. |
59856
+ | \`repo.slug\` | string | \`owner/name\` parsed from the remote (e.g. \`dosu-ai/dosu-cli\`). |
59857
+ | \`items\` | array | One entry per doc type you assessed. Include an entry for every type you looked at, even when \`can_help\` is \`false\` — the CLI uses these to explain what it skipped. |
59858
+
59859
+ ## Item fields
59860
+
59861
+ | Field | Type | Allowed values | Notes |
59862
+ |---|---|---|---|
59863
+ | \`task\` | string | \`generate-agents-md\`, \`refresh-readme\`, \`generate-architecture-md\`, \`generate-deps-md\` | The backend capability id this item maps to. Must be one of these exact strings. |
59864
+ | \`type\` | string | \`agents\`, \`readme\`, \`architecture\`, \`deps\` | Short doc-type key. |
59865
+ | \`file\` | string | — | The target filename in the repo (e.g. \`AGENTS.md\`, \`README.md\`, \`architecture.md\`, \`deps.md\`). Use the casing already present in the repo when updating an existing file. |
59866
+ | \`status\` | string | \`missing\`, \`outdated\`, \`present_ok\` | What you found in the working tree. |
59867
+ | \`action\` | string | \`create\`, \`update\`, \`skip\` | What Dosu should do. \`create\` when \`missing\`; \`update\` when \`outdated\`; \`skip\` when \`present_ok\` (or when not enough info). |
59868
+ | \`can_help\` | boolean | — | Whether Dosu should offer this. \`false\` ⇒ the CLI shows it as not recommended (or omits it). |
59869
+ | \`confidence\` | string | \`high\`, \`medium\`, \`low\` | Your confidence in the recommendation. |
59870
+ | \`rationale\` | string | — | One or two sentences explaining the recommendation, citing what you saw. This is passed to Dosu cloud as generation guidance, so make it specific. |
59871
+ | \`evidence\` | string[] | — | Repo-relative paths (and optionally \`path:line\`) that justify the finding. |
59872
+
59873
+ ## Mapping of \`task\` ↔ \`type\` ↔ \`file\`
59874
+
59875
+ | \`task\` | \`type\` | typical \`file\` |
59876
+ |---|---|---|
59877
+ | \`generate-agents-md\` | \`agents\` | \`AGENTS.md\` |
59878
+ | \`refresh-readme\` | \`readme\` | \`README.md\` |
59879
+ | \`generate-architecture-md\` | \`architecture\` | \`architecture.md\` |
59880
+ | \`generate-deps-md\` | \`deps\` | \`deps.md\` |
59881
+ `,
59882
+ executable: false
59883
+ },
59884
+ {
59885
+ path: "references/audit.md",
59886
+ content: `# Dosu codebase audit
59887
+
59888
+ This is the full procedure for the **codebase audit** referenced from [../SKILL.md](../SKILL.md).
59889
+ The goal: inspect the current repository and decide, with evidence, whether Dosu can help the
59890
+ user by creating or refreshing four docs. Write the result to \`.dosu/audit.json\`
59891
+ (see [audit-findings-schema.md](audit-findings-schema.md)), then tell the user to run
59892
+ \`dosu audit\` so the Dosu CLI can ask them which docs to generate and open a PR.
59893
+
59894
+ You (the coding agent) only do the **triage** here — you have the live working tree, so you can
59895
+ tell what exists, what's stale, and whether there's enough signal. You do **not** write the docs
59896
+ themselves; Dosu cloud generates them and opens the PR after the user picks via \`dosu audit\`.
59897
+
59898
+ ## When to run this
59899
+
59900
+ Run when the user asks Dosu to audit the repo, asks "what can Dosu do for this codebase?", or
59901
+ asks to set up / refresh their agent docs, README, architecture doc, or dependency doc.
59902
+
59903
+ ## The four doc types
59904
+
59905
+ | \`task\` | File | When Dosu can help |
59906
+ |---|---|---|
59907
+ | \`generate-agents-md\` | \`AGENTS.md\` | Missing, or present but stale/thin given the repo's structure, commands, and conventions. |
59908
+ | \`refresh-readme\` | \`README.md\` | Present but **outdated** — references removed scripts/deps, missing setup steps, or describes features that no longer match the code. |
59909
+ | \`generate-architecture-md\` | \`architecture.md\` | **Missing AND** there is genuinely enough structure to describe (multiple modules/services, clear layering). Do not recommend for a tiny or single-file repo. |
59910
+ | \`generate-deps-md\` | \`deps.md\` | Missing, or present but out of sync with the actual dependency manifests. |
59911
+
59912
+ ## Rules
59913
+
59914
+ - **Be evidence-based.** Prefer direct repo evidence over inference. Cite concrete \`evidence\`:
59915
+ file paths (and \`path:line\` where useful), manifest entries, config keys.
59916
+ - **Gate \`architecture.md\` strictly.** Only set \`can_help: true\` for \`generate-architecture-md\`
59917
+ when the repo is large/structured enough that a useful architecture doc can be written. When in
59918
+ doubt, set \`can_help: false\`, \`action: "skip"\`, and a \`rationale\` saying why.
59919
+ - **Distinguish status from action.** \`status\` is what you found (\`missing\` / \`outdated\` /
59920
+ \`present_ok\`); \`action\` is what Dosu should do (\`create\` / \`update\` / \`skip\`).
59921
+ - **Include every type you assessed**, even when \`can_help\` is \`false\`, so the CLI can explain
59922
+ what it skipped and why.
59923
+ - **Make \`rationale\` specific** — it is forwarded to Dosu cloud as generation guidance. "README's
59924
+ install section references a \`make bootstrap\` target that no longer exists" beats "README looks
59925
+ old."
59926
+ - **Don't write the docs.** Producing the actual files is Dosu cloud's job, triggered by the user
59927
+ through \`dosu audit\`.
59928
+
59929
+ ## Use Dosu MCP for org knowledge
59930
+
59931
+ Before finalizing recommendations, use the Dosu MCP tools to pull organization knowledge that
59932
+ should inform the docs (architecture decisions, naming, conventions, prior docs). The exposed
59933
+ tool set depends on the connection — always use what's actually listed:
59934
+
59935
+ 1. Read first: call \`read_knowledge\` when listed (or \`init_knowledge\` on older connections) to
59936
+ get task-relevant context from the knowledge base.
59937
+ 2. Go deeper with whichever search/ask tools the server exposes — check whether the org already
59938
+ documents the architecture, dependencies, or agent conventions elsewhere. If it does, factor
59939
+ that into \`status\`/\`rationale\` (e.g. an existing architecture doc in Dosu may mean a repo
59940
+ \`architecture.md\` should mirror it).
59941
+
59942
+ If no Dosu deployment is connected (only public-library tools are available), skip the MCP step
59943
+ and rely on repo evidence alone; note in the \`rationale\` that org knowledge wasn't consulted.
59944
+
59945
+ ## Procedure
59946
+
59947
+ 1. **Identify the repo.** Get the remote and slug:
59948
+ \`\`\`bash
59949
+ git config --get remote.origin.url
59950
+ \`\`\`
59951
+ Parse \`owner/name\` from it for \`repo.slug\`. If there is no GitHub remote, tell the user the
59952
+ audit needs a GitHub repo connected to Dosu and stop.
59953
+
59954
+ 2. **Inspect the working tree** for each doc type. Useful starting points:
59955
+ \`\`\`bash
59956
+ ls -a
59957
+ # existing docs (any casing)
59958
+ ls AGENTS.md README.md architecture.md ARCHITECTURE.md deps.md DEPS.md docs/ 2>/dev/null
59959
+ # dependency manifests
59960
+ ls package.json pyproject.toml requirements*.txt go.mod Cargo.toml Gemfile pom.xml build.gradle 2>/dev/null
59961
+ \`\`\`
59962
+ - **AGENTS.md** — does it exist? If yes, is it consistent with the current build/test commands,
59963
+ directory layout, and contribution conventions? Read it and compare against \`package.json\`
59964
+ scripts / Makefile / CI config.
59965
+ - **README.md** — read it. Are the setup/build/run steps still accurate? Do referenced scripts,
59966
+ commands, env vars, and features still exist in the code? Mark \`outdated\` only with evidence.
59967
+ - **architecture.md** — does it exist? Is the repo structured enough to warrant one? Look at the
59968
+ top-level layout, number of modules/services, and whether there's a clear separation worth
59969
+ documenting.
59970
+ - **deps.md** — does it exist? If yes, does it match the actual manifests/lockfiles? If missing,
59971
+ are there real dependencies worth documenting?
59972
+
59973
+ 3. **Consult Dosu MCP** (see above) to enrich and cross-check.
59974
+
59975
+ 4. **Write \`.dosu/audit.json\`** following [audit-findings-schema.md](audit-findings-schema.md).
59976
+ Create the \`.dosu/\` directory if needed. Write one \`items\` entry per type you assessed.
59977
+
59978
+ 5. **Tell the user to run the CLI.** End with a short message, e.g.:
59979
+
59980
+ > Audit complete — I wrote \`.dosu/audit.json\`. Run \`dosu audit\` to choose which docs Dosu
59981
+ > should generate; it will open a PR with the ones you pick.
59982
+
59983
+ Do not attempt to generate or commit the docs yourself.
59984
+
59985
+ ## Example \`.dosu/audit.json\`
59986
+
59987
+ \`\`\`json
59988
+ {
59989
+ "version": 1,
59990
+ "generated_at": "2026-06-24T12:00:00Z",
59991
+ "repo": { "remote": "git@github.com:acme/widget.git", "slug": "acme/widget" },
59992
+ "items": [
59993
+ {
59994
+ "task": "generate-agents-md", "type": "agents", "file": "AGENTS.md",
59995
+ "status": "missing", "action": "create", "can_help": true, "confidence": "high",
59996
+ "rationale": "No AGENTS.md; repo has documented \`pnpm test\`/\`pnpm build\` scripts and a clear packages/ layout worth capturing for agents.",
59997
+ "evidence": ["package.json", "packages/", "CONTRIBUTING.md"]
59998
+ },
59999
+ {
60000
+ "task": "refresh-readme", "type": "readme", "file": "README.md",
60001
+ "status": "outdated", "action": "update", "can_help": true, "confidence": "medium",
60002
+ "rationale": "README's Getting Started references a \`make bootstrap\` target that no longer exists; setup now uses \`pnpm install\`.",
60003
+ "evidence": ["README.md:24", "Makefile", "package.json"]
60004
+ },
60005
+ {
60006
+ "task": "generate-architecture-md", "type": "architecture", "file": "architecture.md",
60007
+ "status": "missing", "action": "skip", "can_help": false, "confidence": "high",
60008
+ "rationale": "Single-package repo with one entry point; not enough structure to justify a separate architecture doc yet.",
60009
+ "evidence": ["src/index.ts"]
60010
+ },
60011
+ {
60012
+ "task": "generate-deps-md", "type": "deps", "file": "deps.md",
60013
+ "status": "missing", "action": "create", "can_help": true, "confidence": "medium",
60014
+ "rationale": "No deps doc; package.json has ~30 runtime deps across HTTP, DB, and queue concerns worth summarizing.",
60015
+ "evidence": ["package.json", "pnpm-lock.yaml"]
60016
+ }
60017
+ ]
59807
60018
  }
59808
- function readSkillCache() {
60019
+ \`\`\`
60020
+ `,
60021
+ executable: false
60022
+ },
60023
+ {
60024
+ path: "references/commands.md",
60025
+ content: `# Dosu CLI command reference
60026
+
60027
+ This file is the detailed source for the current command surface. Optional flags are in brackets. Only commands showing \`--json\` support structured JSON. Run the nested \`--help\` if the installed CLI differs.
60028
+
60029
+ ## Authentication and setup
60030
+
60031
+ \`\`\`text
60032
+ dosu login [--request | --check <ticket>] [--json] [--no-browser]
60033
+ dosu logout
60034
+ dosu status [--json]
60035
+ dosu setup [--deployment <id>] [--mode <oss|cloud>] [--agent --tool <id>]
60036
+ [--login-ticket <ticket>]
60037
+ \`\`\`
60038
+
60039
+ - \`--request\` and \`--check\` are mutually exclusive login modes.
60040
+ - \`setup --agent\` requires \`--tool\`, emits NDJSON, and exits instead of waiting for a browser callback.
60041
+
60042
+ ## Libraries
60043
+
60044
+ \`\`\`text
60045
+ dosu libraries list [--json]
60046
+ dosu libraries info <library-id> [--json]
60047
+ dosu libraries create --name <name> [--visibility public|internal|private] [--json]
60048
+ dosu libraries update <library-id> [--name <name>]
60049
+ [--visibility public|internal|private] [--confirm] [--json]
60050
+ dosu libraries delete <library-id> [--confirm] [--json]
60051
+ \`\`\`
60052
+
60053
+ - Library and source IDs in this section must be UUID v4. Names are nonempty and at most 50 characters. Omitted visibility uses the App default, \`internal\`. \`update\` requires at least one changed field.
60054
+ - \`update\` and \`delete\` prompt only in an interactive non-JSON terminal; agents pass \`--confirm\` after authorization.
60055
+ - The last Library in an organization cannot be deleted. A successful delete hides it immediately; child-data cleanup continues asynchronously.
60056
+
60057
+ ### Library documentation config
60058
+
60059
+ \`\`\`text
60060
+ dosu libraries config get <library-id> [--json]
60061
+ dosu libraries config set <library-id> <setting> --value <json> [--confirm] [--json]
60062
+ \`\`\`
60063
+
60064
+ Settings and values:
60065
+
60066
+ | Setting | JSON value |
60067
+ |---|---|
60068
+ | \`commit_to_trigger_pr\` | boolean |
60069
+ | \`default_accept_review\` | boolean |
60070
+ | \`default_save_publish\` | boolean |
60071
+ | \`review_timeout_days\` | \`7\`, \`14\`, \`30\`, or \`90\` |
60072
+
60073
+ \`set\` reads the current version immediately before writing and sends that version with the mutation.
60074
+
60075
+ ### Library sources
60076
+
60077
+ \`\`\`text
60078
+ dosu libraries sources list <library-id> [--json]
60079
+ dosu libraries sources attach <library-id> <source-id...> [--confirm] [--json]
60080
+ dosu libraries sources detach <library-id> <source-id...> [--confirm] [--json]
60081
+
60082
+ dosu libraries sources config get <library-id> <source-id> [--json]
60083
+ dosu libraries sources config update <library-id> <source-id>
60084
+ [--issues on|off] [--pull-requests on|off] [--discussions on|off] [--wiki on|off]
60085
+ [--include-patterns <json-string-array>] [--exclude-patterns <json-string-array>]
60086
+ [--confirm] [--json]
60087
+ \`\`\`
60088
+
60089
+ - \`attach\` and \`detach\` require one or more UUID source IDs. Repeated IDs are deduplicated.
60090
+ - Detaching archives pages that source synced into this Library; copies in other Libraries are unaffected.
60091
+ - Source config requires at least one option. GitHub accepts every option above; GitLab accepts only include/exclude patterns. The App resolves the provider.
60092
+ - Pattern options replace the list. Use \`[]\` to clear it.
60093
+
60094
+ ### Library Monitor
60095
+
60096
+ \`\`\`text
60097
+ dosu libraries monitors list <library-id> [--json]
60098
+ dosu libraries monitors update <library-id> <source-id>
60099
+ [--enabled on|off] [--paths <json-string-array>]
60100
+ [--up-to-date-behavior emoji|comment|silent] [--confirm] [--json]
60101
+ \`\`\`
60102
+
60103
+ \`update\` requires at least one option. Monitor supports GitHub, GitLab, and Azure DevOps. It performs first-time setup for an attached supported source, reusing existing deployment infrastructure when available. When no Monitor row exists, omitted \`--enabled\`, paths, and behavior default to \`true\`, \`[]\`, and \`emoji\`.
60104
+
60105
+ ## Agents
60106
+
60107
+ \`\`\`text
60108
+ dosu agents list [--json]
60109
+ dosu agents info <agent-id> [--json]
60110
+ dosu agents create --library <library-id> --source <source-id>
60111
+ [--name <name>] [--guidelines <text>] [--json]
60112
+ dosu agents update <agent-id> [--name <name>] [--enabled on|off]
60113
+ [--guidelines <text> | --clear-guidelines] [--confirm] [--json]
60114
+ dosu agents delete <agent-id> [--confirm] [--json]
60115
+ dosu agents move <agent-id> --library <library-id> [--confirm] [--json]
60116
+
60117
+ dosu agents config get <agent-id> [--json]
60118
+ dosu agents config set <agent-id> <existing.leaf.path>
60119
+ --value <json> [--confirm] [--json]
60120
+ \`\`\`
60121
+
60122
+ - Agent, Library, and source IDs in this section must be UUID v4. \`create\` accepts an existing GitHub, GitLab, Slack, or Teams source. The App supplies provider defaults, enables the Agent, and starts Mention-only reply behavior. Omitted name uses the source name.
60123
+ - Agent names are at most 80 characters; guidelines are at most 20,000 characters.
60124
+ - \`update\` requires at least one option. \`--guidelines\` conflicts with \`--clear-guidelines\`.
60125
+ - Config \`set\` changes one existing non-object leaf. Read the config first to select a valid path and value type.
60126
+ - \`move\` replaces the Agent's Library and returns the updated Agent. It does not report any historical-data migration.
60127
+
60128
+ ## Knowledge and documents
60129
+
60130
+ \`\`\`text
60131
+ dosu ask <question> [--session <id>] [--timeout <seconds>] [--json]
60132
+ dosu knowledge search <query> [--limit <positive-int>] [--json] # default 10
60133
+ dosu knowledge list [--json]
60134
+
60135
+ dosu docs list [--search <query>] [--topic <id>] [--limit <positive-int>] [--json]
60136
+ dosu docs get <id> [--revision <positive-int>] [--json]
60137
+ dosu docs create --title <title> [--body <markdown> | --body-file <path>] [--json]
60138
+ dosu docs update <id> [--title <title>] [--body <markdown> | --body-file <path>] [--json]
60139
+ dosu docs archive <id> [--json]
60140
+ dosu docs unarchive <id> [--json]
60141
+ dosu docs delete <id> [--json]
60142
+ dosu docs versions <id> [--json]
60143
+ dosu docs restore <id> --revision <positive-int> [--json]
60144
+ dosu docs generate --title <title> [--instructions <text>] [--json]
60145
+ dosu docs auto-tag <id> [--json]
60146
+ dosu docs import <platform> --files <comma-separated-ids> [--json]
60147
+ dosu docs import-status <task-id> [--json]
60148
+ dosu docs publish <id> --to <platform> [target flags] [--json]
60149
+ dosu docs sync-back <id> [--json]
60150
+ \`\`\`
60151
+
60152
+ - Document list defaults to 20. \`create\` and \`update\` reject combining \`--body\` with \`--body-file\`; \`update\` requires at least one field.
60153
+ - Import platforms: \`github\`, \`gitlab\`, \`azure_devops\`, \`confluence\`, \`notion\`, \`coda\`.
60154
+ - Publish platforms: the same six. Target flags are \`--repo-id\`, \`--project-id\`, \`--parent-page-id\`, \`--doc-id\`, \`--directory\`, and \`--data-source-id\`; Azure DevOps requires \`--data-source-id\`. Other target validation may occur in the backend.
60155
+ - \`generate\`, \`auto-tag\`, import, publish, and sync operations may be asynchronous. Use the returned task/status identifiers rather than assuming completion.
60156
+
60157
+ ## Review
60158
+
60159
+ Read [review-workflow.md](review-workflow.md) before mutating a review item.
60160
+
60161
+ \`\`\`text
60162
+ dosu review list [--json]
60163
+ dosu review diff <id> [--json]
60164
+ dosu review edit <id> [--title <title>] [--body <markdown> | --body-file <path>] [--json]
60165
+ dosu review context <thread-id> [--json]
60166
+ dosu review approve <id> [--confirm] [--json]
60167
+ dosu review reject <id> [--confirm] [--json]
60168
+ dosu review revert <id> [--json]
60169
+ \`\`\`
60170
+
60171
+ \`edit\` requires at least one field. \`approve\` and \`reject\` do not write without interactive confirmation or \`--confirm\`.
60172
+
60173
+ ## Sources, integrations, members, and organization
60174
+
60175
+ \`\`\`text
60176
+ dosu sources list [--json]
60177
+ dosu sources info <id> [--json]
60178
+ dosu sources sync <id> [--json]
60179
+ dosu sources update <id> [--name <name>] [--description <text>] [--json]
60180
+ dosu sources delete <id> [--json]
60181
+ dosu sources connect [github] [--json] [--timeout <seconds>] [--no-open]
60182
+ dosu sources create github --repo <owner/name> [--library <id>] [--confirm] [--json]
60183
+
60184
+ dosu integrations list [--json]
60185
+ dosu integrations status <platform> [--json]
60186
+ dosu integrations slack-channels [--json]
60187
+ dosu integrations slack-join <channel-id> [--json]
60188
+ dosu integrations github-collaborators <positive-repository-id> [--json]
60189
+
60190
+ dosu members invite <email> [--role admin|member] [--json] # default member
60191
+ dosu org info [--json]
60192
+ \`\`\`
60193
+
60194
+ - \`sources update\` requires \`--name\` or \`--description\`.
60195
+ - \`sources connect\` currently supports only \`github\`: it prints an install URL for the user to
60196
+ open, then waits for the GitHub App install to complete (default 600s). With \`--json\` it emits
60197
+ NDJSON events — \`awaiting_install\` (give the \`url\` to the user), then \`installed\` with
60198
+ \`new_repositories\`, or \`timeout\` (exit 1). Other providers exit 1 with a web-app handoff URL.
60199
+ - \`sources create\` wires an installed GitHub repo into a Library: it creates (or reuses) the
60200
+ repo's data source + deployment, attaches it, and verifies the first sync. \`--library\` defaults
60201
+ to the active Library. A repo not listed means the GitHub App lacks access — run
60202
+ \`sources connect github\` first. Forks can't be connected.
60203
+ - Integration status choices: \`github\`, \`gitlab\`, \`azure_devops\`, \`slack\`, \`confluence\`, \`notion\`, \`coda\`, \`teams\`. GitHub, Slack, and Teams currently return \`connected: null\` because CLI status probing is unavailable for them.
60204
+ - The CLI has no member list/remove/request commands; \`members invite\` is its only member operation.
60205
+
60206
+ ## Threads, Topics, suggestions, and analytics
60207
+
60208
+ \`\`\`text
60209
+ dosu threads list [--status pending|resolved|archived] [--search <query>]
60210
+ [--limit <1..100>] [--json] # default 20
60211
+ dosu threads get <id> [--limit <-1|positive-int>] [--json] # default 20
60212
+ dosu threads archive <id> [--json]
60213
+
60214
+ dosu topics list [--json]
60215
+ dosu topics pages <topic-id> [--search <query>] [--limit <positive-int>] [--json]
60216
+
60217
+ dosu suggest list [--json]
60218
+ dosu suggest generate [--json]
60219
+ dosu suggest reject <id> [--json]
60220
+
60221
+ dosu analytics [--days <positive-int>] [--json] # default 30
60222
+ \`\`\`
60223
+
60224
+ Topics are read-only. The CLI has no \`tags\` command and no suggestion-accept command.
60225
+
60226
+ ## MCP deployments and local utilities
60227
+
60228
+ \`\`\`text
60229
+ dosu deployments list [--json]
60230
+ dosu deployments info [--json]
60231
+ dosu deployments switch <id> [--json]
60232
+
60233
+ dosu mcp list
60234
+ dosu mcp add <agent> [--global] [--show-secret]
60235
+ dosu skill install | remove | update
60236
+ dosu telemetry status [--json]
60237
+ dosu telemetry enable | disable | reset
60238
+ dosu insights
60239
+ dosu upgrade
60240
+ dosu logs [--tail [n]] [--clear]
60241
+ \`\`\`
60242
+
60243
+ \`deployments\` selects the MCP deployment stored in local config; it is distinct from \`agents\`. \`insights\` opens an interactive visual report. \`logs --clear\` deletes the CLI log file.
60244
+
60245
+ ## Codebase audit
60246
+
60247
+ \`\`\`text
60248
+ dosu audit [--findings <path>] [--data-source-id <id>]
60249
+ [--tasks <comma-separated-task-ids> | --yes] [--list-tasks] [--json]
60250
+ \`\`\`
60251
+
60252
+ The coding agent writes the findings; Dosu generates the selected docs. Follow [audit.md](audit.md) and [audit-findings-schema.md](audit-findings-schema.md).
60253
+ `,
60254
+ executable: false
60255
+ },
60256
+ {
60257
+ path: "references/review-workflow.md",
60258
+ content: `# Review workflow
60259
+
60260
+ How to work Dosu's review queue from the CLI: triage pending items, read the
60261
+ diff, optionally edit, and apply a decision — safely.
60262
+
60263
+ The queue holds **document versions** (AI-generated, user-edited, synced from
60264
+ source, or API-created) and **draft messages**, all surfaced through the same
60265
+ \`dosu review\` commands. Items are keyed on a single \`page-version-id\` so
60266
+ \`list\` → \`diff\` → \`edit\` → \`approve\`/\`reject\` all share one ID.
60267
+
60268
+ > \`list\` returns only the most recent pending items (server-capped, currently
60269
+ > 50) and does not flag truncation. If the queue is large, don't assume \`list\`
60270
+ > shows everything.
60271
+
60272
+ ## Scope tool access for a review session
60273
+
60274
+ Approving and rejecting are destructive and outward-facing. When you spin up an
60275
+ agent session dedicated to reviewing, scope it to just the review commands:
60276
+
60277
+ \`\`\`yaml
60278
+ allowed-tools: Bash(dosu review:*)
60279
+ \`\`\`
60280
+
60281
+ This lets the agent triage, diff, and edit, but keeps it from running unrelated
60282
+ CLI commands during a review pass.
60283
+
60284
+ ## The flow
60285
+
60286
+ \`\`\`bash
60287
+ # 1. Triage — what's pending? Columns: ID, Kind, Title, Source, Status, Created.
60288
+ dosu review list --json
60289
+
60290
+ # 2. Inspect — read the exact change before deciding anything.
60291
+ dosu review diff <page-version-id> --json
60292
+
60293
+ # 3. (optional) Edit in place instead of rejecting a near-miss.
60294
+ dosu review edit <page-version-id> --body-file ./revised.md # or --body / --title
60295
+
60296
+ # 4. Decide — only on the item the user named, only after they OK it.
60297
+ dosu review approve <page-version-id> --confirm --json
60298
+ dosu review reject <page-version-id> --confirm --json
60299
+
60300
+ # Undo a decision — back to pending.
60301
+ dosu review revert <page-version-id> --json
60302
+ \`\`\`
60303
+
60304
+ ### \`--confirm\` is mandatory for agents
60305
+
60306
+ \`approve\` and \`reject\` only prompt interactively in a TTY *without* \`--json\`.
60307
+ The skill always passes \`--json\`, which suppresses both the diff preview and
60308
+ the prompt — so without \`--confirm\` the command changes nothing and returns
60309
+ \`{ "applied": false, "confirmRequired": true }\`. Run \`dosu review diff <id>\` to
60310
+ see the change, then pass \`--confirm\` to apply — only after the user has
60311
+ approved that specific item.
60312
+
60313
+ ## Reading the \`Source\` column
60314
+
60315
+ \`Source\` is the humanized \`origin\` field:
60316
+
60317
+ | \`origin\` | Source | Meaning |
60318
+ |---|---|---|
60319
+ | \`manual_update\` | User created / User updated | A teammate authored or edited the doc |
60320
+ | \`llm_generated\` | AI generated | Dosu drafted the change |
60321
+ | \`sync_upstream\` | Synced from source | Came in from a connected source (Notion/Confluence/GitHub) |
60322
+ | \`api_update\` | Created via API | Pushed in programmatically |
60323
+
60324
+ ## Feeding PR / thread context
60325
+
60326
+ A review often originates from a conversation thread (a GitHub issue, a Slack
60327
+ message, a sync-back PR). Pull that context before deciding:
60328
+
60329
+ \`\`\`bash
60330
+ dosu review context <thread-id> --json
60331
+ \`\`\`
60332
+
60333
+ It returns the review \`type\`, the review/published page IDs, and — when the
60334
+ change round-trips to an external system — a **Sync PR URL**. Use it to:
60335
+
60336
+ - show the user where the change came from and where approval will land, and
60337
+ - read the originating discussion so the decision matches intent.
60338
+
60339
+ ## Safety rules
60340
+
60341
+ - **Explicit item only.** Decide on the \`id\` the user named. "Review my queue"
60342
+ → run \`list\` and show it; never decide on their behalf.
60343
+ - **Diff before deciding.** Always \`diff\` and surface the change first.
60344
+ - **Never batch-accept.** No loop over \`list\` that approves everything. One
60345
+ item, one confirmation.
60346
+ - **Extra care for sync/PR origins.** \`Synced from source\` items and anything
60347
+ with a Sync PR URL push back to an upstream system on approval. Call it out
60348
+ and get explicit sign-off.
60349
+ `,
60350
+ executable: false
60351
+ },
60352
+ {
60353
+ path: "references/workflows.md",
60354
+ content: `# Dosu CLI workflows
60355
+
60356
+ Use these patterns to compose commands. Replace placeholders with IDs read from JSON output; never guess them. See [commands.md](commands.md) for exact flags and choices.
60357
+
60358
+ ## Configure Dosu for a coding agent
60359
+
60360
+ \`\`\`bash
60361
+ dosu setup --agent --tool <tool-id>
60362
+ \`\`\`
60363
+
60364
+ Read every NDJSON event:
60365
+
60366
+ 1. On \`need_user_action\`, give the returned URL to the user and stop.
60367
+ 2. After the user confirms sign-in, run the returned \`resume_command\` verbatim.
60368
+ 3. On \`pending\`, wait for the user and repeat that command.
60369
+ 4. On \`multiple_deployments\`, list MCP deployments, let the user choose, and retry with \`--deployment <id>\`.
60370
+ 5. Treat \`done\` as setup completion, then verify with \`dosu status --json\`.
60371
+
60372
+ ## Onboard from scratch (guided)
60373
+
60374
+ Use this flow when the user asks to "set up Dosu", "create a library and set it up", or any
60375
+ end-to-end onboarding. It is a conversation, not a script: never invent names, never auto-pick
60376
+ sources, and stop at every checkpoint below until the user answers. Run each mutation only after
60377
+ its checkpoint. One step per turn is better than one turn with every step.
60378
+
60379
+ **Step 0 — Discover (read-only, no confirmation needed).**
60380
+
60381
+ \`\`\`bash
60382
+ dosu status --json
60383
+ dosu sources list --json
60384
+ dosu libraries list --json
60385
+ \`\`\`
60386
+
60387
+ If not configured, run the "Configure Dosu for a coding agent" flow first.
60388
+
60389
+ **Checkpoint 1 — Scope.** Present a short summary of the connected sources (name + provider, not
60390
+ raw JSON) and any existing Libraries, then ask and wait:
60391
+
60392
+ 1. Which source(s) should the new Library use? Existing ones, a new one, or both.
60393
+ 2. What should the Library be called? Suggest a name derived from the chosen sources, but let the
60394
+ user decide.
60395
+ 3. Visibility: default \`internal\`; mention \`private\`/\`public\` only if relevant (warn about the
60396
+ public-Library boundary from [SKILL.md](../SKILL.md)).
60397
+ 4. For each chosen GitHub repository: Monitor will be enabled with defaults (whole repository,
60398
+ \`emoji\`) unless they opt out.
60399
+
60400
+ **Step 0.5 — Connect a new source (only when the user asked for one).** Ask which provider. For
60401
+ GitHub, run the CLI bridge — do not send the user hunting through the App:
60402
+
60403
+ \`\`\`bash
60404
+ dosu sources connect github --json
60405
+ \`\`\`
60406
+
60407
+ Give the user the \`url\` from the \`awaiting_install\` event and wait; the command completes on its
60408
+ own when the install finishes and reports \`new_repositories\`. For any other provider (Slack, web
60409
+ docs, Notion, Coda, Confluence, ...) the connect flow is web-only: give the user the App URL the
60410
+ command prints, wait for them to confirm, then re-run \`dosu sources list --json\` to pick up the
60411
+ new source.
60412
+
60413
+ **Step 1 — Create and attach (after the user answers).**
60414
+
60415
+ \`\`\`bash
60416
+ dosu libraries create --name "<user-approved name>" --json
60417
+ dosu libraries sources attach <library-id> <existing-source-ids...> --confirm --json
60418
+ dosu sources create github --repo <owner/name> --library <library-id> --confirm --json
60419
+ dosu libraries monitors update <library-id> <repository-source-id> --enabled on --confirm --json
60420
+ \`\`\`
60421
+
60422
+ Use \`libraries sources attach\` for sources that already exist; use \`sources create\` for a GitHub
60423
+ repo that became visible via \`sources connect\` but has no data source yet (it creates, attaches,
60424
+ and verifies the first sync in one receipt).
60425
+
60426
+ Report each receipt in one line as it lands (Library ID, sources attached, Monitor state).
60427
+
60428
+ **Checkpoint 2 — Agent (optional).** Ask whether the user wants an Agent (GitHub/GitLab/Slack/Teams
60429
+ responder) on one of the attached sources. Only on yes:
60430
+
60431
+ \`\`\`bash
60432
+ dosu agents create --library <library-id> --source <source-id> --name "<user-approved name>" --json
60433
+ \`\`\`
60434
+
60435
+ A \`CONFLICT\` (409) means that data source already has an Agent — one Agent per source. Report which
60436
+ source conflicted and offer the alternatives: pick a different source, or (only with explicit
60437
+ authorization) \`dosu agents move\` the existing Agent, which removes it from its current Library.
60438
+
60439
+ **Step 2 — Verify and hand off.**
60440
+
60441
+ \`\`\`bash
60442
+ dosu libraries info <library-id> --json
60443
+ dosu libraries sources list <library-id> --json
60444
+ dosu libraries monitors list <library-id> --json
60445
+ \`\`\`
60446
+
60447
+ Summarize the final state. Creating an MCP deployment for the new Library is not available in the
60448
+ CLI; if the user wants their MCP/CLI target pointed at this Library, send them to the App to create
60449
+ the MCP deployment, then run \`dosu deployments switch\`.
60450
+
60451
+ ## Create a Library from existing sources
60452
+
60453
+ This works with any number or mix of organization sources.
60454
+
60455
+ \`\`\`bash
60456
+ # Discover connected sources and select exact IDs by provider/name.
60457
+ dosu sources list --json
60458
+
60459
+ # Create the Library; capture its id. Omitted visibility defaults to \`internal\`;
60460
+ # pass --visibility public|internal|private only when the user asks for it.
60461
+ dosu libraries create --name "Incident Response" --json
60462
+
60463
+ # The user's explicit request authorizes these exact attachments.
60464
+ dosu libraries sources attach <library-id> <repository-source-id> <handbook-source-id> \\
60465
+ --confirm --json
60466
+
60467
+ # Enable the default for each newly attached GitHub repository unless the user opted out.
60468
+ dosu libraries monitors update <library-id> <repository-source-id> \\
60469
+ --enabled on --confirm --json
60470
+
60471
+ # Verify the final state, not just mutation receipts.
60472
+ dosu libraries info <library-id> --json
60473
+ dosu libraries sources list <library-id> --json
60474
+ dosu libraries monitors list <library-id> --json
60475
+ \`\`\`
60476
+
60477
+ Apply the connection and public-Library safety boundaries from [SKILL.md](../SKILL.md) before attaching.
60478
+
60479
+ ## Change an existing Library safely
60480
+
60481
+ \`\`\`bash
60482
+ dosu libraries list --json
60483
+ dosu libraries info <library-id> --json
60484
+
60485
+ # Rename or change visibility only after the exact target/change is authorized.
60486
+ dosu libraries update <library-id> --name "Operations Handbook" --confirm --json
60487
+
60488
+ # Read before changing one documentation setting.
60489
+ dosu libraries config get <library-id> --json
60490
+ dosu libraries config set <library-id> review_timeout_days --value 30 --confirm --json
60491
+ \`\`\`
60492
+
60493
+ ## Create and configure an Agent
60494
+
60495
+ \`\`\`bash
60496
+ # Select a Library and an existing GitHub, GitLab, Slack, or Teams source.
60497
+ dosu libraries list --json
60498
+ dosu sources list --json
60499
+
60500
+ dosu agents create --library <library-id> --source <source-id> \\
60501
+ --name "Repository Helper" --json
60502
+
60503
+ dosu agents info <agent-id> --json
60504
+ dosu agents config get <agent-id> --json
60505
+
60506
+ # Change one leaf only after reading the current structure.
60507
+ dosu agents config set <agent-id> issues.auto_reply.review_required \\
60508
+ --value true --confirm --json
60509
+ \`\`\`
60510
+
60511
+ To move the Agent, confirm the destination and verify the returned \`space_id\`:
60512
+
60513
+ \`\`\`bash
60514
+ dosu agents move <agent-id> --library <destination-library-id> --confirm --json
60515
+ \`\`\`
60516
+
60517
+ ## Configure a Library source and Monitor
60518
+
60519
+ \`\`\`bash
60520
+ dosu libraries sources config get <library-id> <source-id> --json
60521
+ dosu libraries sources config update <library-id> <source-id> \\
60522
+ --include-patterns '["docs/**","*.md"]' \\
60523
+ --exclude-patterns '["archive/**"]' --confirm --json
60524
+
60525
+ dosu libraries monitors list <library-id> --json
60526
+ dosu libraries monitors update <library-id> <source-id> \\
60527
+ --enabled on --paths '["docs/**"]' \\
60528
+ --up-to-date-behavior silent --confirm --json
60529
+ \`\`\`
60530
+
60531
+ ## Find information and inspect its source
60532
+
60533
+ \`\`\`bash
60534
+ dosu ask "How is access control enforced?" --json
60535
+ dosu knowledge search "access control" --json
60536
+ dosu docs get <page-id> --json
60537
+ \`\`\`
60538
+
60539
+ Use \`ask\` for a synthesized answer. Use \`knowledge search\` and \`docs get\` when the user wants the underlying documents.
60540
+
60541
+ ## Import external documents
60542
+
60543
+ \`\`\`bash
60544
+ dosu sources list --json
60545
+ dosu docs import <platform> --files <comma-separated-ids> --json
60546
+ dosu docs import-status <task-id> --json
60547
+ \`\`\`
60548
+
60549
+ Capture the returned task ID. Poll only when the user asked you to wait for completion.
60550
+
60551
+ ## Review one pending item
60552
+
60553
+ \`\`\`bash
60554
+ dosu review list --json
60555
+ dosu review diff <item-id> --json
60556
+ dosu review approve <item-id> --confirm --json
60557
+ \`\`\`
60558
+
60559
+ Use \`reject\` instead of \`approve\` only for the same explicitly authorized item. Follow [review-workflow.md](review-workflow.md) for edits, draft replies, upstream sync, and rollback.
60560
+
60561
+ ## Audit repository documentation
60562
+
60563
+ Follow [audit.md](audit.md) to inspect the repository and write \`.dosu/audit.json\`, then invoke only the task IDs the user chooses:
60564
+
60565
+ \`\`\`bash
60566
+ dosu audit --tasks <comma-separated-task-ids> --json
60567
+ \`\`\`
60568
+
60569
+ The coding agent performs triage; Dosu cloud generates docs and opens the PR.
60570
+ `,
60571
+ executable: false
60572
+ }
60573
+ ]
60574
+ }
60575
+ ];
60576
+ });
60577
+
60578
+ // src/commands/skill.ts
60579
+ import {
60580
+ cpSync,
60581
+ existsSync as existsSync19,
60582
+ lstatSync as lstatSync2,
60583
+ mkdirSync as mkdirSync11,
60584
+ readFileSync as readFileSync19,
60585
+ rmSync as rmSync5,
60586
+ symlinkSync,
60587
+ writeFileSync as writeFileSync12
60588
+ } from "node:fs";
60589
+ import { homedir as homedir8 } from "node:os";
60590
+ import { dirname as dirname10, join as join22, relative as relative3 } from "node:path";
60591
+ function skillAgentIDsForProviders(providerIDs) {
60592
+ return [
60593
+ ...new Set(providerIDs.map((providerID) => SKILL_AGENT_BY_PROVIDER[providerID]).filter((agent) => Boolean(agent)))
60594
+ ];
60595
+ }
60596
+ function isSkillAgentID(agent) {
60597
+ return SUPPORTED_SKILL_AGENTS.includes(agent);
60598
+ }
60599
+ function universalSkillsDir() {
60600
+ return join22(homedir8(), ".agents", "skills");
60601
+ }
60602
+ function linkedSkillsDir(agent) {
60603
+ if (agent === "claude-code") {
60604
+ const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR?.trim() || join22(homedir8(), ".claude");
60605
+ return join22(claudeConfigDir, "skills");
60606
+ }
60607
+ if (agent === "windsurf")
60608
+ return join22(homedir8(), ".codeium", "windsurf", "skills");
60609
+ return null;
60610
+ }
60611
+ function skillInstallTargetForProvider(providerID) {
60612
+ const agentID = SKILL_AGENT_BY_PROVIDER[providerID];
60613
+ if (!agentID)
60614
+ return null;
60615
+ const linked = linkedSkillsDir(agentID);
60616
+ if (linked)
60617
+ return { path: join22(linked, SKILL_NAME), symlink: true };
60618
+ return { path: join22(universalSkillsDir(), SKILL_NAME), symlink: false };
60619
+ }
60620
+ function installStatePath() {
60621
+ return join22(getConfigDir(), INSTALL_STATE_FILENAME);
60622
+ }
60623
+ function readSkillInstallState() {
59809
60624
  try {
59810
- const path = getCachePath2();
60625
+ const path = installStatePath();
59811
60626
  if (!existsSync19(path))
59812
60627
  return null;
59813
60628
  const data = JSON.parse(readFileSync19(path, "utf-8"));
59814
- if (typeof data.lastCheck === "number" && typeof data.latestSha === "string" && typeof data.installedSha === "string") {
59815
- return data;
60629
+ if (typeof data?.version === "string" && Array.isArray(data.agents) && data.agents.every((agent) => typeof agent === "string") && typeof data.installedAt === "number") {
60630
+ return { version: data.version, agents: data.agents, installedAt: data.installedAt };
59816
60631
  }
59817
60632
  return null;
59818
60633
  } catch {
59819
60634
  return null;
59820
60635
  }
59821
60636
  }
59822
- function writeSkillCache(cache) {
60637
+ function writeSkillInstallState(state) {
59823
60638
  try {
59824
60639
  const dir = getConfigDir();
59825
- if (!existsSync19(dir)) {
60640
+ if (!existsSync19(dir))
59826
60641
  mkdirSync11(dir, { recursive: true, mode: 448 });
59827
- }
59828
- writeFileSync12(getCachePath2(), JSON.stringify(cache), { mode: 384 });
59829
- } catch {}
59830
- }
59831
- function clearInstalledSha() {
59832
- const cache = readSkillCache();
59833
- if (cache)
59834
- writeSkillCache({ ...cache, installedSha: "" });
59835
- }
59836
- async function fetchLatestSha() {
59837
- const controller = new AbortController;
59838
- const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS2);
59839
- try {
59840
- const resp = await fetch(GITHUB_API_URL, {
59841
- signal: controller.signal,
59842
- headers: {
59843
- "User-Agent": `dosu-cli/${VERSION}`,
59844
- Accept: "application/vnd.github+json"
59845
- }
59846
- });
59847
- if (!resp.ok)
59848
- return null;
59849
- const data = await resp.json();
59850
- const sha = data.sha;
59851
- return typeof sha === "string" ? sha : null;
59852
- } catch {
59853
- return null;
59854
- } finally {
59855
- clearTimeout(timeout);
60642
+ writeFileSync12(installStatePath(), JSON.stringify(state), { mode: 384 });
60643
+ } catch (err) {
60644
+ logger.debug("skill", `Could not record skill install state: ${err}`);
59856
60645
  }
59857
60646
  }
59858
- function displayNotice() {
59859
- const msg = `
59860
- ${import_picocolors26.default.yellow(" Dosu skill update available")}
59861
- ` + `${import_picocolors26.default.dim(' Run "dosu skill update" to upgrade')}
59862
- `;
59863
- console.error(msg);
60647
+ function clearSkillInstallState() {
60648
+ rmSync5(installStatePath(), { force: true });
59864
60649
  }
59865
- function checkForSkillUpdates() {
60650
+ function pruneLegacySkillLock() {
60651
+ const lockPath = join22(homedir8(), ".agents", ".skill-lock.json");
59866
60652
  try {
59867
- const cache = readSkillCache();
59868
- if (cache?.installedSha && cache.latestSha && cache.latestSha !== cache.installedSha) {
59869
- displayNotice();
59870
- }
59871
- const isStale = !cache || Date.now() - cache.lastCheck > CHECK_INTERVAL_MS2;
59872
- if (isStale) {
59873
- fetchLatestSha().then((latest) => {
59874
- const fresh = readSkillCache();
59875
- writeSkillCache({
59876
- lastCheck: Date.now(),
59877
- latestSha: latest ?? fresh?.latestSha ?? "",
59878
- installedSha: fresh?.installedSha ?? ""
59879
- });
59880
- if (latest) {
59881
- logger.debug("skill-update-check", `Cached latest SHA: ${latest}`);
59882
- }
59883
- }).catch((err) => {
59884
- logger.error("skill-update-check", `Background fetch failed: ${err}`);
59885
- });
59886
- }
60653
+ if (!existsSync19(lockPath))
60654
+ return [];
60655
+ const lock = JSON.parse(readFileSync19(lockPath, "utf-8"));
60656
+ const skills = lock?.skills;
60657
+ if (!skills || typeof skills !== "object")
60658
+ return [];
60659
+ const legacy = Object.entries(skills).filter(([, entry]) => entry?.source === LEGACY_SKILL_SOURCE).map(([name]) => name);
60660
+ if (legacy.length === 0)
60661
+ return [];
60662
+ for (const name of legacy)
60663
+ delete skills[name];
60664
+ writeFileSync12(lockPath, `${JSON.stringify(lock, null, 2)}
60665
+ `);
60666
+ logger.debug("skill", `Removed legacy lock entries: ${legacy.join(", ")}`);
60667
+ return legacy;
59887
60668
  } catch (err) {
59888
- logger.error("skill-update-check", `Skill update check failed: ${err}`);
60669
+ logger.debug("skill", `Could not read legacy skill lock: ${err}`);
60670
+ return [];
59889
60671
  }
59890
60672
  }
59891
- var import_picocolors26, CACHE_FILENAME3 = "skill-update-check.json", CHECK_INTERVAL_MS2, FETCH_TIMEOUT_MS2 = 5000, GITHUB_API_URL = "https://api.github.com/repos/dosu-ai/dosu-skill/commits/HEAD";
59892
- var init_skill_update_check = __esm(() => {
59893
- init_config();
59894
- init_logger();
59895
- import_picocolors26 = __toESM(require_picocolors(), 1);
59896
- CHECK_INTERVAL_MS2 = 24 * 60 * 60 * 1000;
59897
- });
59898
-
59899
- // src/commands/skill.ts
59900
- import { exec as exec2, execSync as execSync2 } from "node:child_process";
59901
- import { homedir as homedir8 } from "node:os";
59902
- import { join as join23 } from "node:path";
59903
- function skillAgentIDsForProviders(providerIDs) {
59904
- return [
59905
- ...new Set(providerIDs.map((providerID) => SKILL_AGENT_BY_PROVIDER[providerID]).filter((agent) => Boolean(agent)))
59906
- ];
59907
- }
59908
- function skillInstallTargetForProvider(providerID) {
59909
- const agentID = SKILL_AGENT_BY_PROVIDER[providerID];
59910
- if (!agentID)
59911
- return null;
59912
- if (agentID === "claude-code") {
59913
- const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR?.trim() || join23(homedir8(), ".claude");
59914
- return { path: join23(claudeConfigDir, "skills", SKILL_NAME), symlink: true };
60673
+ function pathExists(path) {
60674
+ try {
60675
+ lstatSync2(path);
60676
+ return true;
60677
+ } catch {
60678
+ return false;
59915
60679
  }
59916
- if (agentID === "windsurf") {
59917
- return {
59918
- path: join23(homedir8(), ".codeium", "windsurf", "skills", SKILL_NAME),
59919
- symlink: true
59920
- };
60680
+ }
60681
+ function writeSkillDir(skill, dir) {
60682
+ rmSync5(dir, { recursive: true, force: true });
60683
+ for (const file of skill.files) {
60684
+ const target = join22(dir, ...file.path.split("/"));
60685
+ mkdirSync11(dirname10(target), { recursive: true });
60686
+ writeFileSync12(target, file.content, { mode: file.executable ? 493 : 420 });
59921
60687
  }
59922
- return {
59923
- path: join23(homedir8(), ".agents", "skills", SKILL_NAME),
59924
- symlink: false
59925
- };
59926
60688
  }
59927
- function skillAgentArgs(providerIDs) {
59928
- const agents = providerIDs === undefined ? SUPPORTED_SKILL_AGENTS : skillAgentIDsForProviders(providerIDs);
59929
- return agents.map((agent) => `-a ${agent}`).join(" ");
60689
+ function linkSkillDir(linkPath, targetDir) {
60690
+ mkdirSync11(dirname10(linkPath), { recursive: true });
60691
+ rmSync5(linkPath, { recursive: true, force: true });
60692
+ try {
60693
+ symlinkSync(relative3(dirname10(linkPath), targetDir), linkPath, "dir");
60694
+ return "symlink";
60695
+ } catch (err) {
60696
+ logger.debug("skill", `Symlink failed for ${linkPath}, copying instead: ${err}`);
60697
+ cpSync(targetDir, linkPath, { recursive: true });
60698
+ return "copy";
60699
+ }
59930
60700
  }
59931
- function execQuiet(command) {
59932
- return new Promise((resolve, reject) => {
59933
- exec2(command, { windowsHide: true }, (error) => {
59934
- if (error)
59935
- reject(error);
59936
- else
59937
- resolve();
59938
- });
59939
- });
60701
+ function removeSkillDir(dir) {
60702
+ if (!pathExists(dir))
60703
+ return false;
60704
+ rmSync5(dir, { recursive: true, force: true });
60705
+ return true;
59940
60706
  }
59941
- async function installSkill(providerIDs, options = {}) {
59942
- const agentArgs = skillAgentArgs(providerIDs);
59943
- if (!agentArgs) {
59944
- logger.debug("skill", "No selected providers support the Dosu skill");
60707
+ function installBundledSkills(agentIDs) {
60708
+ const agents = agentIDs.filter(isSkillAgentID);
60709
+ if (agents.length === 0) {
60710
+ logger.debug("skill", "No selected agents support the Dosu skill");
59945
60711
  return { success: true };
59946
60712
  }
59947
60713
  try {
59948
- const command = `npx skills add ${SKILL_REPO} -g ${agentArgs} -s "*" -y`;
59949
- if (options.quiet)
59950
- await execQuiet(command);
59951
- else
59952
- execSync2(command, { stdio: "inherit" });
60714
+ const legacy = pruneLegacySkillLock();
60715
+ const bundledNames = new Set(BUNDLED_SKILLS.map((skill) => skill.name));
60716
+ const linkDirs = [
60717
+ ...new Set(agents.map(linkedSkillsDir).filter((dir) => !!dir))
60718
+ ];
60719
+ for (const name of legacy) {
60720
+ if (bundledNames.has(name))
60721
+ continue;
60722
+ for (const dir of [universalSkillsDir(), ...linkDirs])
60723
+ removeSkillDir(join22(dir, name));
60724
+ }
60725
+ const paths = [];
60726
+ for (const skill of BUNDLED_SKILLS) {
60727
+ const universal = join22(universalSkillsDir(), skill.name);
60728
+ writeSkillDir(skill, universal);
60729
+ paths.push(universal);
60730
+ for (const dir of linkDirs) {
60731
+ const linkPath = join22(dir, skill.name);
60732
+ linkSkillDir(linkPath, universal);
60733
+ paths.push(linkPath);
60734
+ }
60735
+ }
60736
+ const previous = readSkillInstallState();
60737
+ writeSkillInstallState({
60738
+ version: VERSION,
60739
+ agents: [...new Set([...previous?.agents ?? [], ...agents])],
60740
+ installedAt: Date.now()
60741
+ });
60742
+ rmSync5(join22(getConfigDir(), LEGACY_CACHE_FILENAME), { force: true });
60743
+ logger.info("skill", `Installed bundled skills v${VERSION} for ${agents.join(", ")}`);
60744
+ return { success: true, version: VERSION, paths };
59953
60745
  } catch (err) {
59954
60746
  logger.error("skill", `Failed to install skill: ${err}`);
59955
60747
  return { success: false };
59956
60748
  }
59957
- const sha = await fetchLatestSha();
59958
- if (sha) {
59959
- writeSkillCache({
59960
- lastCheck: Date.now(),
59961
- latestSha: sha,
59962
- installedSha: sha
59963
- });
59964
- return { success: true, sha };
59965
- }
59966
- logger.debug("skill", "Skill installed but could not fetch latest SHA");
59967
- return { success: true };
59968
60749
  }
59969
- function installedSkillNames() {
59970
- let entries;
59971
- try {
59972
- const json = execSync2("npx skills list -g --json", {
59973
- encoding: "utf-8",
59974
- stdio: ["ignore", "pipe", "ignore"]
59975
- });
59976
- const parsed = JSON.parse(json);
59977
- if (!Array.isArray(parsed))
59978
- throw new Error("expected a JSON array");
59979
- entries = parsed;
59980
- } catch (err) {
59981
- logger.debug("skill", `Could not list installed skills: ${err}`);
59982
- return null;
59983
- }
59984
- const names = [];
59985
- for (const entry of entries) {
59986
- if (entry.source !== SKILL_REPO || typeof entry.name !== "string")
59987
- continue;
59988
- if (!SAFE_SKILL_NAME.test(entry.name)) {
59989
- logger.warn("skill", `Skipping skill with an unsupported name: ${entry.name}`);
59990
- continue;
60750
+ async function installSkill(providerIDs) {
60751
+ const agents = providerIDs === undefined ? [...SUPPORTED_SKILL_AGENTS] : skillAgentIDsForProviders(providerIDs);
60752
+ return installBundledSkills(agents);
60753
+ }
60754
+ function removeSkills() {
60755
+ const legacy = pruneLegacySkillLock();
60756
+ const names = new Set([...BUNDLED_SKILLS.map((skill) => skill.name), ...legacy]);
60757
+ const dirs = [
60758
+ universalSkillsDir(),
60759
+ ...new Set(SUPPORTED_SKILL_AGENTS.map(linkedSkillsDir).filter((dir) => !!dir))
60760
+ ];
60761
+ const removed = [];
60762
+ for (const dir of dirs) {
60763
+ for (const name of names) {
60764
+ const path = join22(dir, name);
60765
+ if (removeSkillDir(path))
60766
+ removed.push(path);
59991
60767
  }
59992
- names.push(entry.name);
59993
60768
  }
59994
- return names;
60769
+ clearSkillInstallState();
60770
+ rmSync5(join22(getConfigDir(), LEGACY_CACHE_FILENAME), { force: true });
60771
+ return removed;
60772
+ }
60773
+ function printPaths(paths) {
60774
+ for (const path of paths)
60775
+ console.log(import_picocolors26.default.dim(` ${path}`));
59995
60776
  }
59996
60777
  function skillCommand() {
59997
- const cmd = new Command("skill").description("Manage the Dosu agent skill");
59998
- cmd.command("install").description("Install the Dosu skill for AI coding agents").action(async () => {
59999
- console.log(`Installing skills from ${SKILL_REPO}...`);
60778
+ const cmd = new Command("skill").description("Manage the Dosu agent skills bundled with the CLI");
60779
+ cmd.command("install").description("Install the bundled Dosu skills for AI coding agents").action(async () => {
60780
+ console.log(`Installing Dosu skills (v${VERSION})...`);
60000
60781
  const result = await installSkill();
60001
60782
  if (result.success) {
60002
- console.log(import_picocolors27.default.green(`
60783
+ printPaths(result.paths ?? []);
60784
+ console.log(import_picocolors26.default.green(`
60003
60785
  ✓ Skills installed successfully.`));
60004
60786
  } else {
60005
- console.error(import_picocolors27.default.red(`
60006
- Failed to install skill. Make sure npx is available.`));
60787
+ console.error(import_picocolors26.default.red(`
60788
+ Failed to install skill. Run with --debug for details.`));
60007
60789
  process.exit(1);
60008
60790
  }
60009
60791
  });
60010
60792
  cmd.command("remove").description("Remove the Dosu skills").action(() => {
60011
- const installed = installedSkillNames();
60012
- if (installed?.length === 0) {
60013
- console.log(`No skills from ${SKILL_REPO} are installed.`);
60014
- return;
60015
- }
60016
- const targets = installed ?? [SKILL_NAME];
60017
- console.log(`Removing skills from ${SKILL_REPO}...`);
60018
60793
  try {
60019
- execSync2(`npx skills remove -g ${targets.join(" ")} -y`, {
60020
- stdio: "inherit"
60021
- });
60022
- clearInstalledSha();
60023
- console.log(import_picocolors27.default.green(`
60794
+ const removed = removeSkills();
60795
+ if (removed.length === 0) {
60796
+ console.log("No Dosu skills are installed.");
60797
+ return;
60798
+ }
60799
+ console.log("Removing Dosu skills...");
60800
+ printPaths(removed);
60801
+ console.log(import_picocolors26.default.green(`
60024
60802
  ✓ Skills removed.`));
60025
- } catch {
60026
- console.error(import_picocolors27.default.red(`
60803
+ } catch (err) {
60804
+ logger.error("skill", `Failed to remove skills: ${err}`);
60805
+ console.error(import_picocolors26.default.red(`
60027
60806
  Failed to remove skills.`));
60028
60807
  process.exit(1);
60029
60808
  }
60030
60809
  });
60031
- cmd.command("update").description("Update the Dosu skill to the latest version").action(async () => {
60032
- console.log(`Updating skills from ${SKILL_REPO}...`);
60810
+ cmd.command("update").description("Rewrite the Dosu skills from this CLI version (upgrade the CLI for newer skills)").action(async () => {
60811
+ console.log(`Updating Dosu skills to the copy bundled with v${VERSION}...`);
60033
60812
  const result = await installSkill();
60034
60813
  if (!result.success) {
60035
- console.error(import_picocolors27.default.red(`
60814
+ console.error(import_picocolors26.default.red(`
60036
60815
  Failed to update skill.`));
60037
60816
  process.exit(1);
60038
60817
  }
60039
- console.log(import_picocolors27.default.green(`
60818
+ printPaths(result.paths ?? []);
60819
+ console.log(import_picocolors26.default.green(`
60040
60820
  ✓ Skills updated.`));
60821
+ console.log(import_picocolors26.default.dim(" Skills ship with the CLI; run `dosu upgrade` to get newer ones."));
60041
60822
  });
60042
60823
  return cmd;
60043
60824
  }
60044
- var import_picocolors27, SKILL_REPO = "dosu-ai/dosu-skill", SKILL_NAME = "dosu", SAFE_SKILL_NAME, SUPPORTED_SKILL_AGENTS, SKILL_AGENT_BY_PROVIDER;
60825
+ var import_picocolors26, SKILL_NAME = "dosu", LEGACY_SKILL_SOURCE = "dosu-ai/dosu-skill", INSTALL_STATE_FILENAME = "skill-install.json", LEGACY_CACHE_FILENAME = "skill-update-check.json", SUPPORTED_SKILL_AGENTS, SKILL_AGENT_BY_PROVIDER;
60045
60826
  var init_skill = __esm(() => {
60046
60827
  init_commander();
60828
+ init_config();
60047
60829
  init_logger();
60048
- init_skill_update_check();
60049
- import_picocolors27 = __toESM(require_picocolors(), 1);
60050
- SAFE_SKILL_NAME = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
60830
+ init_skills();
60831
+ import_picocolors26 = __toESM(require_picocolors(), 1);
60051
60832
  SUPPORTED_SKILL_AGENTS = [
60052
60833
  "claude-code",
60053
60834
  "cursor",
@@ -60080,7 +60861,7 @@ var init_skill = __esm(() => {
60080
60861
  function requireConfig11() {
60081
60862
  const cfg = requireLoginConfig();
60082
60863
  if (!cfg.active_account?.target?.org_id) {
60083
- console.error(import_picocolors28.default.red("Missing org config. Run 'dosu setup' to reconfigure."));
60864
+ console.error(import_picocolors27.default.red("Missing org config. Run 'dosu setup' to reconfigure."));
60084
60865
  process.exit(1);
60085
60866
  }
60086
60867
  return cfg;
@@ -60090,7 +60871,7 @@ function rejectWebOnlyProvider(provider, json) {
60090
60871
  if (json) {
60091
60872
  printResult({ provider, cli_supported: false, connect_via: "web", url }, { json: true });
60092
60873
  } else {
60093
- console.error(import_picocolors28.default.yellow(`Connecting '${provider}' sources is web-only for now. Open ${url}, add the source ` + `under Data Sources, then re-run 'dosu sources list'.`));
60874
+ console.error(import_picocolors27.default.yellow(`Connecting '${provider}' sources is web-only for now. Open ${url}, add the source ` + `under Data Sources, then re-run 'dosu sources list'.`));
60094
60875
  }
60095
60876
  process.exit(1);
60096
60877
  }
@@ -60109,7 +60890,7 @@ function sourcesCommand() {
60109
60890
  }
60110
60891
  const list = dataSources ?? [];
60111
60892
  if (list.length === 0) {
60112
- console.log(import_picocolors28.default.dim("No data sources connected."));
60893
+ console.log(import_picocolors27.default.dim("No data sources connected."));
60113
60894
  return;
60114
60895
  }
60115
60896
  printTable(["ID", "Name", "Provider", "Created"], list.map((ds) => [
@@ -60128,7 +60909,7 @@ function sourcesCommand() {
60128
60909
  return;
60129
60910
  }
60130
60911
  if (!ds) {
60131
- console.log(import_picocolors28.default.dim("Data source not found."));
60912
+ console.log(import_picocolors27.default.dim("Data source not found."));
60132
60913
  return;
60133
60914
  }
60134
60915
  printInfo([
@@ -60147,7 +60928,7 @@ function sourcesCommand() {
60147
60928
  printResult({ success: true, id }, opts);
60148
60929
  return;
60149
60930
  }
60150
- console.log(import_picocolors28.default.green(`Data source sync triggered for ${id.slice(0, 8)}.`));
60931
+ console.log(import_picocolors27.default.green(`Data source sync triggered for ${id.slice(0, 8)}.`));
60151
60932
  });
60152
60933
  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) => {
60153
60934
  if (opts.name === undefined && opts.description === undefined) {
@@ -60164,7 +60945,7 @@ function sourcesCommand() {
60164
60945
  printResult(result, opts);
60165
60946
  return;
60166
60947
  }
60167
- console.log(import_picocolors28.default.green("Data source updated."));
60948
+ console.log(import_picocolors27.default.green("Data source updated."));
60168
60949
  });
60169
60950
  cmd.command("delete").description("Delete a data source").argument("<id>", "Data source ID").option("--json", "Output as JSON").action(async (id, opts) => {
60170
60951
  const cfg = requireConfig11();
@@ -60174,7 +60955,7 @@ function sourcesCommand() {
60174
60955
  printResult({ success: true, id }, opts);
60175
60956
  return;
60176
60957
  }
60177
- console.log(import_picocolors28.default.green("Data source deleted."));
60958
+ console.log(import_picocolors27.default.green("Data source deleted."));
60178
60959
  });
60179
60960
  cmd.command("connect").description("Install or update a provider integration (currently GitHub) via the browser").argument("[provider]", "Provider to connect (github)", "github").option("--json", "Emit machine-readable NDJSON progress events").option("--timeout <seconds>", "Seconds to wait for the browser install to complete", String(CONNECT_TIMEOUT_DEFAULT_SECONDS)).option("--no-open", "Print the URL without opening a browser").action(async (provider, opts) => {
60180
60961
  const providerName = provider.toLowerCase();
@@ -60202,14 +60983,14 @@ function sourcesCommand() {
60202
60983
  }));
60203
60984
  } else {
60204
60985
  console.log(`Open this URL to install or update the Dosu GitHub App:
60205
- ${import_picocolors28.default.cyan(url)}`);
60986
+ ${import_picocolors27.default.cyan(url)}`);
60206
60987
  if (opts.open !== false) {
60207
60988
  try {
60208
60989
  const open = await Promise.resolve().then(() => (init_open(), {}));
60209
60990
  await open_default(url);
60210
60991
  } catch {}
60211
60992
  }
60212
- console.log(import_picocolors28.default.dim("Waiting for the install to complete..."));
60993
+ console.log(import_picocolors27.default.dim("Waiting for the install to complete..."));
60213
60994
  }
60214
60995
  const timedOut = new Promise((resolve) => {
60215
60996
  timeoutId = setTimeout(() => resolve(null), timeoutSeconds * 1000);
@@ -60219,7 +61000,7 @@ function sourcesCommand() {
60219
61000
  if (opts.json) {
60220
61001
  console.log(JSON.stringify({ event: "timeout", timeout_seconds: timeoutSeconds }));
60221
61002
  } else {
60222
- console.error(import_picocolors28.default.red(`Timed out after ${timeoutSeconds}s. Finish the install in the browser, then re-run 'dosu sources connect github'.`));
61003
+ console.error(import_picocolors27.default.red(`Timed out after ${timeoutSeconds}s. Finish the install in the browser, then re-run 'dosu sources connect github'.`));
60223
61004
  }
60224
61005
  process.exit(1);
60225
61006
  return;
@@ -60235,14 +61016,14 @@ function sourcesCommand() {
60235
61016
  }));
60236
61017
  return;
60237
61018
  }
60238
- console.log(import_picocolors28.default.green(`GitHub App connected (installation ${result.installation_id}).`));
61019
+ console.log(import_picocolors27.default.green(`GitHub App connected (installation ${result.installation_id}).`));
60239
61020
  if (newRepositories.length > 0) {
60240
61021
  for (const repo of newRepositories) {
60241
61022
  console.log(` ${repo.slug}`);
60242
61023
  }
60243
- console.log(import_picocolors28.default.dim("Next: dosu sources create github --repo <owner/name> --library <library-id>"));
61024
+ console.log(import_picocolors27.default.dim("Next: dosu sources create github --repo <owner/name> --library <library-id>"));
60244
61025
  } else {
60245
- console.log(import_picocolors28.default.dim("No new repositories visible yet — GitHub may still be syncing. " + "Re-run 'dosu sources connect github' or check 'dosu sources list' shortly."));
61026
+ console.log(import_picocolors27.default.dim("No new repositories visible yet — GitHub may still be syncing. " + "Re-run 'dosu sources connect github' or check 'dosu sources list' shortly."));
60246
61027
  }
60247
61028
  } finally {
60248
61029
  clearTimeout(timeoutId);
@@ -60259,7 +61040,7 @@ function sourcesCommand() {
60259
61040
  const orgID = cfg.active_account.target.org_id;
60260
61041
  const libraryID = opts.library ?? cfg.active_account?.target?.space_id;
60261
61042
  if (!libraryID) {
60262
- console.error(import_picocolors28.default.red("No library specified and no active library. Pass --library <id>."));
61043
+ console.error(import_picocolors27.default.red("No library specified and no active library. Pass --library <id>."));
60263
61044
  process.exit(1);
60264
61045
  return;
60265
61046
  }
@@ -60267,12 +61048,12 @@ function sourcesCommand() {
60267
61048
  const repos = await fetchListForOrg(client, orgID);
60268
61049
  const repo = repos.find((r) => r.slug.toLowerCase() === opts.repo.toLowerCase());
60269
61050
  if (!repo) {
60270
- console.error(import_picocolors28.default.red(`Repository '${opts.repo}' is not visible to Dosu. Run ` + `'dosu sources connect github' to grant the GitHub App access, then retry.`));
61051
+ console.error(import_picocolors27.default.red(`Repository '${opts.repo}' is not visible to Dosu. Run ` + `'dosu sources connect github' to grant the GitHub App access, then retry.`));
60271
61052
  process.exit(1);
60272
61053
  return;
60273
61054
  }
60274
61055
  if (repo.is_fork === true) {
60275
- console.error(import_picocolors28.default.red(`'${repo.slug}' is a fork and can't be synced.` + (repo.fork_parent_slug ? ` Connect '${repo.fork_parent_slug}' instead.` : "")));
61056
+ console.error(import_picocolors27.default.red(`'${repo.slug}' is a fork and can't be synced.` + (repo.fork_parent_slug ? ` Connect '${repo.fork_parent_slug}' instead.` : "")));
60276
61057
  process.exit(1);
60277
61058
  return;
60278
61059
  }
@@ -60296,14 +61077,14 @@ function sourcesCommand() {
60296
61077
  dataSourceID: existingDataSources.get(repo.repository_id)
60297
61078
  });
60298
61079
  if (!created) {
60299
- console.error(import_picocolors28.default.red("Could not create the data source. Check 'dosu logs --tail 50' for details."));
61080
+ console.error(import_picocolors27.default.red("Could not create the data source. Check 'dosu logs --tail 50' for details."));
60300
61081
  process.exit(1);
60301
61082
  return;
60302
61083
  }
60303
61084
  const survivors = await verifyDataSourcesPersist(client, orgID, [created.data_source_id]);
60304
61085
  if (survivors.dropped.size > 0) {
60305
61086
  await deleteOrphanDeployment(client, created.deployment_id, repo.slug);
60306
- console.error(import_picocolors28.default.red(`Dosu couldn't sync '${repo.slug}' (the GitHub App may not have access to it). ` + "Nothing was created."));
61087
+ console.error(import_picocolors27.default.red(`Dosu couldn't sync '${repo.slug}' (the GitHub App may not have access to it). ` + "Nothing was created."));
60307
61088
  process.exit(1);
60308
61089
  return;
60309
61090
  }
@@ -60320,13 +61101,13 @@ function sourcesCommand() {
60320
61101
  printResult(receipt, opts);
60321
61102
  return;
60322
61103
  }
60323
- console.log(import_picocolors28.default.green(`Connected ${repo.slug} to library ${libraryID}.`));
60324
- console.log(import_picocolors28.default.dim(` data source ${created.data_source_id}`));
60325
- console.log(import_picocolors28.default.dim(` deployment ${created.deployment_id}`));
61104
+ console.log(import_picocolors27.default.green(`Connected ${repo.slug} to library ${libraryID}.`));
61105
+ console.log(import_picocolors27.default.dim(` data source ${created.data_source_id}`));
61106
+ console.log(import_picocolors27.default.dim(` deployment ${created.deployment_id}`));
60326
61107
  });
60327
61108
  return cmd;
60328
61109
  }
60329
- var import_picocolors28, CONNECT_TIMEOUT_DEFAULT_SECONDS = 600;
61110
+ var import_picocolors27, CONNECT_TIMEOUT_DEFAULT_SECONDS = 600;
60330
61111
  var init_sources = __esm(() => {
60331
61112
  init_commander();
60332
61113
  init_trpc();
@@ -60335,23 +61116,23 @@ var init_sources = __esm(() => {
60335
61116
  init_auth();
60336
61117
  init_confirmation();
60337
61118
  init_output();
60338
- import_picocolors28 = __toESM(require_picocolors(), 1);
61119
+ import_picocolors27 = __toESM(require_picocolors(), 1);
60339
61120
  });
60340
61121
 
60341
61122
  // src/telemetry/settings.ts
60342
61123
  import { randomUUID as randomUUID4 } from "node:crypto";
60343
61124
  import {
60344
61125
  existsSync as existsSync20,
60345
- lstatSync as lstatSync2,
61126
+ lstatSync as lstatSync3,
60346
61127
  mkdirSync as mkdirSync12,
60347
61128
  readFileSync as readFileSync20,
60348
61129
  renameSync as renameSync5,
60349
61130
  unlinkSync as unlinkSync4,
60350
61131
  writeFileSync as writeFileSync13
60351
61132
  } from "node:fs";
60352
- import { join as join24 } from "node:path";
61133
+ import { join as join23 } from "node:path";
60353
61134
  function getTelemetrySettingsPath() {
60354
- return join24(getConfigDir(), TELEMETRY_SETTINGS_FILENAME);
61135
+ return join23(getConfigDir(), TELEMETRY_SETTINGS_FILENAME);
60355
61136
  }
60356
61137
  function loadTelemetrySettings() {
60357
61138
  return readTelemetrySettings().settings;
@@ -60407,7 +61188,7 @@ function readTelemetrySettings() {
60407
61188
  const path = getTelemetrySettingsPath();
60408
61189
  let file;
60409
61190
  try {
60410
- file = lstatSync2(path);
61191
+ file = lstatSync3(path);
60411
61192
  } catch (error) {
60412
61193
  if (isErrorCode(error, "ENOENT")) {
60413
61194
  return { status: "missing", settings: emptyTelemetrySettings() };
@@ -60567,7 +61348,7 @@ var init_telemetry2 = __esm(() => {
60567
61348
  function requireConfig12() {
60568
61349
  const cfg = requireLoginConfig();
60569
61350
  if (!cfg.active_account?.target?.space_id) {
60570
- console.error(import_picocolors29.default.red("Missing space config. Run 'dosu setup' to reconfigure."));
61351
+ console.error(import_picocolors28.default.red("Missing space config. Run 'dosu setup' to reconfigure."));
60571
61352
  process.exit(1);
60572
61353
  }
60573
61354
  return cfg;
@@ -60618,7 +61399,7 @@ function threadsCommand() {
60618
61399
  return;
60619
61400
  }
60620
61401
  if (!threads || threads.length === 0) {
60621
- console.log(import_picocolors29.default.dim("No threads found."));
61402
+ console.log(import_picocolors28.default.dim("No threads found."));
60622
61403
  return;
60623
61404
  }
60624
61405
  printTable(["ID", "Title", "Status", "Created"], threads.map((t) => [
@@ -60643,10 +61424,10 @@ function threadsCommand() {
60643
61424
  return;
60644
61425
  }
60645
61426
  if (!thread) {
60646
- console.log(import_picocolors29.default.dim("Thread not found."));
61427
+ console.log(import_picocolors28.default.dim("Thread not found."));
60647
61428
  return;
60648
61429
  }
60649
- console.log(import_picocolors29.default.bold(thread.generated_title ?? "(untitled thread)"));
61430
+ console.log(import_picocolors28.default.bold(thread.generated_title ?? "(untitled thread)"));
60650
61431
  printInfo([
60651
61432
  ["ID", thread.id],
60652
61433
  ["Created", formatDate(thread.created_at)],
@@ -60657,13 +61438,13 @@ function threadsCommand() {
60657
61438
  if (messages && messages.length > 0) {
60658
61439
  const allMessages = messages.flatMap((group) => group.messages);
60659
61440
  console.log(`
60660
- ${import_picocolors29.default.bold("Messages")} (${allMessages.length})`);
60661
- console.log(import_picocolors29.default.dim("─".repeat(60)));
61441
+ ${import_picocolors28.default.bold("Messages")} (${allMessages.length})`);
61442
+ console.log(import_picocolors28.default.dim("─".repeat(60)));
60662
61443
  for (const msg of allMessages) {
60663
61444
  const role = msg.author_role ?? "unknown";
60664
61445
  const date = formatDate(msg.created_at);
60665
61446
  console.log(`
60666
- ${import_picocolors29.default.bold(role)} ${import_picocolors29.default.dim(date)}`);
61447
+ ${import_picocolors28.default.bold(role)} ${import_picocolors28.default.dim(date)}`);
60667
61448
  if (msg.body) {
60668
61449
  console.log(truncate(msg.body, 500));
60669
61450
  }
@@ -60678,25 +61459,25 @@ ${import_picocolors29.default.bold(role)} ${import_picocolors29.default.dim(date
60678
61459
  printResult({ success: true, id }, opts);
60679
61460
  return;
60680
61461
  }
60681
- console.log(import_picocolors29.default.green(`Thread ${id.slice(0, 8)} archived.`));
61462
+ console.log(import_picocolors28.default.green(`Thread ${id.slice(0, 8)} archived.`));
60682
61463
  });
60683
61464
  return cmd;
60684
61465
  }
60685
- var import_picocolors29;
61466
+ var import_picocolors28;
60686
61467
  var init_threads = __esm(() => {
60687
61468
  init_commander();
60688
61469
  init_trpc();
60689
61470
  init_arguments();
60690
61471
  init_auth();
60691
61472
  init_output();
60692
- import_picocolors29 = __toESM(require_picocolors(), 1);
61473
+ import_picocolors28 = __toESM(require_picocolors(), 1);
60693
61474
  });
60694
61475
 
60695
61476
  // src/commands/topics.ts
60696
61477
  function requireConfig13() {
60697
61478
  const cfg = requireLoginConfig();
60698
61479
  if (!cfg.active_account?.target?.space_id) {
60699
- console.error(import_picocolors30.default.red("Missing space config. Run 'dosu setup' to reconfigure."));
61480
+ console.error(import_picocolors29.default.red("Missing space config. Run 'dosu setup' to reconfigure."));
60700
61481
  process.exit(1);
60701
61482
  }
60702
61483
  return cfg;
@@ -60706,7 +61487,7 @@ async function getKnowledgeStoreId3(client, spaceId) {
60706
61487
  space_id: spaceId
60707
61488
  });
60708
61489
  if (!store) {
60709
- console.error(import_picocolors30.default.red("No knowledge store found for this deployment."));
61490
+ console.error(import_picocolors29.default.red("No knowledge store found for this deployment."));
60710
61491
  process.exit(1);
60711
61492
  }
60712
61493
  return store.id;
@@ -60725,7 +61506,7 @@ function topicsCommand() {
60725
61506
  return;
60726
61507
  }
60727
61508
  if (!topics || topics.length === 0) {
60728
- console.log(import_picocolors30.default.dim("No topics found."));
61509
+ console.log(import_picocolors29.default.dim("No topics found."));
60729
61510
  return;
60730
61511
  }
60731
61512
  printTable(["ID", "Name", "Description"], topics.map((t) => [
@@ -60750,7 +61531,7 @@ function topicsCommand() {
60750
61531
  return;
60751
61532
  }
60752
61533
  if (!pages || pages.length === 0) {
60753
- console.log(import_picocolors30.default.dim("No pages found with this topic."));
61534
+ console.log(import_picocolors29.default.dim("No pages found with this topic."));
60754
61535
  return;
60755
61536
  }
60756
61537
  printTable(["ID", "Title"], pages.map((p) => [
@@ -60760,14 +61541,14 @@ function topicsCommand() {
60760
61541
  });
60761
61542
  return cmd;
60762
61543
  }
60763
- var import_picocolors30;
61544
+ var import_picocolors29;
60764
61545
  var init_topics = __esm(() => {
60765
61546
  init_commander();
60766
61547
  init_trpc();
60767
61548
  init_arguments();
60768
61549
  init_auth();
60769
61550
  init_output();
60770
- import_picocolors30 = __toESM(require_picocolors(), 1);
61551
+ import_picocolors29 = __toESM(require_picocolors(), 1);
60771
61552
  });
60772
61553
 
60773
61554
  // src/commands/upgrade.ts
@@ -60920,7 +61701,7 @@ Could not update Dosu automatically.`);
60920
61701
  ${plan.manualCommand}`);
60921
61702
  return result.status && result.status > 0 ? result.status : 1;
60922
61703
  }
60923
- console.log(import_picocolors31.default.green(`
61704
+ console.log(import_picocolors30.default.green(`
60924
61705
  ✓ Update command completed.`));
60925
61706
  console.log('Run "dosu --version" to verify.');
60926
61707
  return 0;
@@ -60969,7 +61750,7 @@ async function completeUpgrade(channel = INSTALL_CHANNEL, options = {}) {
60969
61750
  try {
60970
61751
  const result = await installSkill();
60971
61752
  if (result.success) {
60972
- console.log(import_picocolors31.default.green("✓ Skills updated."));
61753
+ console.log(import_picocolors30.default.green("✓ Skills updated."));
60973
61754
  } else {
60974
61755
  console.error('Skills could not be refreshed. Run "dosu skill update" to retry.');
60975
61756
  }
@@ -60987,11 +61768,11 @@ function upgradeCommand() {
60987
61768
  process.exitCode = status;
60988
61769
  });
60989
61770
  }
60990
- var import_picocolors31, PACKAGE_NAME = "@dosu/cli", LATEST_PACKAGE, BREW_MANUAL_COMMAND = "brew upgrade dosu-ai/dosu/dosu", NPX_COMMAND = "npx -y @dosu/cli@latest", PROBE_TIMEOUT_MS = 5000, RELEASES_URL = "https://github.com/dosu-ai/dosu-cli/releases/latest", PACKAGE_MANAGERS, SETUP_FALLBACK = 'Run "dosu setup" to finish updating your AI agents.';
61771
+ var import_picocolors30, PACKAGE_NAME = "@dosu/cli", LATEST_PACKAGE, BREW_MANUAL_COMMAND = "brew upgrade dosu-ai/dosu/dosu", NPX_COMMAND = "npx -y @dosu/cli@latest", PROBE_TIMEOUT_MS = 5000, RELEASES_URL = "https://github.com/dosu-ai/dosu-cli/releases/latest", PACKAGE_MANAGERS, SETUP_FALLBACK = 'Run "dosu setup" to finish updating your AI agents.';
60991
61772
  var init_upgrade = __esm(() => {
60992
61773
  init_commander();
60993
61774
  init_skill();
60994
- import_picocolors31 = __toESM(require_picocolors(), 1);
61775
+ import_picocolors30 = __toESM(require_picocolors(), 1);
60995
61776
  LATEST_PACKAGE = `${PACKAGE_NAME}@latest`;
60996
61777
  PACKAGE_MANAGERS = {
60997
61778
  npm: {
@@ -61116,7 +61897,7 @@ var init_antigravity = __esm(() => {
61116
61897
  });
61117
61898
 
61118
61899
  // src/mcp/providers/claude.ts
61119
- import { join as join25 } from "node:path";
61900
+ import { join as join24 } from "node:path";
61120
61901
  var ClaudeProvider = () => createJSONProvider({
61121
61902
  providerName: "Claude Code",
61122
61903
  providerID: "claude",
@@ -61125,24 +61906,24 @@ var ClaudeProvider = () => createJSONProvider({
61125
61906
  paths: ["~/.claude"],
61126
61907
  globalPath: "~/.claude.json",
61127
61908
  topKey: "mcpServers",
61128
- localConfigPath: (cwd) => join25(cwd, ".mcp.json")
61909
+ localConfigPath: (cwd) => join24(cwd, ".mcp.json")
61129
61910
  });
61130
61911
  var init_claude = __esm(() => {
61131
61912
  init_base();
61132
61913
  });
61133
61914
 
61134
61915
  // src/mcp/providers/claude-desktop.ts
61135
- import { join as join26 } from "node:path";
61916
+ import { join as join25 } from "node:path";
61136
61917
  function configPath() {
61137
- return join26(appSupportDir(), "Claude", "claude_desktop_config.json");
61918
+ return join25(appSupportDir(), "Claude", "claude_desktop_config.json");
61138
61919
  }
61139
61920
  var ClaudeDesktopProvider = () => ({
61140
61921
  name: () => "Claude Desktop",
61141
61922
  id: () => "claude-desktop",
61142
61923
  supportsLocal: () => false,
61143
61924
  priority: () => 2,
61144
- detectPaths: () => [join26(appSupportDir(), "Claude")],
61145
- isInstalled: () => isInstalled([join26(appSupportDir(), "Claude")]),
61925
+ detectPaths: () => [join25(appSupportDir(), "Claude")],
61926
+ isInstalled: () => isInstalled([join25(appSupportDir(), "Claude")]),
61146
61927
  globalConfigPath: () => configPath(),
61147
61928
  isConfigured: () => isJSONKeyConfigured(configPath(), "mcpServers"),
61148
61929
  install(cfg, global2) {
@@ -61169,14 +61950,14 @@ var init_claude_desktop = __esm(() => {
61169
61950
  });
61170
61951
 
61171
61952
  // src/mcp/providers/cline.ts
61172
- import { join as join27 } from "node:path";
61173
- var extensionDir = () => join27(appSupportDir(), "Code", "User", "globalStorage", "saoudrizwan.claude-dev"), ClineProvider = () => createJSONProvider({
61953
+ import { join as join26 } from "node:path";
61954
+ var extensionDir = () => join26(appSupportDir(), "Code", "User", "globalStorage", "saoudrizwan.claude-dev"), ClineProvider = () => createJSONProvider({
61174
61955
  providerName: "Cline",
61175
61956
  providerID: "cline",
61176
61957
  local: false,
61177
61958
  priorityValue: 11,
61178
61959
  paths: [extensionDir()],
61179
- globalPath: join27(extensionDir(), "settings", "cline_mcp_settings.json"),
61960
+ globalPath: join26(extensionDir(), "settings", "cline_mcp_settings.json"),
61180
61961
  topKey: "mcpServers",
61181
61962
  buildServer: ({ url, headers }) => ({
61182
61963
  url,
@@ -61191,7 +61972,7 @@ var init_cline = __esm(() => {
61191
61972
  });
61192
61973
 
61193
61974
  // src/mcp/providers/cline-cli.ts
61194
- import { join as join28 } from "node:path";
61975
+ import { join as join27 } from "node:path";
61195
61976
  function clineDir() {
61196
61977
  return process.env.CLINE_DIR ?? expandHome("~/.cline");
61197
61978
  }
@@ -61201,7 +61982,7 @@ var ClineCliProvider = () => createJSONProvider({
61201
61982
  local: false,
61202
61983
  priorityValue: 12,
61203
61984
  paths: [clineDir()],
61204
- globalPath: join28(clineDir(), "data", "settings", "cline_mcp_settings.json"),
61985
+ globalPath: join27(clineDir(), "data", "settings", "cline_mcp_settings.json"),
61205
61986
  topKey: "mcpServers",
61206
61987
  buildServer: ({ url, headers }) => ({
61207
61988
  url,
@@ -61217,14 +61998,14 @@ var init_cline_cli = __esm(() => {
61217
61998
 
61218
61999
  // src/mcp/providers/codex.ts
61219
62000
  import { existsSync as existsSync21, readFileSync as readFileSync21 } from "node:fs";
61220
- import { dirname as dirname10, join as join29 } from "node:path";
62001
+ import { dirname as dirname11, join as join28 } from "node:path";
61221
62002
  function codexHome3() {
61222
62003
  return process.env.CODEX_HOME ?? expandHome("~/.codex");
61223
62004
  }
61224
62005
  function getConfigPath2(global2) {
61225
62006
  if (global2)
61226
- return join29(codexHome3(), "config.toml");
61227
- return join29(process.cwd(), ".codex", "config.toml");
62007
+ return join28(codexHome3(), "config.toml");
62008
+ return join28(process.cwd(), ".codex", "config.toml");
61228
62009
  }
61229
62010
  function readTOML(path) {
61230
62011
  if (!existsSync21(path))
@@ -61304,14 +62085,14 @@ function projectConfigPaths() {
61304
62085
  const chain = [];
61305
62086
  for (let dir = cwd;; ) {
61306
62087
  chain.push(dir);
61307
- if (existsSync21(join29(dir, ".git")))
62088
+ if (existsSync21(join28(dir, ".git")))
61308
62089
  break;
61309
- const parent = dirname10(dir);
62090
+ const parent = dirname11(dir);
61310
62091
  if (parent === dir)
61311
- return [join29(cwd, ".codex", "config.toml")];
62092
+ return [join28(cwd, ".codex", "config.toml")];
61312
62093
  dir = parent;
61313
62094
  }
61314
- return chain.reverse().map((dir) => join29(dir, ".codex", "config.toml"));
62095
+ return chain.reverse().map((dir) => join28(dir, ".codex", "config.toml"));
61315
62096
  }
61316
62097
  function pruneLegacyRemoteEntry(path) {
61317
62098
  if (!existsSync21(path))
@@ -61328,9 +62109,9 @@ var REMOTE_HTTP_KEY, CodexProvider = () => ({
61328
62109
  priority: () => 8,
61329
62110
  detectPaths: () => ["~/.codex"],
61330
62111
  isInstalled: () => isInstalled(["~/.codex"]),
61331
- globalConfigPath: () => join29(codexHome3(), "config.toml"),
62112
+ globalConfigPath: () => join28(codexHome3(), "config.toml"),
61332
62113
  isConfigured: () => {
61333
- const content = readTOML(join29(codexHome3(), "config.toml"));
62114
+ const content = readTOML(join28(codexHome3(), "config.toml"));
61334
62115
  return content.includes("[mcp_servers.dosu]");
61335
62116
  },
61336
62117
  install(cfg, global2) {
@@ -61361,10 +62142,10 @@ var init_codex = __esm(() => {
61361
62142
  });
61362
62143
 
61363
62144
  // src/mcp/providers/copilot.ts
61364
- import { join as join30 } from "node:path";
62145
+ import { join as join29 } from "node:path";
61365
62146
  function globalPath() {
61366
62147
  if (process.env.XDG_CONFIG_HOME) {
61367
- return join30(process.env.XDG_CONFIG_HOME, "mcp-config.json");
62148
+ return join29(process.env.XDG_CONFIG_HOME, "mcp-config.json");
61368
62149
  }
61369
62150
  return expandHome("~/.copilot/mcp-config.json");
61370
62151
  }
@@ -61388,7 +62169,7 @@ var CopilotProvider = () => ({
61388
62169
  };
61389
62170
  installJSONServer(globalPath(), "mcpServers", server);
61390
62171
  } else {
61391
- const configPath = join30(process.cwd(), ".vscode", "mcp.json");
62172
+ const configPath = join29(process.cwd(), ".vscode", "mcp.json");
61392
62173
  const server = {
61393
62174
  type: "http",
61394
62175
  url,
@@ -61401,7 +62182,7 @@ var CopilotProvider = () => ({
61401
62182
  if (global2) {
61402
62183
  removeJSONServer(globalPath(), "mcpServers");
61403
62184
  } else {
61404
- const configPath = join30(process.cwd(), ".vscode", "mcp.json");
62185
+ const configPath = join29(process.cwd(), ".vscode", "mcp.json");
61405
62186
  removeJSONServer(configPath, "servers");
61406
62187
  }
61407
62188
  }
@@ -61412,7 +62193,7 @@ var init_copilot = __esm(() => {
61412
62193
  });
61413
62194
 
61414
62195
  // src/mcp/providers/cursor.ts
61415
- import { join as join31 } from "node:path";
62196
+ import { join as join30 } from "node:path";
61416
62197
  var CursorProvider = () => createJSONProvider({
61417
62198
  providerName: "Cursor",
61418
62199
  providerID: "cursor",
@@ -61425,14 +62206,14 @@ var CursorProvider = () => createJSONProvider({
61425
62206
  url,
61426
62207
  headers
61427
62208
  }),
61428
- localConfigPath: (cwd) => join31(cwd, ".cursor", "mcp.json")
62209
+ localConfigPath: (cwd) => join30(cwd, ".cursor", "mcp.json")
61429
62210
  });
61430
62211
  var init_cursor = __esm(() => {
61431
62212
  init_base();
61432
62213
  });
61433
62214
 
61434
62215
  // src/mcp/providers/factory.ts
61435
- import { join as join32 } from "node:path";
62216
+ import { join as join31 } from "node:path";
61436
62217
  var FactoryProvider = () => createJSONProvider({
61437
62218
  providerName: "Factory",
61438
62219
  providerID: "factory",
@@ -61441,14 +62222,14 @@ var FactoryProvider = () => createJSONProvider({
61441
62222
  paths: ["~/.factory"],
61442
62223
  globalPath: "~/.factory/mcp.json",
61443
62224
  topKey: "mcpServers",
61444
- localConfigPath: (cwd) => join32(cwd, ".factory", "mcp.json")
62225
+ localConfigPath: (cwd) => join31(cwd, ".factory", "mcp.json")
61445
62226
  });
61446
62227
  var init_factory = __esm(() => {
61447
62228
  init_base();
61448
62229
  });
61449
62230
 
61450
62231
  // src/mcp/providers/gemini.ts
61451
- import { join as join33 } from "node:path";
62232
+ import { join as join32 } from "node:path";
61452
62233
  var GeminiProvider = () => createJSONProvider({
61453
62234
  providerName: "Gemini CLI",
61454
62235
  providerID: "gemini",
@@ -61457,7 +62238,7 @@ var GeminiProvider = () => createJSONProvider({
61457
62238
  paths: ["~/.gemini"],
61458
62239
  globalPath: "~/.gemini/settings.json",
61459
62240
  topKey: "mcpServers",
61460
- localConfigPath: (cwd) => join33(cwd, ".gemini", "settings.json")
62241
+ localConfigPath: (cwd) => join32(cwd, ".gemini", "settings.json")
61461
62242
  });
61462
62243
  var init_gemini = __esm(() => {
61463
62244
  init_base();
@@ -61500,7 +62281,7 @@ var init_manual = __esm(() => {
61500
62281
 
61501
62282
  // src/mcp/providers/mcporter.ts
61502
62283
  import { existsSync as existsSync22 } from "node:fs";
61503
- import { join as join34 } from "node:path";
62284
+ import { join as join33 } from "node:path";
61504
62285
  function resolveGlobalConfigPath() {
61505
62286
  const jsonPath = expandHome("~/.mcporter/mcporter.json");
61506
62287
  if (existsSync22(jsonPath))
@@ -61520,7 +62301,7 @@ var MCPorterProvider = () => ({
61520
62301
  globalConfigPath: () => resolveGlobalConfigPath(),
61521
62302
  isConfigured: () => isJSONKeyConfigured(resolveGlobalConfigPath(), "mcpServers"),
61522
62303
  install(cfg, global2) {
61523
- const configPath = global2 ? resolveGlobalConfigPath() : join34(process.cwd(), "config", "mcporter.json");
62304
+ const configPath = global2 ? resolveGlobalConfigPath() : join33(process.cwd(), "config", "mcporter.json");
61524
62305
  const server = {
61525
62306
  type: "http",
61526
62307
  url: mcpEndpoint(cfg),
@@ -61529,7 +62310,7 @@ var MCPorterProvider = () => ({
61529
62310
  installJSONServer(configPath, "mcpServers", server);
61530
62311
  },
61531
62312
  remove(global2) {
61532
- const configPath = global2 ? resolveGlobalConfigPath() : join34(process.cwd(), "config", "mcporter.json");
62313
+ const configPath = global2 ? resolveGlobalConfigPath() : join33(process.cwd(), "config", "mcporter.json");
61533
62314
  removeJSONServer(configPath, "mcpServers");
61534
62315
  }
61535
62316
  });
@@ -61539,7 +62320,7 @@ var init_mcporter = __esm(() => {
61539
62320
  });
61540
62321
 
61541
62322
  // src/mcp/providers/opencode.ts
61542
- import { join as join35 } from "node:path";
62323
+ import { join as join34 } from "node:path";
61543
62324
  var OpenCodeProvider = () => createJSONProvider({
61544
62325
  providerName: "OpenCode",
61545
62326
  providerID: "opencode",
@@ -61554,23 +62335,23 @@ var OpenCodeProvider = () => createJSONProvider({
61554
62335
  enabled: true,
61555
62336
  headers
61556
62337
  }),
61557
- localConfigPath: (cwd) => join35(cwd, "opencode.json")
62338
+ localConfigPath: (cwd) => join34(cwd, "opencode.json")
61558
62339
  });
61559
62340
  var init_opencode = __esm(() => {
61560
62341
  init_base();
61561
62342
  });
61562
62343
 
61563
62344
  // src/mcp/providers/vscode.ts
61564
- import { join as join36 } from "node:path";
62345
+ import { join as join35 } from "node:path";
61565
62346
  var VSCodeProvider = () => createJSONProvider({
61566
62347
  providerName: "VS Code",
61567
62348
  providerID: "vscode",
61568
62349
  local: true,
61569
62350
  priorityValue: 6,
61570
- paths: [join36(appSupportDir(), "Code")],
61571
- globalPath: join36(appSupportDir(), "Code", "User", "mcp.json"),
62351
+ paths: [join35(appSupportDir(), "Code")],
62352
+ globalPath: join35(appSupportDir(), "Code", "User", "mcp.json"),
61572
62353
  topKey: "servers",
61573
- localConfigPath: (cwd) => join36(cwd, ".vscode", "mcp.json")
62354
+ localConfigPath: (cwd) => join35(cwd, ".vscode", "mcp.json")
61574
62355
  });
61575
62356
  var init_vscode = __esm(() => {
61576
62357
  init_detect();
@@ -61579,14 +62360,14 @@ var init_vscode = __esm(() => {
61579
62360
 
61580
62361
  // src/mcp/providers/windsurf.ts
61581
62362
  import { homedir as homedir10 } from "node:os";
61582
- import { join as join37 } from "node:path";
62363
+ import { join as join36 } from "node:path";
61583
62364
  var WindsurfProvider = () => createJSONProvider({
61584
62365
  providerName: "Windsurf",
61585
62366
  providerID: "windsurf",
61586
62367
  local: false,
61587
62368
  priorityValue: 9,
61588
- paths: [join37(homedir10(), ".codeium", "windsurf")],
61589
- globalPath: join37(homedir10(), ".codeium", "windsurf", "mcp_config.json"),
62369
+ paths: [join36(homedir10(), ".codeium", "windsurf")],
62370
+ globalPath: join36(homedir10(), ".codeium", "windsurf", "mcp_config.json"),
61590
62371
  topKey: "mcpServers"
61591
62372
  });
61592
62373
  var init_windsurf = __esm(() => {
@@ -61594,27 +62375,27 @@ var init_windsurf = __esm(() => {
61594
62375
  });
61595
62376
 
61596
62377
  // src/mcp/providers/zed.ts
61597
- import { rmSync as rmSync5 } from "node:fs";
62378
+ import { rmSync as rmSync6 } from "node:fs";
61598
62379
  import { homedir as homedir11, platform as platform3 } from "node:os";
61599
- import { join as join38 } from "node:path";
62380
+ import { join as join37 } from "node:path";
61600
62381
  function zedConfigDir() {
61601
62382
  const os = platform3();
61602
62383
  if (os === "win32")
61603
- return join38(appSupportDir(), "Zed");
62384
+ return join37(appSupportDir(), "Zed");
61604
62385
  if (os === "darwin")
61605
- return join38(homedir11(), ".config", "zed");
61606
- return join38(appSupportDir(), "zed");
62386
+ return join37(homedir11(), ".config", "zed");
62387
+ return join37(appSupportDir(), "zed");
61607
62388
  }
61608
62389
  function zedDataDir() {
61609
62390
  const os = platform3();
61610
62391
  if (os === "darwin")
61611
- return join38(appSupportDir(), "Zed");
62392
+ return join37(appSupportDir(), "Zed");
61612
62393
  if (os === "win32")
61613
- return join38(process.env.LOCALAPPDATA ?? "", "Zed");
61614
- return join38(process.env.XDG_DATA_HOME ?? join38(homedir11(), ".local", "share"), "zed");
62394
+ return join37(process.env.LOCALAPPDATA ?? "", "Zed");
62395
+ return join37(process.env.XDG_DATA_HOME ?? join37(homedir11(), ".local", "share"), "zed");
61615
62396
  }
61616
62397
  function legacyDarwinSettingsPath() {
61617
- return platform3() === "darwin" ? join38(appSupportDir(), "Zed", "settings.json") : null;
62398
+ return platform3() === "darwin" ? join37(appSupportDir(), "Zed", "settings.json") : null;
61618
62399
  }
61619
62400
  function removeLegacyDosuEntry(path) {
61620
62401
  let cfg;
@@ -61629,7 +62410,7 @@ function removeLegacyDosuEntry(path) {
61629
62410
  delete servers.dosu;
61630
62411
  const nothingElse = Object.keys(cfg).length === 1 && Object.keys(servers).length === 0;
61631
62412
  if (nothingElse)
61632
- rmSync5(path, { force: true });
62413
+ rmSync6(path, { force: true });
61633
62414
  else
61634
62415
  saveJSONConfig(path, cfg);
61635
62416
  }
@@ -61640,10 +62421,10 @@ var ZedProvider = (legacyPath = legacyDarwinSettingsPath()) => {
61640
62421
  local: true,
61641
62422
  priorityValue: 10,
61642
62423
  paths: [zedConfigDir(), zedDataDir()],
61643
- globalPath: join38(zedConfigDir(), "settings.json"),
62424
+ globalPath: join37(zedConfigDir(), "settings.json"),
61644
62425
  topKey: "context_servers",
61645
62426
  buildServer: ({ url, headers }) => ({ url, headers }),
61646
- localConfigPath: (cwd) => join38(cwd, ".zed", "settings.json")
62427
+ localConfigPath: (cwd) => join37(cwd, ".zed", "settings.json")
61647
62428
  });
61648
62429
  if (!legacyPath)
61649
62430
  return provider;
@@ -61749,7 +62530,7 @@ var init_refresh = __esm(() => {
61749
62530
 
61750
62531
  // src/version/update-check.ts
61751
62532
  import { existsSync as existsSync23, mkdirSync as mkdirSync13, readFileSync as readFileSync22, writeFileSync as writeFileSync14 } from "node:fs";
61752
- import { join as join39 } from "node:path";
62533
+ import { join as join38 } from "node:path";
61753
62534
  function isValidVersion(value) {
61754
62535
  return typeof value === "string" && SEMVER_PATTERN.test(value);
61755
62536
  }
@@ -61770,12 +62551,12 @@ function isNewerVersion(latest, current) {
61770
62551
  }
61771
62552
  return false;
61772
62553
  }
61773
- function getCachePath3() {
61774
- return join39(getConfigDir(), CACHE_FILENAME4);
62554
+ function getCachePath2() {
62555
+ return join38(getConfigDir(), CACHE_FILENAME3);
61775
62556
  }
61776
62557
  function readCache() {
61777
62558
  try {
61778
- const path = getCachePath3();
62559
+ const path = getCachePath2();
61779
62560
  if (!existsSync23(path))
61780
62561
  return null;
61781
62562
  const data = JSON.parse(readFileSync22(path, "utf-8"));
@@ -61793,12 +62574,12 @@ function writeCache(cache) {
61793
62574
  if (!existsSync23(dir)) {
61794
62575
  mkdirSync13(dir, { recursive: true, mode: 448 });
61795
62576
  }
61796
- writeFileSync14(getCachePath3(), JSON.stringify(cache), { mode: 384 });
62577
+ writeFileSync14(getCachePath2(), JSON.stringify(cache), { mode: 384 });
61797
62578
  } catch {}
61798
62579
  }
61799
62580
  async function fetchLatestVersion() {
61800
62581
  const controller = new AbortController;
61801
- const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS3);
62582
+ const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS2);
61802
62583
  try {
61803
62584
  const resp = await fetch(REGISTRY_URL, { signal: controller.signal });
61804
62585
  if (!resp.ok)
@@ -61821,29 +62602,29 @@ function buildUpdateHint(channel, npx = false) {
61821
62602
  function styleHint(hint) {
61822
62603
  const match = hint.match(/^(.*)("[^"]+")(.*)$/);
61823
62604
  if (!match)
61824
- return import_picocolors32.default.dim(hint);
62605
+ return import_picocolors31.default.dim(hint);
61825
62606
  const [, before, command, after] = match;
61826
- return [before && import_picocolors32.default.dim(before), import_picocolors32.default.cyan(command), after && import_picocolors32.default.dim(after)].filter(Boolean).join("");
62607
+ return [before && import_picocolors31.default.dim(before), import_picocolors31.default.cyan(command), after && import_picocolors31.default.dim(after)].filter(Boolean).join("");
61827
62608
  }
61828
62609
  function buildUpdateNotice(current, latest, channel, interactive, npx = false, width = process.stderr.columns ?? 80) {
61829
62610
  const hint = buildUpdateHint(channel, npx);
61830
62611
  if (interactive) {
61831
62612
  const content = [
61832
- `Update available: ${import_picocolors32.default.dim(current)} ${import_picocolors32.default.dim("→")} ${import_picocolors32.default.bold(brand(latest))}`,
62613
+ `Update available: ${import_picocolors31.default.dim(current)} ${import_picocolors31.default.dim("→")} ${import_picocolors31.default.bold(brand(latest))}`,
61833
62614
  styleHint(hint)
61834
62615
  ];
61835
62616
  const innerWidth = Math.max(...content.map(visibleWidth2)) + BOX_PADDING * 2;
61836
62617
  const framed = (line) => {
61837
62618
  const pad = innerWidth - visibleWidth2(line);
61838
62619
  const left = Math.floor(pad / 2);
61839
- return `${import_picocolors32.default.yellow("│")}${" ".repeat(left)}${line}${" ".repeat(pad - left)}${import_picocolors32.default.yellow("│")}`;
62620
+ return `${import_picocolors31.default.yellow("│")}${" ".repeat(left)}${line}${" ".repeat(pad - left)}${import_picocolors31.default.yellow("│")}`;
61840
62621
  };
61841
62622
  const box = [
61842
- import_picocolors32.default.yellow(`╭${"─".repeat(innerWidth)}╮`),
62623
+ import_picocolors31.default.yellow(`╭${"─".repeat(innerWidth)}╮`),
61843
62624
  framed(""),
61844
62625
  ...content.map(framed),
61845
62626
  framed(""),
61846
- import_picocolors32.default.yellow(`╰${"─".repeat(innerWidth)}╯`)
62627
+ import_picocolors31.default.yellow(`╰${"─".repeat(innerWidth)}╯`)
61847
62628
  ];
61848
62629
  return `
61849
62630
  ${centerBlock(box, width).join(`
@@ -61861,17 +62642,17 @@ function getAvailableUpdate() {
61861
62642
  const cache = readCache();
61862
62643
  return cache && isNewerVersion(cache.latestVersion, VERSION) ? cache.latestVersion : null;
61863
62644
  }
61864
- function displayNotice2(current, latest) {
62645
+ function displayNotice(current, latest) {
61865
62646
  console.error(buildUpdateNotice(current, latest, INSTALL_CHANNEL, process.stderr.isTTY === true, isNpxInvocation()));
61866
62647
  }
61867
62648
  async function checkForUpdates(options = {}) {
61868
62649
  const notify = options.notify ?? true;
61869
62650
  try {
61870
62651
  const cache = readCache();
61871
- const isStale = !cache || Date.now() - cache.lastCheck > CHECK_INTERVAL_MS3;
62652
+ const isStale = !cache || Date.now() - cache.lastCheck > CHECK_INTERVAL_MS2;
61872
62653
  if (!isStale) {
61873
62654
  if (notify && isNewerVersion(cache.latestVersion, VERSION)) {
61874
- displayNotice2(VERSION, cache.latestVersion);
62655
+ displayNotice(VERSION, cache.latestVersion);
61875
62656
  }
61876
62657
  return;
61877
62658
  }
@@ -61885,26 +62666,26 @@ async function checkForUpdates(options = {}) {
61885
62666
  logger.debug("update-check", `Cached latest version: ${latest}`);
61886
62667
  }
61887
62668
  if (notify && isNewerVersion(latestKnownVersion, VERSION)) {
61888
- displayNotice2(VERSION, latestKnownVersion);
62669
+ displayNotice(VERSION, latestKnownVersion);
61889
62670
  }
61890
62671
  } catch (err) {
61891
62672
  logger.error("update-check", `Update check failed: ${err}`);
61892
62673
  }
61893
62674
  }
61894
- var import_picocolors32, CACHE_FILENAME4 = "update-check.json", CHECK_INTERVAL_MS3, FETCH_TIMEOUT_MS3 = 1000, REGISTRY_URL = "https://registry.npmjs.org/-/package/@dosu/cli/dist-tags", SEMVER_PATTERN, BOX_PADDING = 3;
62675
+ var import_picocolors31, CACHE_FILENAME3 = "update-check.json", CHECK_INTERVAL_MS2, FETCH_TIMEOUT_MS2 = 1000, REGISTRY_URL = "https://registry.npmjs.org/-/package/@dosu/cli/dist-tags", SEMVER_PATTERN, BOX_PADDING = 3;
61895
62676
  var init_update_check = __esm(() => {
61896
62677
  init_config();
61897
62678
  init_logger();
61898
62679
  init_styles();
61899
62680
  init_layout();
61900
- import_picocolors32 = __toESM(require_picocolors(), 1);
61901
- CHECK_INTERVAL_MS3 = 6 * 60 * 60 * 1000;
62681
+ import_picocolors31 = __toESM(require_picocolors(), 1);
62682
+ CHECK_INTERVAL_MS2 = 6 * 60 * 60 * 1000;
61902
62683
  SEMVER_PATTERN = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
61903
62684
  });
61904
62685
 
61905
62686
  // src/version/mcp-refresh-check.ts
61906
62687
  import { existsSync as existsSync24, mkdirSync as mkdirSync14, readFileSync as readFileSync23, writeFileSync as writeFileSync15 } from "node:fs";
61907
- import { join as join40 } from "node:path";
62688
+ import { join as join39 } from "node:path";
61908
62689
  function needsMcpRefresh(previous, current) {
61909
62690
  if (previous === null)
61910
62691
  return true;
@@ -61913,12 +62694,12 @@ function needsMcpRefresh(previous, current) {
61913
62694
  const [older, newer] = isNewerVersion(current, previous) ? [previous, current] : [current, previous];
61914
62695
  return MCP_FORMAT_CHANGES.some((change) => isNewerVersion(change, older) && !isNewerVersion(change, newer));
61915
62696
  }
61916
- function getCachePath4() {
61917
- return join40(getConfigDir(), CACHE_FILENAME5);
62697
+ function getCachePath3() {
62698
+ return join39(getConfigDir(), CACHE_FILENAME4);
61918
62699
  }
61919
62700
  function readMcpRefreshCache() {
61920
62701
  try {
61921
- const path = getCachePath4();
62702
+ const path = getCachePath3();
61922
62703
  if (!existsSync24(path))
61923
62704
  return null;
61924
62705
  const data = JSON.parse(readFileSync23(path, "utf-8"));
@@ -61935,7 +62716,7 @@ function writeMcpRefreshCache(cache) {
61935
62716
  if (!existsSync24(dir)) {
61936
62717
  mkdirSync14(dir, { recursive: true, mode: 448 });
61937
62718
  }
61938
- writeFileSync15(getCachePath4(), JSON.stringify(cache), { mode: 384 });
62719
+ writeFileSync15(getCachePath3(), JSON.stringify(cache), { mode: 384 });
61939
62720
  } catch {}
61940
62721
  }
61941
62722
  function canRefreshMcp(cfg) {
@@ -61944,10 +62725,10 @@ function canRefreshMcp(cfg) {
61944
62725
  return false;
61945
62726
  return cfg.mode === MODE_OSS || Boolean(target.deployment_id);
61946
62727
  }
61947
- function displayNotice3(names) {
62728
+ function displayNotice2(names) {
61948
62729
  console.error(`
61949
- ${import_picocolors33.default.green(`✓ Dosu ${VERSION}: refreshed MCP config for ${names.join(", ")}`)}
61950
- ` + `${import_picocolors33.default.dim(` Run ${import_picocolors33.default.cyan('"dosu setup"')} to also update skills, hooks, and rules, then restart your AI agents.`)}
62730
+ ${import_picocolors32.default.green(`✓ Dosu ${VERSION}: refreshed MCP config for ${names.join(", ")}`)}
62731
+ ` + `${import_picocolors32.default.dim(` Run ${import_picocolors32.default.cyan('"dosu setup"')} to also update hooks and rules, then restart your AI agents.`)}
61951
62732
  `);
61952
62733
  }
61953
62734
  function checkForMcpRefresh(options = {}) {
@@ -61969,31 +62750,63 @@ function checkForMcpRefresh(options = {}) {
61969
62750
  writeMcpRefreshCache({ version: VERSION });
61970
62751
  logger.info("mcp-refresh", `Version ${VERSION}: refreshed ${result.updated.length}, failed ${result.failed.length}`);
61971
62752
  if (notify && result.updated.length > 0) {
61972
- displayNotice3(result.updated.map((provider) => provider.name()));
62753
+ displayNotice2(result.updated.map((provider) => provider.name()));
61973
62754
  }
61974
62755
  } catch (err) {
61975
62756
  logger.error("mcp-refresh", `MCP refresh check failed: ${err}`);
61976
62757
  }
61977
62758
  }
61978
- var import_picocolors33, CACHE_FILENAME5 = "mcp-refresh.json", MCP_FORMAT_CHANGES;
62759
+ var import_picocolors32, CACHE_FILENAME4 = "mcp-refresh.json", MCP_FORMAT_CHANGES;
61979
62760
  var init_mcp_refresh_check = __esm(() => {
61980
62761
  init_config();
61981
62762
  init_logger();
61982
62763
  init_refresh();
61983
62764
  init_update_check();
61984
- import_picocolors33 = __toESM(require_picocolors(), 1);
62765
+ import_picocolors32 = __toESM(require_picocolors(), 1);
61985
62766
  MCP_FORMAT_CHANGES = ["0.53.0"];
61986
62767
  });
61987
62768
 
62769
+ // src/version/skill-update-check.ts
62770
+ function displayNotice3() {
62771
+ console.error(`
62772
+ ${import_picocolors33.default.green(`✓ Dosu ${VERSION}: refreshed the bundled agent skills`)}
62773
+ ` + `${import_picocolors33.default.dim(" Restart your AI agents to pick up the new skill content.")}
62774
+ `);
62775
+ }
62776
+ function checkForSkillUpdates(options = {}) {
62777
+ const notify = options.notify ?? true;
62778
+ try {
62779
+ const state = readSkillInstallState();
62780
+ if (!state || state.version === VERSION)
62781
+ return;
62782
+ const result = installBundledSkills(state.agents);
62783
+ if (!result.success) {
62784
+ logger.error("skill-update-check", `Skill refresh to ${VERSION} failed; will retry`);
62785
+ return;
62786
+ }
62787
+ logger.info("skill-update-check", `Refreshed skills from ${state.version} to ${VERSION}`);
62788
+ if (notify && result.version)
62789
+ displayNotice3();
62790
+ } catch (err) {
62791
+ logger.error("skill-update-check", `Skill update check failed: ${err}`);
62792
+ }
62793
+ }
62794
+ var import_picocolors33;
62795
+ var init_skill_update_check = __esm(() => {
62796
+ init_skill();
62797
+ init_logger();
62798
+ import_picocolors33 = __toESM(require_picocolors(), 1);
62799
+ });
62800
+
61988
62801
  // src/rules/installer.ts
61989
62802
  import { existsSync as existsSync25, mkdirSync as mkdirSync15, readFileSync as readFileSync24, unlinkSync as unlinkSync5, writeFileSync as writeFileSync16 } from "node:fs";
61990
62803
  import { homedir as homedir12 } from "node:os";
61991
- import { dirname as dirname11, join as join41 } from "node:path";
62804
+ import { dirname as dirname12, join as join40 } from "node:path";
61992
62805
  function claudeConfigDir4() {
61993
- return process.env.CLAUDE_CONFIG_DIR || join41(homedir12(), ".claude");
62806
+ return process.env.CLAUDE_CONFIG_DIR || join40(homedir12(), ".claude");
61994
62807
  }
61995
62808
  function codexHome4() {
61996
- return process.env.CODEX_HOME || join41(homedir12(), ".codex");
62809
+ return process.env.CODEX_HOME || join40(homedir12(), ".codex");
61997
62810
  }
61998
62811
  function isRuleAgent(agent) {
61999
62812
  return Object.hasOwn(RULE_TARGETS, agent);
@@ -62019,7 +62832,7 @@ async function fetchDosuRule(fetchImpl = globalThis.fetch) {
62019
62832
  return normalizeRule(FALLBACK_DOSU_RULE);
62020
62833
  }
62021
62834
  function ensureParent(path) {
62022
- mkdirSync15(dirname11(path), { recursive: true });
62835
+ mkdirSync15(dirname12(path), { recursive: true });
62023
62836
  }
62024
62837
  function writeIfChanged(path, content) {
62025
62838
  if (!existsSync25(path)) {
@@ -62135,39 +62948,39 @@ var init_installer = __esm(() => {
62135
62948
  RULE_TARGETS = {
62136
62949
  claude: {
62137
62950
  kind: "file",
62138
- path: () => join41(claudeConfigDir4(), "rules", "dosu.md")
62951
+ path: () => join40(claudeConfigDir4(), "rules", "dosu.md")
62139
62952
  },
62140
62953
  cursor: {
62141
62954
  kind: "file",
62142
- path: () => join41(homedir12(), ".cursor", "rules", "dosu.mdc"),
62955
+ path: () => join40(homedir12(), ".cursor", "rules", "dosu.mdc"),
62143
62956
  cursorFrontmatter: true
62144
62957
  },
62145
62958
  codex: {
62146
62959
  kind: "section",
62147
- path: () => join41(codexHome4(), "AGENTS.md")
62960
+ path: () => join40(codexHome4(), "AGENTS.md")
62148
62961
  },
62149
62962
  opencode: {
62150
62963
  kind: "section",
62151
- path: () => join41(homedir12(), ".config", "opencode", "AGENTS.md")
62964
+ path: () => join40(homedir12(), ".config", "opencode", "AGENTS.md")
62152
62965
  },
62153
62966
  gemini: {
62154
62967
  kind: "section",
62155
- path: () => join41(homedir12(), ".gemini", "GEMINI.md")
62968
+ path: () => join40(homedir12(), ".gemini", "GEMINI.md")
62156
62969
  },
62157
62970
  antigravity: {
62158
62971
  kind: "section",
62159
- path: () => join41(homedir12(), ".gemini", "GEMINI.md")
62972
+ path: () => join40(homedir12(), ".gemini", "GEMINI.md")
62160
62973
  }
62161
62974
  };
62162
62975
  });
62163
62976
 
62164
62977
  // src/setup/agents-md-step.ts
62165
- import { execSync as execSync3 } from "node:child_process";
62978
+ import { execSync as execSync2 } from "node:child_process";
62166
62979
  import { existsSync as existsSync26, readFileSync as readFileSync25, writeFileSync as writeFileSync17 } from "node:fs";
62167
- import { join as join42 } from "node:path";
62980
+ import { join as join41 } from "node:path";
62168
62981
  function inGitWorkTree(cwd = process.cwd()) {
62169
62982
  try {
62170
- const stdout = execSync3("git rev-parse --is-inside-work-tree", {
62983
+ const stdout = execSync2("git rev-parse --is-inside-work-tree", {
62171
62984
  cwd,
62172
62985
  stdio: ["ignore", "pipe", "ignore"]
62173
62986
  });
@@ -62178,7 +62991,7 @@ function inGitWorkTree(cwd = process.cwd()) {
62178
62991
  }
62179
62992
  function dosuAgentsSectionState(cwd = process.cwd()) {
62180
62993
  try {
62181
- const path = join42(cwd, "AGENTS.md");
62994
+ const path = join41(cwd, "AGENTS.md");
62182
62995
  if (!existsSync26(path))
62183
62996
  return "missing";
62184
62997
  const content = readFileSync25(path, "utf-8");
@@ -62216,7 +63029,7 @@ function findSection2(content) {
62216
63029
  return { start, end };
62217
63030
  }
62218
63031
  function upsertDosuAgentsSection(cwd = process.cwd(), content = FALLBACK_DOSU_RULE) {
62219
- const path = join42(cwd, "AGENTS.md");
63032
+ const path = join41(cwd, "AGENTS.md");
62220
63033
  if (!existsSync26(path)) {
62221
63034
  const section = buildDosuAgentsSection(content);
62222
63035
  writeFileSync17(path, `${section}
@@ -62293,9 +63106,9 @@ var MCP_PROVIDER_SLUG2 = "dosu_mcp";
62293
63106
  // src/sessions/session-title.ts
62294
63107
  import { existsSync as existsSync27, mkdirSync as mkdirSync16, readFileSync as readFileSync26, renameSync as renameSync6, statSync as statSync9, writeFileSync as writeFileSync18 } from "node:fs";
62295
63108
  import { homedir as homedir13 } from "node:os";
62296
- import { join as join43 } from "node:path";
63109
+ import { join as join42 } from "node:path";
62297
63110
  function cachePath2(configDir) {
62298
- return join43(configDir, CACHE_FILENAME6);
63111
+ return join42(configDir, CACHE_FILENAME5);
62299
63112
  }
62300
63113
  function loadCacheFile2(configDir) {
62301
63114
  try {
@@ -62352,10 +63165,10 @@ function reconstructSession(harness, id, slug, home = homedir13(), exists = exis
62352
63165
  return null;
62353
63166
  const candidates = [];
62354
63167
  if (harness === "claude") {
62355
- candidates.push(join43(home, ".claude", "projects", slug, `${id}.jsonl`));
63168
+ candidates.push(join42(home, ".claude", "projects", slug, `${id}.jsonl`));
62356
63169
  } else if (harness === "cursor") {
62357
- const project = join43(home, ".cursor", "projects", slug);
62358
- candidates.push(join43(project, "agent-transcripts", id, `${id}.jsonl`), join43(project, "agent-transcripts", `${id}.jsonl`));
63170
+ const project = join42(home, ".cursor", "projects", slug);
63171
+ candidates.push(join42(project, "agent-transcripts", id, `${id}.jsonl`), join42(project, "agent-transcripts", `${id}.jsonl`));
62359
63172
  } else {
62360
63173
  return null;
62361
63174
  }
@@ -62418,7 +63231,7 @@ function createSessionTitleResolver(configDir = getConfigDir(), deps = {}) {
62418
63231
  }
62419
63232
  };
62420
63233
  }
62421
- var CACHE_FILENAME6 = "session-titles.json", CACHE_SCHEMA_VERSION2 = 3, HEAD_LINES2 = 50, SESSION_NAME_MAX = 80;
63234
+ var CACHE_FILENAME5 = "session-titles.json", CACHE_SCHEMA_VERSION2 = 3, HEAD_LINES2 = 50, SESSION_NAME_MAX = 80;
62422
63235
  var init_session_title = __esm(() => {
62423
63236
  init_config();
62424
63237
  init_read();
@@ -63930,9 +64743,9 @@ async function runInstallSkill(providers) {
63930
64743
  const agentLabel = providers.length === 1 ? "agent" : "agents";
63931
64744
  spinner.start(`Installing skill for ${providers.length} ${agentLabel}`);
63932
64745
  try {
63933
- const result = await installSkill(providers.map((provider) => provider.id()), { quiet: true });
64746
+ const result = await installSkill(providers.map((provider) => provider.id()));
63934
64747
  if (result.success) {
63935
- logger.info("setup", `Skill installed${result.sha ? ` sha=${result.sha}` : ""}`);
64748
+ logger.info("setup", `Skill installed${result.version ? ` v${result.version}` : ""}`);
63936
64749
  const items = providers.flatMap((provider) => {
63937
64750
  const target = skillInstallTargetForProvider(provider.id());
63938
64751
  if (!target)
@@ -66079,7 +66892,7 @@ async function runAgentSetup(opts) {
66079
66892
  }
66080
66893
  if (skillAgentIDsForProviders([provider.id()]).length > 0) {
66081
66894
  try {
66082
- const skill = await installSkill([provider.id()], { quiet: true });
66895
+ const skill = await installSkill([provider.id()]);
66083
66896
  if (!skill.success) {
66084
66897
  throw new Error("the skills installer failed");
66085
66898
  }
@@ -66087,7 +66900,8 @@ async function runAgentSetup(opts) {
66087
66900
  step: "skill_install",
66088
66901
  tool: provider.id(),
66089
66902
  tool_name: provider.name(),
66090
- source: "dosu-ai/dosu-skill"
66903
+ source: "@dosu/cli",
66904
+ version: skill.version
66091
66905
  });
66092
66906
  } catch (err) {
66093
66907
  emitError({
@@ -66469,7 +67283,7 @@ function createProgram(options = {}) {
66469
67283
  if (!process.env.CI) {
66470
67284
  await checkForUpdates({ notify: !launchesTUI });
66471
67285
  }
66472
- checkForSkillUpdates();
67286
+ checkForSkillUpdates({ notify: !launchesTUI });
66473
67287
  checkForReadyTasks();
66474
67288
  if (shouldRunMcpRefreshCheck(actionCommand)) {
66475
67289
  checkForMcpRefresh({ notify: !launchesTUI });
@@ -66947,4 +67761,4 @@ main().catch((err) => {
66947
67761
  process.exit(1);
66948
67762
  });
66949
67763
 
66950
- //# debugId=9cb59d41-7339-0702-6475-6e2164756e21
67764
+ //# debugId=ecb91fd5-693a-ffc0-6475-6e2164756e21