codsh-cli 0.1.0 → 0.3.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.
package/README.md CHANGED
@@ -1,65 +1,7 @@
1
- # codsh
1
+ # codsh-cli
2
2
 
3
- > npm: [`codsh-cli`](https://www.npmjs.com/package/codsh-cli) · command: `codsh`
3
+ The `codsh` command: a **zero-dependency launcher** for [codsh](https://github.com/Blackman99/codsh), a Claude Code-style coding agent for the terminal composed on the DeepSeek Harness (dsh).
4
4
 
5
- English | [中文](README.zh.md)
5
+ This package bundles nothing. It finds the dsh you already have (`DSH_BIN`, a resolvable `@deepseek-ai/dsh`, or `dsh` on PATH), registers the [`codsh-bundle`](https://www.npmjs.com/package/codsh-bundle) runtime into a dsh `code` profile on first run, and boots `dsh --profile code`. No dsh yet? `npm install -g @deepseek-ai/dsh` first.
6
6
 
7
- A Claude Code-style coding agent for the terminal, composed on the [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (dsh) plugin runtime. codsh is a dsh *bundle*: it ships the interactive TTY surface and a coding agent preset, and everything underneath — the agent loop, tools, sessions, sandboxing, model adapters — is the released dsh packages from npm.
8
-
9
- ## Install
10
-
11
- ```sh
12
- npm install -g codsh-cli
13
- codsh
14
- ```
15
-
16
- The first run registers this package into a dsh `code` profile under `$DSH_HOME` (default `~/.dsh`) and installs the packaged `code-cli` agent preset; every later run boots straight into the prompt. The model key is read from `DEEPSEEK_API_KEY` (environment or `.env`).
17
-
18
- `codsh` is exactly `dsh --profile code` — the wrapper only performs the one-time profile registration. Flags after `codsh` reach the app: `codsh --resume <session-id>`, `codsh --continue`, `codsh -p "one-shot task"`.
19
-
20
- ## What you get
21
-
22
- - **An input box that owns the keyboard**: multi-line editing (Alt-Enter), history across sessions, completion for commands, arguments, and `@`-mentioned files (fuzzy, workspace-wide), opened as you type.
23
- - **Streaming rendering**: Markdown with code highlighting and table layout, reasoning models' thinking dim under `✻ thinking`, tool calls as presenter-driven cards with diffs, and Ctrl-O to reprint the last clipped output in full.
24
- - **Decisions as selections**: approvals, questions, `/model`, and `/resume` are arrow-key widgets; plan mode toggles on Shift-Tab and tints the box frame.
25
- - **Session flow**: `/clear` starts fresh in place, `/resume` picks from recorded sessions with titles and ages, Escape twice recalls your previous message for editing, and `!cmd` runs in your shell with the outcome injected as model-visible context — no turn spent.
26
- - **Canned prompts**: `/init` drafts an `AGENTS.md`; your own Markdown files under `$DSH_HOME/commands/` or `<workspace>/.dsh/commands/` become slash commands with `$ARGUMENTS` templating.
27
- - Status line (model, preset, permissions, tokens, context left, branch), terminal-title updates, a bell when a decision waits, and a `--print` mode for scripts.
28
-
29
- Off a TTY (pipes, scripts) the same surface degrades to a line reader: selections become typed answers, lists replace widgets, and nothing draws.
30
-
31
- ## Development
32
-
33
- ```sh
34
- pnpm install
35
- pnpm run dev # build → sync into .dev-home → boot; seconds per iteration
36
- MOCK=markdown pnpm run dev # keyless, against the e2e mock model
37
- pnpm run build # tsdown runtime bundles + tsc declarations into lib/
38
- pnpm run typecheck
39
- pnpm test # unit suites (pure modules: editor, markdown, transcript, …)
40
- pnpm run test:e2e # packs this repo, registers it into a dsh profile, and
41
- # drives the INSTALLED dsh binary through pipes and a real PTY
42
- ```
43
-
44
- `pnpm run dev` keeps a repo-local dsh home in `.dev-home`: the first run does a real profile install of the packed tree, and every later run just copies the fresh `lib/` over the profile's unpacked package — so edits reach the running surface in seconds. `MOCK=<write|bash|slow|markdown|reasoning|echo|tall>` swaps in the keyless e2e model for UI work without a key, arguments pass through (`pnpm run dev -- --resume <id>`), and `INSPECT=1` opens the Node inspector on the app process (`chrome://inspect` or a VS Code attach). Off-TTY logic is easiest to step through piped — `printf 'task\n/exit\n' | MOCK=echo pnpm run dev` — where raw mode and the repaint region are out of the picture; keep `console.*` out of debug prints on a TTY (they tear the managed region) and log to a file instead.
45
-
46
- The e2e suites test the release artifact: `npm pack` output installed into a real profile, booted by the dsh launcher from npm, with a keyless mock model. What passes there is what a user installs.
47
-
48
- ### Debugging against dsh sources
49
-
50
- Day to day, dsh is an ordinary npm dependency. To step into harness code, clone [deepseek-harness](https://github.com/deepseek-ai/deepseek-harness) beside this repo, build it (`pnpm install && pnpm run build`), then point the packages you are debugging at the checkout:
51
-
52
- ```jsonc
53
- // package.json — remove again when done; keep npm as the default
54
- "pnpm": {
55
- "overrides": {
56
- "@deepseek-ai/dsh-agent-loop": "link:../deepseek-harness/packages/core/agent-loop"
57
- }
58
- }
59
- ```
60
-
61
- and re-run `pnpm install`. Changes you want upstream go to the harness repo as ordinary PRs; this repository never forks it.
62
-
63
- ## License
64
-
65
- MIT
7
+ Full documentation: [github.com/Blackman99/codsh](https://github.com/Blackman99/codsh)
package/bin/codsh.mjs CHANGED
@@ -1,61 +1,123 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * The `codsh` command: the dsh launcher booted onto the code profile, with
4
- * this package registered as that profile's bundle on first run.
3
+ * The `codsh` command: a zero-dependency launcher over the dsh you already
4
+ * have.
5
5
  *
6
- * dsh owns profiles, plugin installation, and the boot; this wrapper only
7
- * makes `codsh` a one-command experience it is exactly
8
- * `dsh plugin --profile code add <this package>` once, then
9
- * `dsh --profile code <args>` every time.
6
+ * This package deliberately bundles NOTHING the ~300MB dsh runtime lives
7
+ * once on a machine, not once per tool. The wrapper finds a dsh (`DSH_BIN`,
8
+ * then a resolvable `@deepseek-ai/dsh` install, then `dsh` on PATH), registers
9
+ * the `codsh-bundle` runtime into the `code` profile on first run, and boots
10
+ * `dsh --profile code` with the arguments passed through.
10
11
  */
11
12
 
12
13
  import { spawnSync } from 'node:child_process'
13
- import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs'
14
- import { homedir, tmpdir } from 'node:os'
14
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs'
15
+ import { homedir } from 'node:os'
15
16
  import { dirname, join } from 'node:path'
16
- import { fileURLToPath } from 'node:url'
17
17
  import { createRequire } from 'node:module'
18
18
 
19
- const require = createRequire(import.meta.url)
20
- const ownDir = fileURLToPath(new URL('..', import.meta.url))
21
- const dshPackage = require.resolve('@deepseek-ai/dsh/package.json')
22
- const dshBinField = JSON.parse(readFileSync(dshPackage, 'utf8')).bin
23
- const dshBin = join(dirname(dshPackage), typeof dshBinField === 'string' ? dshBinField : dshBinField.dsh)
24
-
25
- /** Whether the code profile already carries this package. */
26
- function registered() {
27
- const home = process.env.DSH_HOME ?? join(homedir(), '.dsh')
28
- const manifest = join(home, 'profiles', 'code', 'package.json')
29
- if (!existsSync(manifest)) return false
19
+ const requireFromHere = createRequire(import.meta.url)
20
+ const own = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'))
21
+
22
+ /** The bundle package this launcher pairs with, lockstep-versioned. */
23
+ const BUNDLE = 'codsh-bundle'
24
+
25
+ /**
26
+ * Locate a dsh launcher without carrying one.
27
+ * @returns how to spawn it, or undefined when the machine has none.
28
+ */
29
+ function findDsh() {
30
+ const pinned = process.env.DSH_BIN
31
+ if (pinned !== undefined && pinned !== '') {
32
+ // A JS entry runs through this Node; anything else is an executable.
33
+ return /\.[cm]?js$/.test(pinned)
34
+ ? { command: process.execPath, prefix: [pinned] }
35
+ : { command: pinned, prefix: [] }
36
+ }
30
37
  try {
31
- const profile = JSON.parse(readFileSync(manifest, 'utf8'))
32
- return 'codsh-cli' in (profile.dependencies ?? {})
38
+ const manifest = requireFromHere.resolve('@deepseek-ai/dsh/package.json')
39
+ const bin = JSON.parse(readFileSync(manifest, 'utf8')).bin
40
+ const entry = join(dirname(manifest), typeof bin === 'string' ? bin : bin.dsh)
41
+ return { command: process.execPath, prefix: [entry] }
33
42
  } catch {
34
- return false
43
+ // Not installed beside this package; the PATH is next.
35
44
  }
45
+ const probe = spawnSync('dsh', ['--version'], { stdio: 'ignore', shell: process.platform === 'win32' })
46
+ if (probe.error === undefined && probe.status !== null) return { command: 'dsh', prefix: [] }
47
+ return undefined
48
+ }
49
+
50
+ const dsh = findDsh()
51
+ if (dsh === undefined) {
52
+ console.error(`codsh: no dsh runtime found. codsh launches the dsh you already have —
53
+ the runtime is not bundled, so a machine never carries a second copy.
54
+
55
+ install one: npm install -g @deepseek-ai/dsh
56
+ or point at one: DSH_BIN=/path/to/dsh codsh`)
57
+ process.exit(1)
58
+ }
59
+
60
+ /** Run the found dsh with arguments, inheriting the terminal. */
61
+ function run(args) {
62
+ const result = spawnSync(dsh.command, [...dsh.prefix, ...args], { stdio: 'inherit' })
63
+ return result.status ?? 1
36
64
  }
37
65
 
38
- if (!registered()) {
39
- console.error('codsh: registering this package into the dsh code profile (first run)')
40
- // A bare directory installs as `link:`, whose dependencies never reach the
41
- // profile's resolver. A development checkout (it has node_modules) packs to
42
- // the release tarball; an installed copy is clean and `file:` copies it,
43
- // with its dependencies resolved by the profile install either way.
44
- let spec = `file:${ownDir}`
45
- let scratch
46
- if (existsSync(join(ownDir, 'node_modules'))) {
47
- scratch = mkdtempSync(join(tmpdir(), 'codsh-pack-'))
48
- const packed = spawnSync('npm', ['pack', '--pack-destination', scratch], { cwd: ownDir, encoding: 'utf8' })
49
- if (packed.status !== 0) {
50
- console.error(packed.stderr ?? 'codsh: npm pack failed')
51
- process.exit(packed.status ?? 1)
66
+ /** `a > b` for plain x.y.z versions, which is all this pair publishes. */
67
+ function newer(a, b) {
68
+ const pa = String(a).split('.').map(Number)
69
+ const pb = String(b).split('.').map(Number)
70
+ for (let index = 0; index < 3; index += 1) {
71
+ if ((pa[index] ?? 0) !== (pb[index] ?? 0)) return (pa[index] ?? 0) > (pb[index] ?? 0)
72
+ }
73
+ return false
74
+ }
75
+
76
+ const home = process.env.DSH_HOME ?? join(homedir(), '.dsh')
77
+ const manifestPath = join(home, 'profiles', 'code', 'package.json')
78
+
79
+ /** What the code profile currently carries, or undefined before first run. */
80
+ function profile() {
81
+ if (!existsSync(manifestPath)) return undefined
82
+ try {
83
+ return JSON.parse(readFileSync(manifestPath, 'utf8'))
84
+ } catch {
85
+ return undefined
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Decide whether — and what — to register into the profile this run.
91
+ * @returns the spec to `dsh plugin add`, or undefined when nothing is due.
92
+ */
93
+ function registration() {
94
+ const spec = process.env.CODSH_BUNDLE_SPEC ?? `${BUNDLE}@^${own.version}`
95
+ const manifest = profile()
96
+ const dependencies = manifest?.dependencies ?? {}
97
+ // The pre-split layout carried the whole runtime under this launcher's own
98
+ // name; migrate it out so both bundles don't fight over the terminal.
99
+ if (manifest !== undefined && 'codsh-cli' in dependencies) {
100
+ console.error('codsh: migrating the profile to the split codsh-bundle runtime')
101
+ delete manifest.dependencies['codsh-cli']
102
+ const bundles = manifest?.dsh?.profile?.bundles
103
+ if (Array.isArray(bundles)) {
104
+ manifest.dsh.profile.bundles = bundles.filter(name => name !== 'codsh-cli')
52
105
  }
53
- spec = join(scratch, packed.stdout.trim().split('\n').at(-1) ?? '')
106
+ writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`)
107
+ return spec
54
108
  }
55
- const setup = spawnSync(process.execPath, [dshBin, 'plugin', '--profile', 'code', 'add', spec], { stdio: 'inherit' })
56
- if (scratch !== undefined) rmSync(scratch, { recursive: true, force: true })
57
- if (setup.status !== 0) process.exit(setup.status ?? 1)
109
+ const current = dependencies[BUNDLE]
110
+ if (current === undefined) return spec
111
+ // A file:/link: registration is a development pin; never clobber it.
112
+ if (!current.startsWith('^')) return undefined
113
+ return newer(own.version, current.slice(1)) ? spec : undefined
114
+ }
115
+
116
+ const spec = registration()
117
+ if (spec !== undefined) {
118
+ console.error(`codsh: registering ${spec} into the dsh code profile`)
119
+ const status = run(['plugin', '--profile', 'code', 'add', spec])
120
+ if (status !== 0) process.exit(status)
58
121
  }
59
122
 
60
- const run = spawnSync(process.execPath, [dshBin, '--profile', 'code', ...process.argv.slice(2)], { stdio: 'inherit' })
61
- process.exit(run.status ?? 0)
123
+ process.exit(run(['--profile', 'code', ...process.argv.slice(2)]))
package/package.json CHANGED
@@ -1,131 +1,24 @@
1
1
  {
2
2
  "name": "codsh-cli",
3
- "description": "A Claude Code-style coding agent for the terminal, composed on the DeepSeek Harness (dsh): interactive TTY surface, plan mode, approvals, custom commands, and session management over the dsh plugin runtime",
4
- "version": "0.1.0",
3
+ "description": "A Claude Code-style coding agent for the terminal, composed on the DeepSeek Harness (dsh). This is the zero-dependency launcher: it finds your dsh, registers the codsh-bundle runtime into a profile, and boots it.",
4
+ "version": "0.3.0",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "bin": {
8
8
  "codsh": "./bin/codsh.mjs"
9
9
  },
10
- "main": "lib/index.js",
11
- "types": "lib/types/index.d.ts",
12
- "exports": {
13
- ".": {
14
- "types": "./lib/types/index.d.ts",
15
- "default": "./lib/index.js"
16
- },
17
- "./startup": {
18
- "types": "./lib/types/startup.d.ts",
19
- "default": "./lib/startup.js"
20
- },
21
- "./invariant": {
22
- "types": "./lib/types/invariant.d.ts",
23
- "default": "./lib/invariant.js"
24
- },
25
- "./cordis.patch.yml": "./cordis.patch.yml",
26
- "./package.json": "./package.json",
27
- "./agent-presets/*": "./agent-presets/*"
28
- },
29
10
  "files": [
30
- "lib/index.js",
31
- "lib/invariant.js",
32
- "lib/startup.js",
33
11
  "bin",
34
- "cordis.patch.yml",
35
- "agent-presets",
36
- "lib/types/**/*.d.ts"
12
+ "README.md"
37
13
  ],
38
- "dsh": {
39
- "bundle": {
40
- "patch": "./cordis.patch.yml"
41
- }
42
- },
43
- "dependencies": {
44
- "@deepseek-ai/dsh": "^0.1.0-rc.7",
45
- "@deepseek-ai/dsh-agent-instructions": "^0.1.0-rc.7",
46
- "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.7",
47
- "@deepseek-ai/dsh-cmdline": "^0.1.0-rc.7",
48
- "@deepseek-ai/dsh-code-runtime-worker-thread": "^0.1.0-rc.7",
49
- "@deepseek-ai/dsh-command-compact": "^0.1.0-rc.7",
50
- "@deepseek-ai/dsh-compaction-basic": "^0.1.0-rc.7",
51
- "@deepseek-ai/dsh-compaction-tool-result-pruner": "^0.1.0-rc.7",
52
- "@deepseek-ai/dsh-lsp": "^0.1.0-rc.7",
53
- "@deepseek-ai/dsh-lsp-stdio": "^0.1.0-rc.7",
54
- "@deepseek-ai/dsh-persona": "^0.1.0-rc.7",
55
- "@deepseek-ai/dsh-plan-mode": "^0.1.0-rc.7",
56
- "@deepseek-ai/dsh-skill-filesystem": "^0.1.0-rc.7",
57
- "@deepseek-ai/dsh-terminal": "^0.1.0-rc.7",
58
- "@deepseek-ai/dsh-terminal-bash": "^0.1.0-rc.7",
59
- "@deepseek-ai/dsh-tool-ask-user": "^0.1.0-rc.7",
60
- "@deepseek-ai/dsh-tool-bash": "^0.1.0-rc.7",
61
- "@deepseek-ai/dsh-tool-fs": "^0.1.0-rc.7",
62
- "@deepseek-ai/dsh-tool-fs-search": "^0.1.0-rc.7",
63
- "@deepseek-ai/dsh-tool-goal": "^0.1.0-rc.7",
64
- "@deepseek-ai/dsh-tool-jobs": "^0.1.0-rc.7",
65
- "@deepseek-ai/dsh-tool-lsp": "^0.1.0-rc.7",
66
- "@deepseek-ai/dsh-tool-pwsh": "^0.1.0-rc.7",
67
- "@deepseek-ai/dsh-tool-ralph": "^0.1.0-rc.7",
68
- "@deepseek-ai/dsh-tool-skill": "^0.1.0-rc.7",
69
- "@deepseek-ai/dsh-tool-subagent": "^0.1.0-rc.7",
70
- "@deepseek-ai/dsh-tool-subagent-control": "^0.1.0-rc.7",
71
- "@deepseek-ai/dsh-tool-terminal": "^0.1.0-rc.7",
72
- "@deepseek-ai/dsh-tool-todo": "^0.1.0-rc.7",
73
- "@deepseek-ai/dsh-tool-web": "^0.1.0-rc.7",
74
- "@deepseek-ai/dsh-tool-workflow": "^0.1.0-rc.7",
75
- "@deepseek-ai/dsh-workflow-worker-thread": "^0.1.0-rc.7",
76
- "@deepseek-ai/schemastery": "^3.18.1",
77
- "commander": "^15.0.0",
78
- "diff": "^9.0.0"
79
- },
80
- "peerDependencies": {
81
- "@deepseek-ai/cordis": "^4.0.1",
82
- "@deepseek-ai/cordis-plugin-loader": "^1.0.2",
83
- "@deepseek-ai/dsh-agent": "^0.1.0-rc.7",
84
- "@deepseek-ai/dsh-agent-default-model": "^0.1.0-rc.7",
85
- "@deepseek-ai/dsh-commands": "^0.1.0-rc.7",
86
- "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.7",
87
- "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7",
88
- "@deepseek-ai/dsh-llm": "^0.1.0-rc.7",
89
- "@deepseek-ai/dsh-permission-presets": "^0.1.0-rc.7",
90
- "@deepseek-ai/dsh-session": "^0.1.0-rc.7",
91
- "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.7",
92
- "@deepseek-ai/dsh-session-query": "^0.1.0-rc.7",
93
- "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.7",
94
- "@deepseek-ai/dsh-tools": "^0.1.0-rc.7",
95
- "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.7",
96
- "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.7"
97
- },
98
- "devDependencies": {
99
- "@changesets/cli": "^3.0.0",
100
- "@deepseek-ai/cordis": "^4.0.1",
101
- "@deepseek-ai/cordis-plugin-loader": "^1.0.2",
102
- "@deepseek-ai/dsh-agent": "^0.1.0-rc.7",
103
- "@deepseek-ai/dsh-agent-default-model": "^0.1.0-rc.7",
104
- "@deepseek-ai/dsh-commands": "^0.1.0-rc.7",
105
- "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.7",
106
- "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7",
107
- "@deepseek-ai/dsh-llm": "^0.1.0-rc.7",
108
- "@deepseek-ai/dsh-permission-presets": "^0.1.0-rc.7",
109
- "@deepseek-ai/dsh-session": "^0.1.0-rc.7",
110
- "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.7",
111
- "@deepseek-ai/dsh-session-query": "^0.1.0-rc.7",
112
- "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.7",
113
- "@deepseek-ai/dsh-tools": "^0.1.0-rc.7",
114
- "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.7",
115
- "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.7",
116
- "@types/node": "^24.0.0",
117
- "execa": "^9.0.0",
118
- "tsdown": "^0.15.0",
119
- "tsx": "^4.20.0",
120
- "typescript": "^5.9.0",
121
- "vitest": "^4.0.0"
14
+ "engines": {
15
+ "node": ">=22.19"
122
16
  },
123
17
  "repository": {
124
18
  "type": "git",
125
- "url": "git+https://github.com/Blackman99/codsh.git"
19
+ "url": "git+https://github.com/Blackman99/codsh.git",
20
+ "directory": "packages/cli"
126
21
  },
127
- "homepage": "https://github.com/Blackman99/codsh#readme",
128
- "bugs": "https://github.com/Blackman99/codsh/issues",
129
22
  "keywords": [
130
23
  "cli",
131
24
  "coding-agent",
@@ -135,15 +28,6 @@
135
28
  "ai",
136
29
  "agent"
137
30
  ],
138
- "engines": {
139
- "node": ">=22.19"
140
- },
141
- "scripts": {
142
- "build": "tsdown && tsc -p tsconfig.build.json",
143
- "typecheck": "tsc --noEmit",
144
- "test": "vitest run",
145
- "test:e2e": "pnpm run build && vitest run --config vitest.e2e.config.ts",
146
- "dev": "node scripts/dev.mjs",
147
- "release": "pnpm run build && changeset publish"
148
- }
31
+ "homepage": "https://github.com/Blackman99/codsh#readme",
32
+ "bugs": "https://github.com/Blackman99/codsh/issues"
149
33
  }
package/README.zh.md DELETED
@@ -1,65 +0,0 @@
1
- # codsh
2
-
3
- > npm 包名:[`codsh-cli`](https://www.npmjs.com/package/codsh-cli) · 命令:`codsh`
4
-
5
- [English](README.md) | 中文
6
-
7
- 面向终端的 Claude Code 风格编码 agent,组合在 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(dsh)插件运行时之上。codsh 是一个 dsh *bundle*:它携带交互式 TTY 界面与编码 agent preset,其下的一切——agent 循环、工具、会话、沙箱、模型适配器——都是 npm 上已发布的 dsh 包。
8
-
9
- ## 安装
10
-
11
- ```sh
12
- npm install -g codsh-cli
13
- codsh
14
- ```
15
-
16
- 首次运行会把本包注册进 `$DSH_HOME`(默认 `~/.dsh`)下的 dsh `code` profile 并安装自带的 `code-cli` agent preset;之后每次运行直接进入提示符。模型密钥从 `DEEPSEEK_API_KEY` 读取(环境变量或 `.env`)。
17
-
18
- `codsh` 严格等价于 `dsh --profile code`——包装器只做一次性的 profile 注册。`codsh` 之后的参数直达应用:`codsh --resume <会话 id>`、`codsh --continue`、`codsh -p "一次性任务"`。
19
-
20
- ## 你会得到什么
21
-
22
- - **接管键盘的输入框**:多行编辑(Alt-Enter)、跨会话历史,命令、参数与 `@` 文件提及(全工作区模糊搜索)的补全随输入自动打开。
23
- - **流式渲染**:Markdown 带代码高亮与表格排版,推理模型的思考在 `✻ thinking` 下暗色显示,工具调用按 presenter 驱动的卡片渲染(含 diff),Ctrl-O 完整重印最近被截断的输出。
24
- - **决定用选择**:审批、提问、`/model` 与 `/resume` 都是方向键组件;Shift-Tab 切换 plan 模式并为框着色。
25
- - **会话流**:`/clear` 原地开新会话,`/resume` 从带标题和时间的会话列表里选,连按两次 Escape 召回上一条消息编辑,`!cmd` 在你自己的 shell 里运行并把结果注入为模型可见上下文——不花回合。
26
- - **固定 prompt**:`/init` 起草 `AGENTS.md`;`$DSH_HOME/commands/` 或 `<工作区>/.dsh/commands/` 下的 Markdown 文件即成为斜杠命令,支持 `$ARGUMENTS` 模板。
27
- - 状态行(模型、preset、权限、token、剩余上下文、分支)、终端标题跟随、有决定等待时的铃声,以及面向脚本的 `--print` 模式。
28
-
29
- 非 TTY 环境(管道、脚本)下同一界面降级为行读取器:选择变为键入回答、组件变为列表、不绘制任何东西。
30
-
31
- ## 开发
32
-
33
- ```sh
34
- pnpm install
35
- pnpm run dev # build → 同步进 .dev-home → 启动;秒级迭代
36
- MOCK=markdown pnpm run dev # 无 key,对着 e2e mock 模型
37
- pnpm run build # tsdown 运行时 bundle + tsc 声明文件,输出到 lib/
38
- pnpm run typecheck
39
- pnpm test # 单测(纯函数模块:editor、markdown、transcript……)
40
- pnpm run test:e2e # 打包本仓库、注册进 dsh profile,然后经管道与真实 PTY
41
- # 驱动 npm 安装的 dsh 可执行文件
42
- ```
43
-
44
- `pnpm run dev` 在 `.dev-home` 维护一个仓库本地的 dsh home:首次运行对打包后的工作树做一次真实 profile 安装,之后每次只把新构建的 `lib/` 覆盖到 profile 里解包的本包上——改动秒级到达运行中的界面。`MOCK=<write|bash|slow|markdown|reasoning|echo|tall>` 换上 keyless e2e 模型、无 key 调 UI;参数透传(`pnpm run dev -- --resume <id>`);`INSPECT=1` 在应用进程上打开 Node inspector(`chrome://inspect` 或 VS Code attach)。逻辑问题优先用管道形态单步——`printf 'task\n/exit\n' | MOCK=echo pnpm run dev`——那里没有 raw mode 和重绘区域的干扰;在 TTY 上调试不要用 `console.*` 打点(会撕裂受管理区域),改写文件日志。
45
-
46
- e2e 测试的是发布产物:`npm pack` 的输出装进真实 profile,由 npm 上的 dsh launcher 启动,配 keyless mock 模型。那里通过的就是用户装到的。
47
-
48
- ### 对着 dsh 源码调试
49
-
50
- 日常里 dsh 是普通的 npm 依赖。需要单步进 harness 代码时,把 [deepseek-harness](https://github.com/deepseek-ai/deepseek-harness) clone 到本仓库旁边并构建(`pnpm install && pnpm run build`),然后把要调试的包指向 checkout:
51
-
52
- ```jsonc
53
- // package.json —— 调完删掉;npm 始终是默认
54
- "pnpm": {
55
- "overrides": {
56
- "@deepseek-ai/dsh-agent-loop": "link:../deepseek-harness/packages/core/agent-loop"
57
- }
58
- }
59
- ```
60
-
61
- 再执行 `pnpm install`。想进上游的改动以普通 PR 提交到 harness 仓库;本仓库绝不 fork 它。
62
-
63
- ## 许可
64
-
65
- MIT