{"_id":"@aiwayds/dsh-profile-switch","_rev":"4-1f75ea85039d23d33a1504f347f241d7","name":"@aiwayds/dsh-profile-switch","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.0":{"name":"@aiwayds/dsh-profile-switch","version":"0.1.0","keywords":["dsh","dsh-plugin","profile","model-profile","model","thinking","ask-user","workspace"],"author":{"name":"fliu56"},"license":"MIT","_id":"@aiwayds/dsh-profile-switch@0.1.0","maintainers":[{"name":"aiwayds","email":"aiway.ds@qq.com"}],"homepage":"https://github.com/fan56/dsh-profile-switch","bugs":{"url":"https://github.com/fan56/dsh-profile-switch/issues"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"}},"dist":{"shasum":"11755cda9971d928b2f204671fffbb3e8ce7c161","tarball":"https://registry.npmjs.org/@aiwayds/dsh-profile-switch/-/dsh-profile-switch-0.1.0.tgz","fileCount":36,"integrity":"sha512-9yTz9ivyyvRdqnJ0h5zSLmrefGlWpbmsrXH8j6lNil6qoVlewC9oC79GAyF3e8DQiJ6g7owm214Q81+zcQbVfg==","signatures":[{"sig":"MEYCIQClvSHJFljN6m8YL2J8OCSPNaS/gjy5tTo8bS1HQn9wGwIhAJP87/6Is0/QE55oeJGGw3N/RJiX4teCrdQvpjk2C70d","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aiwayds%2fdsh-profile-switch@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":216970},"main":"lib/index.js","type":"module","types":"lib/index.d.ts","engines":{"node":">=22.19.0"},"gitHead":"d37fef29f55f479a8a95a74d69b8c4cb067c1a55","scripts":{"test":"npm run build && node --test test/*.test.mjs","build":"tsc -p tsconfig.json","check":"tsc --noEmit -p tsconfig.json","smoke":"node scripts/smoke-boot.mjs","contract":"node scripts/contract-check.mjs","link-closure":"node scripts/link-dsh-closure.mjs"},"_npmUser":{"name":"aiwayds","email":"aiway.ds@qq.com"},"deprecated":"apply() lacks the mount idempotence guard — double-mounting (tui-pi 2.17.0+ auto-mount + an explicit bundles entry) crashes the boot; use 0.1.1+","repository":{"url":"git+https://github.com/fan56/dsh-profile-switch.git","type":"git"},"_npmVersion":"10.9.8","description":"dsh plugin: switch named model profiles (default model, think level, per-subagent models) interactively via the host ask-user flow — one implementation for the TUI and web surfaces, a clean fast-fail on headless","directories":{},"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.9.0","@types/node":"^24.0.0","@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/dsh-llm":"0.1.5-rc.2","@deepseek-ai/dsh-agent":"0.1.5-rc.2","@deepseek-ai/dsh-commands":"0.1.5-rc.2","@deepseek-ai/dsh-user-questions":"0.1.5-rc.2"},"peerDependencies":{"@deepseek-ai/dsh-llm":">=0.1.5-rc.2","@deepseek-ai/dsh-agent":">=0.1.5-rc.2","@deepseek-ai/dsh-commands":">=0.1.5-rc.2","@deepseek-ai/dsh-user-questions":">=0.1.5-rc.2"},"peerDependenciesMeta":{"@deepseek-ai/dsh-llm":{"optional":true},"@deepseek-ai/dsh-agent":{"optional":true},"@deepseek-ai/dsh-commands":{"optional":true},"@deepseek-ai/dsh-user-questions":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/dsh-profile-switch_0.1.0_1789175536687_0.6577708179979558","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@aiwayds/dsh-profile-switch","version":"0.1.1","keywords":["dsh","dsh-plugin","profile","model-profile","model","thinking","ask-user","workspace"],"author":{"name":"fliu56"},"license":"MIT","_id":"@aiwayds/dsh-profile-switch@0.1.1","maintainers":[{"name":"aiwayds","email":"aiway.ds@qq.com"}],"homepage":"https://github.com/fan56/dsh-profile-switch","bugs":{"url":"https://github.com/fan56/dsh-profile-switch/issues"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"}},"dist":{"shasum":"801211b76baa04f0097e38af704c296321adf8f1","tarball":"https://registry.npmjs.org/@aiwayds/dsh-profile-switch/-/dsh-profile-switch-0.1.1.tgz","fileCount":36,"integrity":"sha512-TkG2rEfG3i5sDOSr29t0j/FQroRXbOmyQjdz1oGd9+18uoP3thGZYPKS4FqPyb1qGf+m5WOgzMoCi3WVqMhutQ==","signatures":[{"sig":"MEQCIC1v78lCxcLaCkuStpBFz48gmMNdYkTDDCo4zyJrhB4xAiBIDlCbJJ1Pc/mySTv/KSP9fEWue8e8Q4K4CYM/XMGP0w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aiwayds%2fdsh-profile-switch@0.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":219461},"main":"lib/index.js","type":"module","types":"lib/index.d.ts","engines":{"node":">=22.19.0"},"gitHead":"c0b876c77cef10bbfa2d2e5999432237b66700e4","scripts":{"test":"npm run build && node --test test/*.test.mjs","build":"tsc -p tsconfig.json","check":"tsc --noEmit -p tsconfig.json","smoke":"node scripts/smoke-boot.mjs","contract":"node scripts/contract-check.mjs","link-closure":"node scripts/link-dsh-closure.mjs"},"_npmUser":{"name":"aiwayds","email":"aiway.ds@qq.com"},"repository":{"url":"git+https://github.com/fan56/dsh-profile-switch.git","type":"git"},"_npmVersion":"10.9.8","description":"dsh plugin: switch named model profiles (default model, think level, per-subagent models) interactively via the host ask-user flow — one implementation for the TUI and web surfaces, a clean fast-fail on headless","directories":{},"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.9.0","@types/node":"^24.0.0","@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/dsh-llm":"0.1.5-rc.2","@deepseek-ai/dsh-agent":"0.1.5-rc.2","@deepseek-ai/dsh-commands":"0.1.5-rc.2","@deepseek-ai/dsh-user-questions":"0.1.5-rc.2"},"peerDependencies":{"@deepseek-ai/dsh-llm":">=0.1.5-rc.2","@deepseek-ai/dsh-agent":">=0.1.5-rc.2","@deepseek-ai/dsh-commands":">=0.1.5-rc.2","@deepseek-ai/dsh-user-questions":">=0.1.5-rc.2"},"peerDependenciesMeta":{"@deepseek-ai/dsh-llm":{"optional":true},"@deepseek-ai/dsh-agent":{"optional":true},"@deepseek-ai/dsh-commands":{"optional":true},"@deepseek-ai/dsh-user-questions":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/dsh-profile-switch_0.1.1_1789180692917_0.5019740888836719","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@aiwayds/dsh-profile-switch","version":"0.1.2","description":"dsh plugin: switch named model profiles (default model, think level, per-subagent models) interactively via the host ask-user flow — one implementation for the TUI and web surfaces, a clean fast-fail on headless","type":"module","main":"lib/index.js","types":"lib/index.d.ts","license":"MIT","keywords":["dsh","dsh-plugin","profile","model-profile","model","thinking","ask-user","workspace"],"repository":{"type":"git","url":"git+https://github.com/fan56/dsh-profile-switch.git"},"homepage":"https://github.com/fan56/dsh-profile-switch","engines":{"node":">=22.19.0"},"scripts":{"build":"tsc -p tsconfig.json","check":"tsc --noEmit -p tsconfig.json","link-closure":"node scripts/link-dsh-closure.mjs","smoke":"node scripts/smoke-boot.mjs","test":"npm run build && node --test test/*.test.mjs","contract":"node scripts/contract-check.mjs","postinstall":"node scripts/link-dsh-closure.mjs"},"peerDependencies":{"@deepseek-ai/dsh-agent":">=0.1.5-rc.2","@deepseek-ai/dsh-commands":">=0.1.5-rc.2","@deepseek-ai/dsh-llm":">=0.1.5-rc.2","@deepseek-ai/dsh-user-questions":">=0.1.5-rc.2"},"peerDependenciesMeta":{"@deepseek-ai/dsh-agent":{"optional":true},"@deepseek-ai/dsh-commands":{"optional":true},"@deepseek-ai/dsh-llm":{"optional":true},"@deepseek-ai/dsh-user-questions":{"optional":true}},"devDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/dsh-agent":"0.1.5-rc.2","@deepseek-ai/dsh-commands":"0.1.5-rc.2","@deepseek-ai/dsh-llm":"0.1.5-rc.2","@deepseek-ai/dsh-user-questions":"0.1.5-rc.2","@types/node":"^24.0.0","typescript":"^5.9.0"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"}},"author":{"name":"fliu56"},"publishConfig":{"access":"public"},"_id":"@aiwayds/dsh-profile-switch@0.1.2","gitHead":"70c0f74bb4728293f4ed6c06bbc8dd118fc6b6a1","bugs":{"url":"https://github.com/fan56/dsh-profile-switch/issues"},"_nodeVersion":"22.23.2","_npmVersion":"10.9.8","dist":{"integrity":"sha512-KwliyUZ+ruzMtOyHf+k1Bqwx42DsNBhLu5VJDfm3RZfMpBTD1pjFLOW3xnEiNtiUNXwO3EmxHX/UfPOLdtFagw==","shasum":"7885d9364074f97b61baa4be79ad4dc70f6e6082","tarball":"https://registry.npmjs.org/@aiwayds/dsh-profile-switch/-/dsh-profile-switch-0.1.2.tgz","fileCount":36,"unpackedSize":220130,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aiwayds%2fdsh-profile-switch@0.1.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIG+qreE9RyOCQuS3crvbmZjHqfTsLz8voIYP0E2J8RYNAiEAi6GDwZIIEHNYLavhowhA5coYx8zhoDht+cyABJ7FIhk="}]},"_npmUser":{"name":"aiwayds","email":"aiway.ds@qq.com"},"directories":{},"maintainers":[{"name":"aiwayds","email":"aiway.ds@qq.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dsh-profile-switch_0.1.2_1789354168032_0.022059233963853897"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-12T01:12:16.526Z","modified":"2026-09-14T02:49:28.622Z","0.1.0":"2026-09-12T01:12:16.829Z","0.1.1":"2026-09-12T02:38:13.053Z","0.1.2":"2026-09-14T02:49:28.165Z"},"bugs":{"url":"https://github.com/fan56/dsh-profile-switch/issues"},"author":{"name":"fliu56"},"license":"MIT","homepage":"https://github.com/fan56/dsh-profile-switch","keywords":["dsh","dsh-plugin","profile","model-profile","model","thinking","ask-user","workspace"],"repository":{"type":"git","url":"git+https://github.com/fan56/dsh-profile-switch.git"},"description":"dsh plugin: switch named model profiles (default model, think level, per-subagent models) interactively via the host ask-user flow — one implementation for the TUI and web surfaces, a clean fast-fail on headless","maintainers":[{"name":"aiwayds","email":"aiway.ds@qq.com"}],"readme":"# dsh-profile-switch\n\nA [dsh](https://www.npmjs.com/package/@deepseek-ai/dsh) plugin: **named model\nprofiles you can switch and configure interactively through the host's native\nask-user flow — one implementation that works on the TUI and the web surface,\nand fails fast with guidance on headless.**\n\nA *model profile* is a snapshot of your whole model configuration:\n\n- the **default model + think level** (a saved `/model` selection), and\n- optional **per-subagent model/thinking overrides**.\n\nSwitching between contexts (`work` ↔ `personal`) becomes one command instead\nof a `/model` + per-agent tour.\n\n> **\"profile\" means two different things in dsh — this plugin is the model\n> kind.** A dsh *profile* (`~/.dsh/profiles/<name>/`, `dsh --profile <name>`)\n> is the boot-time plugin composition; it cannot change while the process\n> runs. The *model profiles* this plugin switches live in\n> `~/.dsh/model-profiles.json`, apply at runtime, and are scoped to the\n> workspace tree that binds them.\n\n## Install\n\n```bash\ndsh plugin --profile <your-profile> add @aiwayds/dsh-profile-switch\n```\n\nThe plugin mounts with `inject: ['commands', 'userQuestions']` — both are\ndsh-base services, so it coexists with any surface and any plugin stack.\n\n## Commands\n\n### `/profile-switch`\n\nOne question: which profile this workspace tree binds to. Answering applies\nthe profile in layers:\n\n1. **Live default model** — when a live-selection channel exists: on the TUI\n   through dsh-tui-pi's selection bridge, on the web through the session\n   controller. The current conversation continues on the new model\n   immediately. Without a channel the summary says so; the route still lands\n   through the tree pin on the next session.\n2. **Tree binding** — writes `.dsh-profile` into the current directory\n   (nearest file up the tree wins, `.nvmrc` style), so every NEW session in\n   this tree assembles its initial selection from the profile. Other trees\n   are untouched: a switch is workspace-scoped, never machine-global.\n3. **Subagent overrides** — written nowhere at apply time. Each agent's\n   runtime model/thinking is composed at spawn from the agent file's\n   frontmatter baseline ⊕ this pinned profile's overrides (recomputed on\n   every dispatch, including continuations), which is what keeps a switch\n   fully workspace-scoped.\n\nThe switch deliberately does NOT write the global `agent-default-model`\nsetting — that stays `/model`'s write, and crossing tree boundaries is\nexactly what a profile switch must not do.\n\nThe list also carries **`(unbind this tree)`** when the tree is bound:\nremoves the pin (guarded — a hand-decorated pin file is never clobbered; the\nplugin refuses and says so).\n\n### `/profile-cfg`\n\nThe configuration wizard — an operation menu, then the matching flow:\n\n| Operation | What it asks |\n| --- | --- |\n| `new` | name → default model chain → per-subagent overrides |\n| `edit` | pick a profile → re-answer the same chain (current values shown in the questions) |\n| `save-current` | name → captures the live selection (or the deployment default) → optionally snapshot every discovered agent's baseline |\n| `rename` | pick a profile → new name |\n| `delete` | pick a profile → confirm (the last remaining profile is refused) |\n\nEvery model choice is a **three-step narrowing chain** of separate ask-user\nquestions — provider → that provider's models → that model's think levels —\nbecause each step's options depend on the previous answer. All three lists\nare read live from the installed llm adapters (`listProviders` /\n`listModels` / `resolveModelInfo`), so think levels are exactly what the\nadapter serves — never hardcoded (the `llm-deepseek` route rejects `medium`;\nonly the adapter knows what a model accepts). A provider that lists nothing\nfalls back to typing a model id; a model with no selectable efforts skips\nthe think step.\n\nCancel anywhere (Esc / closing the question) aborts the wizard with **nothing\nsaved** — the store is written exactly once, at the end.\n\n## Subagent overrides (with dsh-subagent-registry)\n\nWhen [dsh-subagent-registry](https://github.com/fan56/dsh-subagent-registry)\nis installed, the `new`/`edit` wizards add a multi-select over your\ndiscovered agents (`~/.dsh/agents/*.md`), then the same provider → model →\nthink chain per selected agent — with **`(inherit)`** leading every step.\nComposing semantics:\n\n- a recorded non-empty value wins over the agent file's frontmatter;\n- an empty entry (both steps inherited) records an *explicit inherit*;\n- agents absent from the profile compose from the baseline.\n\n**Without the registry** the overrides would have no consumer, so the\nper-agent section is skipped with a note and profiles simply hold the main\ndefault model — detection is a contract-member probe\n(`composeAgentRuntime` / `readModelProfilesDoc` / `workspaceProfileName`),\nthe same convention dsh-tui-pi established.\n\n## Surfaces\n\n| | TUI | web | headless |\n| --- | --- | --- | --- |\n| Question rendering | dsh-tui-pi's ask-user dock panel | the web composer takeover | — |\n| Live default-model switch | yes (tui-pi bridge) | yes (session controller) | n/a |\n| Tree binding + store | yes | yes | via files |\n| No-answerer behavior | — | — | fast-fail with guidance |\n\nOn a surface with no ask-user answerer (headless runs one task and exits),\nthe commands fail fast with guidance pointing at the non-interactive path:\nwrite `<workspace>/.dsh-profile` and edit `~/.dsh/model-profiles.json`\ndirectly. Nothing hangs.\n\n## Storage & files\n\n- `~/.dsh/model-profiles.json` — the store (`$DSH_HOME` honored). Versioned\n  (`version: 1`), self-healing (a corrupt/unknown file degrades to the\n  seeded `work` / `personal` / `other` profiles, never throws), atomically\n  written (tmp sibling + rename). **This file is a shared contract**:\n  dsh-subagent-registry reads it (spawn-time composition) and dsh-tui-pi's\n  session bootstrap reads it (new-session seeding from the pin). Schema:\n\n  ```jsonc\n  {\n    \"version\": 1,\n    \"current\": \"work\",            // informational, last applied anywhere\n    \"profiles\": [\n      {\n        \"name\": \"work\",\n        \"defaultModel\": { \"provider\": \"zai-coding-cn\", \"model\": \"glm-5.3\", \"reasoningEffort\": \"high\" },\n        \"agents\": {\n          \"workhorse\": { \"model\": \"volc-ark-plan/deepseek-v4-flash\", \"thinking\": \"high\" },\n          \"oldfox\": {}              // empty entry = explicit inherit\n        }\n      }\n    ]\n  }\n  ```\n\n- `<workspace>/.dsh-profile` — the tree pin: one line naming the profile;\n  blank lines and `#` comments allowed. The plugin overwrites it on a switch\n  ONLY when it parses as exactly one entry line — a hand-decorated file is\n  refused and surfaced, never clobbered.\n\n## Relation to dsh-tui-pi\n\nThe model-profile feature moved here from dsh-tui-pi (which carried it as\nTUI-only panels). Pairing:\n\n- **with** a dsh-tui-pi that provides the `dshTuiModelSelection` bridge:\n  `/profile-switch` also live-switches the current TUI session's default\n  model;\n- with an older/newer tui-pi without the bridge: everything else works; the\n  live leg degrades to \"next session in this tree\" and the summary says so;\n- the per-agent editing entry in tui-pi's `/agents` manager writes the same\n  store with the same schema — both editors coexist;\n- **dsh-tui-pi ≥ 2.18.1 recommended on the TUI.** tui-pi 2.16.0–2.18.0\n  dropped these command names from its never-aborting dispatch list while\n  moving the panels here, so a `/profile-cfg` session longer than 90s echoed\n  a spurious `aborted due to timeout` (the panel itself kept working;\n  2.18.1 restored the dispatch). On web/headless surfaces no such guard\n  exists and any plugin version pairs with anything.\n\nNo manual profile wiring is expected anywhere: `dsh plugin add` reconciles\nthe bundle entry, the bundle patch mounts the plugin, and the commands\nregister on every surface the profile boots.\n\n## Uninstall\n\n```bash\ndsh plugin --profile <your-profile> remove @aiwayds/dsh-profile-switch\n```\n\nThe plugin owns no daemons and holds no host resources, so removal is clean\non the next boot. Your data is intentionally preserved:\n\n- `~/.dsh/model-profiles.json` — delete it if you want the store gone;\n- `<workspace>/.dsh-profile` pins — delete per tree (`rm .dsh-profile`); a\n  pin naming a missing profile simply binds nothing.\n\n## Development\n\n```bash\npnpm install\npnpm build && pnpm check && pnpm test   # unit suite (builds first)\nnode scripts/smoke-boot.mjs             # real-host boot gate (needs global dsh)\npnpm contract                           # write↔read handshake with the registry\n                                        # (auto-skips where no registry resolves)\n```\n\nThe contract check proves the deployed three-repo shape on real files: the\nplugin's store write (pin + per-agent overrides) composed back through the\nregistry's `composeAgentRuntime` — override wins, explicit-inherit and\nbaseline fallback hold, and the probe leg confirms `registryDetected()`\nresolves through the profile's sibling node_modules exactly as it does in a\nlive deployment. On machines/profiles without the registry it degrades to a\ndocumented skip, so it can run anywhere.\n\n`scripts/link-dsh-closure.mjs` re-points `node_modules/@deepseek-ai/*` at\nthe global dsh CLI's own closure so typecheck and tests see exactly one\ncordis. CI runs the same steps on Node 22/24 plus the boot smoke, and a\ndaily schedule watches for upstream rc/stable drift.\n\nLicense — MIT.\n","readmeFilename":"README.md"}