@norman-else/dsh-claude 0.1.27 → 0.1.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/INSTALL.md CHANGED
@@ -1,55 +1,55 @@
1
- # Agent Installation Runbook
2
-
3
- This runbook is idempotent for a local `dsh-claude` checkout and an existing DSH `web` profile.
4
-
5
- ## 1. Verify the checkout
6
-
7
- ```sh
8
- cd /path/to/dsh-claude
9
- export PATH="/opt/homebrew/bin:$PATH"
10
- pnpm install
11
- pnpm check
12
- node lib/bin.mjs doctor
13
- ```
14
-
15
- Stop if Doctor cannot find an authenticated local Claude Code installation. Do not request, copy, or write credentials.
16
-
17
- ## 2. Link the bundle into the current Web profile
18
-
19
- The bundle retains its package-contained system preset and installs a protected compatibility copy at `$DSH_HOME/.agent-presets/claude` during Host activation. This works around supported DSH release-candidate builds replacing third-party preset roots. Existing user-modified files are preserved rather than overwritten.
20
-
21
- ```sh
22
- dsh plugin --profile web add "link:$(pwd)"
23
- ```
24
-
25
- Do not start another DSH Web server. This bundle must load in the existing app at `http://127.0.0.1:56454`.
26
-
27
- ## 3. Refresh and smoke test
28
-
29
- 1. Refresh the existing DSH Web page.
30
- 2. Confirm **Claude** appears in the new-session Agent Preset picker.
31
- 3. Run one existing native preset prompt and verify it remains native.
32
- 4. Create a Claude session and send a read-only prompt.
33
- 5. Send one edit prompt; verify DSH displays a permission request. Exercise reject first, then allow once with a harmless temporary file.
34
- 6. Cancel a running prompt and confirm the cancelled session owns no child `claude` process that is still executing cancelled work or left orphaned/unowned.
35
- 7. Refresh the browser and continue the session.
36
- 8. Restart DSH and confirm the next prompt resumes the persisted Claude session.
37
-
38
- A live prompt can consume the user's Claude subscription. Keep it minimal.
39
-
40
- ## 4. Uninstall
41
-
42
- Clean up the managed preset while the profile can still execute the package CLI, then remove the plugin:
43
-
44
- ```sh
45
- dsh plugin --profile web exec dsh-claude remove-preset
46
- dsh plugin --profile web remove @norman-else/dsh-claude
47
- ```
48
-
49
- DSH has no plugin uninstall lifecycle hook, so direct package removal can leave the compatibility preset behind. After direct removal, no source checkout is required; run the matching package version:
50
-
51
- ```sh
52
- pnpm dlx @norman-else/dsh-claude@<version> remove-preset
53
- ```
54
-
55
- Cleanup refuses to delete user-modified preset content.
1
+ # Agent Installation Runbook
2
+
3
+ This runbook is idempotent for a local `dsh-claude` checkout and an existing DSH `web` profile.
4
+
5
+ ## 1. Verify the checkout
6
+
7
+ ```sh
8
+ cd /path/to/dsh-claude
9
+ export PATH="/opt/homebrew/bin:$PATH"
10
+ pnpm install
11
+ pnpm check
12
+ node lib/bin.mjs doctor
13
+ ```
14
+
15
+ Stop if Doctor cannot find an authenticated local Claude Code installation. Do not request, copy, or write credentials.
16
+
17
+ ## 2. Link the bundle into the current Web profile
18
+
19
+ The bundle retains its package-contained system preset and installs a protected compatibility copy at `$DSH_HOME/.agent-presets/claude` during Host activation. This works around supported DSH release-candidate builds replacing third-party preset roots. Existing user-modified files are preserved rather than overwritten.
20
+
21
+ ```sh
22
+ dsh plugin --profile web add "link:$(pwd)"
23
+ ```
24
+
25
+ Do not start another DSH Web server. This bundle must load in the existing app at `http://127.0.0.1:56454`.
26
+
27
+ ## 3. Refresh and smoke test
28
+
29
+ 1. Refresh the existing DSH Web page.
30
+ 2. Confirm **Claude** appears in the new-session Agent Preset picker.
31
+ 3. Run one existing native preset prompt and verify it remains native.
32
+ 4. Create a Claude session and send a read-only prompt.
33
+ 5. Send one edit prompt; verify DSH displays a permission request. Exercise reject first, then allow once with a harmless temporary file.
34
+ 6. Cancel a running prompt and confirm the cancelled session owns no child `claude` process that is still executing cancelled work or left orphaned/unowned.
35
+ 7. Refresh the browser and continue the session.
36
+ 8. Restart DSH and confirm the next prompt resumes the persisted Claude session.
37
+
38
+ A live prompt can consume the user's Claude subscription. Keep it minimal.
39
+
40
+ ## 4. Uninstall
41
+
42
+ Clean up the managed preset while the profile can still execute the package CLI, then remove the plugin:
43
+
44
+ ```sh
45
+ dsh plugin --profile web exec dsh-claude remove-preset
46
+ dsh plugin --profile web remove @norman-else/dsh-claude
47
+ ```
48
+
49
+ DSH has no plugin uninstall lifecycle hook, so direct package removal can leave the compatibility preset behind. After direct removal, no source checkout is required; run the matching package version:
50
+
51
+ ```sh
52
+ pnpm dlx @norman-else/dsh-claude@<version> remove-preset
53
+ ```
54
+
55
+ Cleanup refuses to delete user-modified preset content.
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 dsh-claude contributors
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 dsh-claude contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,82 +1,82 @@
1
- # dsh-claude
2
-
3
- ## 1. Overview
4
-
5
- `dsh-claude` runs the locally installed Claude Code CLI as a first-class conversation provider inside DeepSeek Harness (DSH). It uses Claude Code's official Agent SDK protocol instead of recreating the agent with a separate API client.
6
-
7
- Claude Code remains responsible for its agent loop, tools, `CLAUDE.md`, Skills, Hooks, Plugins, MCP servers, settings, and authentication. DSH provides the conversation UI, approval and question surfaces, repository workflow, activity presentation, and managed process lifetime.
8
-
9
- ## 2. Installation and removal
10
-
11
- ### Requirements
12
-
13
- - DeepSeek Harness Desktop with compatible public plugin APIs. This package is currently developed against the DSH `0.1.1-rc.2` package line.
14
- - A local Claude Code installation that is already authenticated.
15
- - Node.js 20 or later when installing from a source checkout.
16
-
17
- The plugin never asks for or stores Claude credentials. Authenticate through the local Claude Code CLI before using the plugin.
18
-
19
- ### Install from npm
20
-
21
- Add the published package to the DSH Web profile:
22
-
23
- ```sh
24
- dsh plugin --profile web add @norman-else/dsh-claude
25
- ```
26
-
27
- Wait for the profile rebuild to finish, then restart DSH Desktop if requested. Create a new conversation and select **Claude** from the Agent Preset picker.
28
-
29
- ### Install from source
30
-
31
- ```sh
32
- git clone https://github.com/Norman-else/dsh-claude.git
33
- cd dsh-claude
34
- pnpm install
35
- pnpm check
36
- ```
37
-
38
- Link the checkout to DSH from PowerShell:
39
-
40
- ```powershell
41
- dsh plugin --profile web add "link:$PWD"
42
- ```
43
-
44
- Or from macOS/Linux:
45
-
46
- ```sh
47
- dsh plugin --profile web add "link:$(pwd)"
48
- ```
49
-
50
- ### Remove the plugin
51
-
52
- Remove the managed compatibility preset before removing the package:
53
-
54
- ```sh
55
- dsh plugin --profile web exec dsh-claude remove-preset
56
- dsh plugin --profile web remove @norman-else/dsh-claude
57
- ```
58
-
59
- DSH does not currently expose a plugin uninstall lifecycle hook. If the package was removed before its managed preset was cleaned up, run the matching installed version directly:
60
-
61
- ```sh
62
- pnpm dlx @norman-else/dsh-claude@<version> remove-preset
63
- ```
64
-
65
- Preset cleanup removes only installer-managed content and refuses to delete user-modified preset files.
66
-
67
- ## 3. Features
68
-
69
- - **Native Claude Code conversations** — Runs Claude Code as the main agent in a normal DSH conversation instead of wrapping it as a tool or secondary chat.
70
- - **Claude preset and model selection** — Adds a `Claude` Agent Preset and exposes Claude Code's `default`, `opus[1m]`, `fable`, `sonnet`, and `haiku` model choices.
71
- - **Local Claude environment compatibility** — Preserves the user's existing Claude Code authentication, settings, `CLAUDE.md`, Skills, Hooks, Plugins, tools, and MCP configuration.
72
- - **Real-time streaming and conversation continuity** — Streams Claude responses and tool activity into DSH while retaining multi-turn context and persisted Claude session resume.
73
- - **DSH permissions and questions** — Routes Claude tool permission requests through DSH approvals and Claude clarification prompts through DSH's native question forms.
74
- - **Managed process lifecycle** — Keeps one live Claude process per active session, serializes turns, evicts idle processes, and handles Stop, cancellation, restart, and process-tree cleanup.
75
- - **Redacted activity timeline** — Displays thinking summaries, tool calls and results, permission events, questions, status changes, usage, errors, and subagent activity without persisting credentials.
76
- - **Background task tracking** — Shows running and completed Claude subagents or background tasks with task status, recent tools, and expandable activity.
77
- - **Repository and worktree preparation** — Lets a user choose a branch before submitting, switch an eligible local branch, or create a dedicated Git worktree and DSH workspace while transferring the current draft and attachments, and removes a worktree's directory automatically once its workspace is deleted and the tree is clean.
78
- - **Repository and pull request status** — Shows the current repository, branch, worktree state, changed-line counts, unpushed commits, GitHub pull request, checks, review state, merge state, and blocking Claude rate limits near the composer.
79
- - **Diff viewer and review comments** — Provides an expandable or maximized branch diff, including file statistics and line-level review comments that are attached to the next Claude message.
80
- - **Commit, push, and pull request actions** — Supports Commit, Commit & Push, Push, and draft pull request creation, with repository snapshot validation and optional Claude-generated commit messages.
81
- - **Claude Code settings and Doctor** — Adds a Settings panel for runtime diagnostics, supported Claude settings, worktree branch prefix, process limits, authentication and handshake status, and safe npm update checks.
82
- - **Managed preset compatibility** — Installs an idempotent compatibility copy of the Claude preset for supported DSH builds without overwriting user-modified preset content.
1
+ # dsh-claude
2
+
3
+ ## 1. Overview
4
+
5
+ `dsh-claude` runs the locally installed Claude Code CLI as a first-class conversation provider inside DeepSeek Harness (DSH). It uses Claude Code's official Agent SDK protocol instead of recreating the agent with a separate API client.
6
+
7
+ Claude Code remains responsible for its agent loop, tools, `CLAUDE.md`, Skills, Hooks, Plugins, MCP servers, settings, and authentication. DSH provides the conversation UI, approval and question surfaces, repository workflow, activity presentation, and managed process lifetime.
8
+
9
+ ## 2. Installation and removal
10
+
11
+ ### Requirements
12
+
13
+ - DeepSeek Harness Desktop with compatible public plugin APIs. This package is currently developed against the DSH `0.1.1-rc.2` package line.
14
+ - A local Claude Code installation that is already authenticated.
15
+ - Node.js 20 or later when installing from a source checkout.
16
+
17
+ The plugin never asks for or stores Claude credentials. Authenticate through the local Claude Code CLI before using the plugin.
18
+
19
+ ### Install from npm
20
+
21
+ Add the published package to the DSH Web profile:
22
+
23
+ ```sh
24
+ dsh plugin --profile web add @norman-else/dsh-claude
25
+ ```
26
+
27
+ Wait for the profile rebuild to finish, then restart DSH Desktop if requested. Create a new conversation and select **Claude** from the Agent Preset picker.
28
+
29
+ ### Install from source
30
+
31
+ ```sh
32
+ git clone https://github.com/Norman-else/dsh-claude.git
33
+ cd dsh-claude
34
+ pnpm install
35
+ pnpm check
36
+ ```
37
+
38
+ Link the checkout to DSH from PowerShell:
39
+
40
+ ```powershell
41
+ dsh plugin --profile web add "link:$PWD"
42
+ ```
43
+
44
+ Or from macOS/Linux:
45
+
46
+ ```sh
47
+ dsh plugin --profile web add "link:$(pwd)"
48
+ ```
49
+
50
+ ### Remove the plugin
51
+
52
+ Remove the managed compatibility preset before removing the package:
53
+
54
+ ```sh
55
+ dsh plugin --profile web exec dsh-claude remove-preset
56
+ dsh plugin --profile web remove @norman-else/dsh-claude
57
+ ```
58
+
59
+ DSH does not currently expose a plugin uninstall lifecycle hook. If the package was removed before its managed preset was cleaned up, run the matching installed version directly:
60
+
61
+ ```sh
62
+ pnpm dlx @norman-else/dsh-claude@<version> remove-preset
63
+ ```
64
+
65
+ Preset cleanup removes only installer-managed content and refuses to delete user-modified preset files.
66
+
67
+ ## 3. Features
68
+
69
+ - **Native Claude Code conversations** — Runs Claude Code as the main agent in a normal DSH conversation instead of wrapping it as a tool or secondary chat.
70
+ - **Claude preset and model selection** — Adds a `Claude` Agent Preset and exposes Claude Code's `default`, `opus[1m]`, `fable`, `sonnet`, and `haiku` model choices.
71
+ - **Local Claude environment compatibility** — Preserves the user's existing Claude Code authentication, settings, `CLAUDE.md`, Skills, Hooks, Plugins, tools, and MCP configuration.
72
+ - **Real-time streaming and conversation continuity** — Streams Claude responses and tool activity into DSH while retaining multi-turn context and persisted Claude session resume.
73
+ - **DSH permissions and questions** — Routes Claude tool permission requests through DSH approvals and Claude clarification prompts through DSH's native question forms.
74
+ - **Managed process lifecycle** — Keeps one live Claude process per active session, serializes turns, evicts idle processes, and handles Stop, cancellation, restart, and process-tree cleanup.
75
+ - **Redacted activity timeline** — Displays thinking summaries, tool calls and results, permission events, questions, status changes, usage, errors, and subagent activity without persisting credentials.
76
+ - **Background task tracking** — Shows running and completed Claude subagents or background tasks with task status, recent tools, and expandable activity.
77
+ - **Repository and worktree preparation** — Lets a user choose a branch before submitting, switch an eligible local branch, or create a dedicated Git worktree and DSH workspace while transferring the current draft and attachments, and removes a worktree's directory automatically once its workspace is deleted and the tree is clean.
78
+ - **Repository and pull request status** — Shows the current repository, branch, worktree state, changed-line counts, unpushed commits, GitHub pull request, checks, review state, merge state, and blocking Claude rate limits near the composer.
79
+ - **Diff viewer and review comments** — Provides an expandable or maximized branch diff, including file statistics and line-level review comments that are attached to the next Claude message.
80
+ - **Commit, push, and pull request actions** — Supports Commit, Commit & Push, Push, and draft pull request creation, with repository snapshot validation and optional Claude-generated commit messages.
81
+ - **Claude Code settings and Doctor** — Adds a Settings panel for runtime diagnostics, supported Claude settings, worktree branch prefix, process limits, authentication and handshake status, and safe npm update checks.
82
+ - **Managed preset compatibility** — Installs an idempotent compatibility copy of the Claude preset for supported DSH builds without overwriting user-modified preset content.
package/cordis.patch.yml CHANGED
@@ -1,12 +1,12 @@
1
- # dsh-claude host bundle. The preset stays inside this package as a system
2
- # preset, so removing the profile dependency removes the complete integration.
3
- - id: agent-presets
4
- config:
5
- default: standard
6
- roots:
7
- - path: !!js "process.getBuiltinModule('node:path').join(process.getBuiltinModule('node:path').dirname(process.getBuiltinModule('node:module').createRequire(ctx.baseUrl).resolve('@norman-else/dsh-claude/package.json')), 'preset')"
8
- trust: system
9
-
10
- - insert:
11
- - id: llm-claude
12
- name: '@norman-else/dsh-claude'
1
+ # dsh-claude host bundle. The preset stays inside this package as a system
2
+ # preset, so removing the profile dependency removes the complete integration.
3
+ - id: agent-presets
4
+ config:
5
+ default: standard
6
+ roots:
7
+ - path: !!js "process.getBuiltinModule('node:path').join(process.getBuiltinModule('node:path').dirname(process.getBuiltinModule('node:module').createRequire(ctx.baseUrl).resolve('@norman-else/dsh-claude/package.json')), 'preset')"
8
+ trust: system
9
+
10
+ - insert:
11
+ - id: llm-claude
12
+ name: '@norman-else/dsh-claude'
@@ -1,11 +1,11 @@
1
- # Shipped by dsh-claude. Claude Code owns the inner agent loop and tools;
2
- # this system preset contributes only the request-route override. DSH resolves
3
- # the bare package specifier from the host profile when mounting system roots.
4
- - id: claude-code-route
5
- name: '@norman-else/dsh-claude/preset-route'
6
- # Entry-local isolate realm: each session's preset mount gets its own
7
- # claudeCommands service instance (keeps mountPreset's leaked-service check
8
- # happy and prevents cross-session collisions). The host reads it through
9
- # dsh-agent-presets' serviceForAgent().
10
- isolate:
11
- claudeCommands: true
1
+ # Shipped by dsh-claude. Claude Code owns the inner agent loop and tools;
2
+ # this system preset contributes only the request-route override. DSH resolves
3
+ # the bare package specifier from the host profile when mounting system roots.
4
+ - id: claude-code-route
5
+ name: '@norman-else/dsh-claude/preset-route'
6
+ # Entry-local isolate realm: each session's preset mount gets its own
7
+ # claudeCommands service instance (keeps mountPreset's leaked-service check
8
+ # happy and prevents cross-session collisions). The host reads it through
9
+ # dsh-agent-presets' serviceForAgent().
10
+ isolate:
11
+ claudeCommands: true
@@ -1,4 +1,4 @@
1
- # Shipped by dsh-claude. Copy this system preset under a new id to customize it.
2
- name: Claude
3
- description: Use the local Claude Code as the complete agent runtime inside DSH.
4
- order: 10
1
+ # Shipped by dsh-claude. Copy this system preset under a new id to customize it.
2
+ name: Claude
3
+ description: Use the local Claude Code as the complete agent runtime inside DSH.
4
+ order: 10
package/lib/bin.mjs CHANGED
File without changes
package/lib/bin.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bin.mjs","names":[],"sources":["../src/bin.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { access } from 'node:fs/promises'\nimport { constants } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { delimiter, isAbsolute, join } from 'node:path'\nimport { spawnSync } from 'node:child_process'\nimport { scrubbedParentEnv } from '@deepseek-ai/dsh-subprocess'\nimport { parseClaudeVersion } from './executable.ts'\nimport { ensureManagedPreset, removeManagedPreset } from './preset-installer.ts'\n\nfunction option(name: string): string | undefined {\n const index = process.argv.indexOf(name)\n return index < 0 ? undefined : process.argv[index + 1]\n}\n\nasync function executable(configured?: string): Promise<string | undefined> {\n const candidates: string[] = []\n if (configured !== undefined) candidates.push(configured)\n else {\n for (const directory of (process.env.PATH ?? '').split(delimiter)) {\n if (directory.length > 0) candidates.push(join(directory, 'claude'))\n }\n candidates.push(join(homedir(), '.local', 'bin', 'claude'), '/opt/homebrew/bin/claude', '/usr/local/bin/claude')\n }\n for (const candidate of [...new Set(candidates)]) {\n if (!isAbsolute(candidate)) continue\n try {\n await access(candidate, constants.X_OK)\n return candidate\n } catch {\n // Continue to the next documented candidate.\n }\n }\n return undefined\n}\n\nfunction run(executablePath: string, args: string[]) {\n return spawnSync(executablePath, args, {\n encoding: 'utf8',\n env: scrubbedParentEnv(),\n timeout: 15_000,\n windowsHide: true,\n })\n}\n\nasync function doctor(): Promise<number> {\n const configured = option('--executable') ?? process.env.DSH_CLAUDE_CODE_EXECUTABLE\n const path = await executable(configured)\n if (path === undefined) {\n process.stdout.write(`${JSON.stringify({\n executable: { status: 'missing', searched: configured === undefined ? ['claude', '~/.local/bin/claude', '/opt/homebrew/bin/claude', '/usr/local/bin/claude'] : [configured] },\n version: { status: 'not-run' },\n authentication: { status: 'not-run' },\n message: 'Set executablePath to an absolute Claude Code CLI path',\n }, null, 2)}\\n`)\n return 1\n }\n const versionProbe = run(path, ['--version'])\n const version = parseClaudeVersion(`${versionProbe.stdout ?? ''}\\n${versionProbe.stderr ?? ''}`)\n const authProbe = run(path, ['auth', 'status', '--json'])\n let authentication: Record<string, unknown> = { status: 'unknown' }\n if (authProbe.status === 0) {\n try {\n const value = JSON.parse(authProbe.stdout) as Record<string, unknown>\n authentication = {\n status: value.loggedIn === true ? 'signed-in' : 'signed-out',\n ...(typeof value.authMethod === 'string' ? { method: value.authMethod } : {}),\n ...(typeof value.apiProvider === 'string' ? { provider: value.apiProvider } : {}),\n ...(typeof value.subscriptionType === 'string' ? { subscription: value.subscriptionType } : {}),\n }\n } catch {\n authentication = { status: 'unknown', message: 'Authentication status was not valid JSON' }\n }\n }\n process.stdout.write(`${JSON.stringify({\n executable: { status: 'found', path },\n version: version === undefined ? { status: 'error' } : { status: 'ok', value: version },\n authentication,\n handshake: 'not-run',\n }, null, 2)}\\n`)\n return version === undefined ? 1 : 0\n}\n\nasync function main(): Promise<number> {\n const command = process.argv[2] ?? 'doctor'\n if (command === 'doctor') return doctor()\n if (command === 'install-preset') {\n process.stdout.write(`${await ensureManagedPreset()}\\n`)\n return 0\n }\n if (command === 'remove-preset') {\n process.stdout.write(`${await removeManagedPreset()}\\n`)\n return 0\n }\n process.stderr.write(`Usage: dsh-claude [doctor [--executable PATH] | install-preset | remove-preset]\\n`)\n return 2\n}\n\ntry {\n process.exitCode = await main()\n} catch (error) {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`)\n process.exitCode = 1\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"bin.mjs","names":[],"sources":["../src/bin.ts"],"sourcesContent":["#!/usr/bin/env node\r\n\r\nimport { access } from 'node:fs/promises'\r\nimport { constants } from 'node:fs'\r\nimport { homedir } from 'node:os'\r\nimport { delimiter, isAbsolute, join } from 'node:path'\r\nimport { spawnSync } from 'node:child_process'\r\nimport { scrubbedParentEnv } from '@deepseek-ai/dsh-subprocess'\r\nimport { parseClaudeVersion } from './executable.ts'\r\nimport { ensureManagedPreset, removeManagedPreset } from './preset-installer.ts'\r\n\r\nfunction option(name: string): string | undefined {\r\n const index = process.argv.indexOf(name)\r\n return index < 0 ? undefined : process.argv[index + 1]\r\n}\r\n\r\nasync function executable(configured?: string): Promise<string | undefined> {\r\n const candidates: string[] = []\r\n if (configured !== undefined) candidates.push(configured)\r\n else {\r\n for (const directory of (process.env.PATH ?? '').split(delimiter)) {\r\n if (directory.length > 0) candidates.push(join(directory, 'claude'))\r\n }\r\n candidates.push(join(homedir(), '.local', 'bin', 'claude'), '/opt/homebrew/bin/claude', '/usr/local/bin/claude')\r\n }\r\n for (const candidate of [...new Set(candidates)]) {\r\n if (!isAbsolute(candidate)) continue\r\n try {\r\n await access(candidate, constants.X_OK)\r\n return candidate\r\n } catch {\r\n // Continue to the next documented candidate.\r\n }\r\n }\r\n return undefined\r\n}\r\n\r\nfunction run(executablePath: string, args: string[]) {\r\n return spawnSync(executablePath, args, {\r\n encoding: 'utf8',\r\n env: scrubbedParentEnv(),\r\n timeout: 15_000,\r\n windowsHide: true,\r\n })\r\n}\r\n\r\nasync function doctor(): Promise<number> {\r\n const configured = option('--executable') ?? process.env.DSH_CLAUDE_CODE_EXECUTABLE\r\n const path = await executable(configured)\r\n if (path === undefined) {\r\n process.stdout.write(`${JSON.stringify({\r\n executable: { status: 'missing', searched: configured === undefined ? ['claude', '~/.local/bin/claude', '/opt/homebrew/bin/claude', '/usr/local/bin/claude'] : [configured] },\r\n version: { status: 'not-run' },\r\n authentication: { status: 'not-run' },\r\n message: 'Set executablePath to an absolute Claude Code CLI path',\r\n }, null, 2)}\\n`)\r\n return 1\r\n }\r\n const versionProbe = run(path, ['--version'])\r\n const version = parseClaudeVersion(`${versionProbe.stdout ?? ''}\\n${versionProbe.stderr ?? ''}`)\r\n const authProbe = run(path, ['auth', 'status', '--json'])\r\n let authentication: Record<string, unknown> = { status: 'unknown' }\r\n if (authProbe.status === 0) {\r\n try {\r\n const value = JSON.parse(authProbe.stdout) as Record<string, unknown>\r\n authentication = {\r\n status: value.loggedIn === true ? 'signed-in' : 'signed-out',\r\n ...(typeof value.authMethod === 'string' ? { method: value.authMethod } : {}),\r\n ...(typeof value.apiProvider === 'string' ? { provider: value.apiProvider } : {}),\r\n ...(typeof value.subscriptionType === 'string' ? { subscription: value.subscriptionType } : {}),\r\n }\r\n } catch {\r\n authentication = { status: 'unknown', message: 'Authentication status was not valid JSON' }\r\n }\r\n }\r\n process.stdout.write(`${JSON.stringify({\r\n executable: { status: 'found', path },\r\n version: version === undefined ? { status: 'error' } : { status: 'ok', value: version },\r\n authentication,\r\n handshake: 'not-run',\r\n }, null, 2)}\\n`)\r\n return version === undefined ? 1 : 0\r\n}\r\n\r\nasync function main(): Promise<number> {\r\n const command = process.argv[2] ?? 'doctor'\r\n if (command === 'doctor') return doctor()\r\n if (command === 'install-preset') {\r\n process.stdout.write(`${await ensureManagedPreset()}\\n`)\r\n return 0\r\n }\r\n if (command === 'remove-preset') {\r\n process.stdout.write(`${await removeManagedPreset()}\\n`)\r\n return 0\r\n }\r\n process.stderr.write(`Usage: dsh-claude [doctor [--executable PATH] | install-preset | remove-preset]\\n`)\r\n return 2\r\n}\r\n\r\ntry {\r\n process.exitCode = await main()\r\n} catch (error) {\r\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`)\r\n process.exitCode = 1\r\n}\r\n"],"mappings":"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"}
package/lib/client.d.ts CHANGED
@@ -173,6 +173,7 @@ declare const en: {
173
173
  readonly no: "No";
174
174
  readonly diffOpen: "View branch changes";
175
175
  readonly diffClose: "Close diff panel";
176
+ readonly presetHeaderHint: "The agent preset this session runs";
176
177
  readonly diffWorkingTree: "Branch changes";
177
178
  readonly diffFiles: "{count} modified file(s)";
178
179
  readonly diffFilesShort: "{count} files";
@@ -218,10 +219,12 @@ declare const en: {
218
219
  readonly diffMergeCompleted: "Merged PR #{number}";
219
220
  readonly diffUpdateBranch: "Update branch…";
220
221
  readonly repositoryUpdateBranch: "Update branch";
221
- readonly diffUpdateBranchDescription: "Merge origin/{base} into the current branch and push; hand any conflicts to Claude.";
222
+ readonly diffUpdateBranchDescription: "Update the current branch from origin/{base} and push; hand any conflicts to Claude.";
223
+ readonly diffUpdateBranch_rebase: "Rebase onto origin/{base} (rewrites history, pushes with --force-with-lease)";
224
+ readonly diffUpdateBranch_merge: "Merge origin/{base} into the current branch";
222
225
  readonly diffUpdateBranchBehind: "{count} commit(s) behind origin/{base}";
223
- readonly diffUpdateBranchCompleted: "Merged and pushed commit {commit}";
224
- readonly diffUpdateBranchConflicts: "The merge left conflicts in these files:";
226
+ readonly diffUpdateBranchCompleted: "Updated and pushed commit {commit}";
227
+ readonly diffUpdateBranchConflicts: "The update left conflicts in these files:";
225
228
  readonly diffUpdateBranchResolve: "Have Claude resolve the conflicts";
226
229
  readonly repositoryChecksOpen: "Show failing checks";
227
230
  readonly checksCardTitle: "Failing checks";