|
2 | 2 |
|
3 | 3 | ## Project Structure & Module Organization |
4 | 4 |
|
5 | | -This is an **npm workspaces monorepo**. Packages live under `packages/`. |
6 | | - |
7 | | -``` |
8 | | -packages/ |
9 | | -├── core/src/ # LLM session, tool execution, shared utilities |
10 | | -│ ├── common/ # File I/O, permissions, telemetry, OpenAI client, shell utils, etc. |
11 | | -│ ├── tools/ # 9 built-in handlers (bash, read, write, edit, skill, web-search, ask-user-question, update-plan, understand-image) |
12 | | -│ ├── mcp/ # MCP client & manager (JSON-RPC lifecycle) |
13 | | -│ ├── session.ts # SessionManager — LLM loop, compaction, tool orchestration |
14 | | -│ ├── prompt.ts # System prompt builder & tool definitions |
15 | | -│ └── settings.ts # Settings resolution from ~/.deepcode/settings.json |
16 | | -├── cli/src/ # Terminal UI (Ink/React) |
17 | | -│ ├── cli.tsx # Entry point — renders AppContainer |
18 | | -│ ├── cli-args.ts # CLI argument parsing (yargs: -p, -r, -v, -h) |
19 | | -│ ├── common/ # Update checker |
20 | | -│ ├── utils/ # stdio helpers, version, package info |
21 | | -│ ├── generated/ # Build-time git commit info |
22 | | -│ ├── ui/views/ # Top-level screens (App, PromptInput, SessionList, PermissionPrompt, WelcomeScreen, UpdatePrompt, McpStatusList, etc.) |
23 | | -│ ├── ui/components/ # Reusable Ink components (MessageView, DropdownMenu, ModelsDropdown, etc.) |
24 | | -│ ├── ui/core/ # Prompt buffer, slash commands, file mentions, clipboard, undo/redo |
25 | | -│ ├── ui/hooks/ # Custom hooks (cursor, history navigation, paste handling, terminal input, statusline) |
26 | | -│ ├── ui/contexts/ # React contexts (AppContext, RawModeContext) |
27 | | -│ ├── ui/statusline/ # Pluggable statusline providers (command, module) |
28 | | -│ ├── ui/utils/ # Shared UI utilities (writing, formatting) |
29 | | -│ └── tests/ # UI-focused tests with run-tests.mjs runner |
30 | | -├── vscode-ide-companion/ # VSCode extension companion |
31 | | -│ └── src/ # extension.ts, provider.ts, utils.ts |
32 | | -docs/ # User-facing documentation (configuration, MCP, notify, permissions) |
33 | | -scripts/ # Build, release, and packaging scripts |
34 | | -dist/ # Bundled CLI output — single-file dist/cli.js (gitignored) |
35 | | -dist/bundled/ # Bundled skills & references shipped with the CLI |
36 | | -``` |
37 | | - |
38 | | -Templates for tool descriptions and prompts are at `packages/cli/dist/templates/` (copied during build from `packages/core/templates/`). Built-in skills are under `packages/cli/dist/bundled/`. |
| 5 | +npm workspaces monorepo; packages live under `packages/`. |
| 6 | + |
| 7 | +- `packages/core/src/` — LLM session (`session.ts`), prompt/tool definitions (`prompt.ts`), settings resolution (`settings.ts`), `tools/` (10 built-in handlers), `common/` (permissions, OpenAI client, DeepSeek Files API, file history), `mcp/`. |
| 8 | +- `packages/cli/src/` — Ink/React terminal UI: `cli.tsx` entry, `ui/views`, `ui/components`, `ui/core`, `ui/hooks`, `tests/`. |
| 9 | +- `packages/vscode-ide-companion/` — VSCode extension companion. |
| 10 | +- `docs/` — user documentation; `scripts/` — build/release tooling; `dist/` — bundled CLI output (gitignored). |
39 | 11 |
|
40 | 12 | ## Build, Test, and Development Commands |
41 | 13 |
|
42 | 14 | All commands run from the repo root. |
43 | 15 |
|
44 | | -| Command | What it does | |
45 | | -|---|---| |
46 | | -| `npm run typecheck` | TypeScript type checking across all workspaces | |
47 | | -| `npm run lint` | ESLint across `packages/*/src/**/*.{ts,tsx}` + `scripts/*.js` | |
48 | | -| `npm run lint:fix` | ESLint with auto-fix | |
49 | | -| `npm run format` | Prettier on all source files | |
50 | | -| `npm run format:check` | Prettier in check-only mode | |
51 | | -| `npm run check` | Runs typecheck + lint + format:check together | |
52 | | -| `npm run build` | Orchestrates full build (scripts/build.js) — compiles core + bundles CLI + copies assets | |
53 | | -| `npm run bundle` | Generates git commit info + esbuild bundle + copies bundled assets | |
54 | | -| `npm run build:vscode` | Builds the VSCode extension companion | |
55 | | -| `npm test` | Runs all workspace tests (`npm run test --workspaces --if-present`) | |
56 | | -| `npm run start` | Runs the locally built CLI (`scripts/start.js`) | |
57 | | -| `npm run build-and-start` | Builds then starts the CLI | |
58 | | -| `npm run clean` | Removes generated files and dist directories | |
59 | | -| `npm run release:version` | Bumps version across all packages | |
60 | | -| `npm run prepare:package` | Prepares the CLI package for distribution | |
61 | | -| `npm run prepare:vscode` | Prepares the VSCode extension for distribution | |
62 | | - |
63 | | -To run a **single test file** within a package: |
64 | | -``` |
65 | | -node packages/core/src/tests/run-tests.mjs packages/core/src/tests/session.test.ts |
66 | | -node packages/cli/src/tests/run-tests.mjs packages/cli/src/tests/slash-commands.test.ts |
67 | | -``` |
68 | | - |
69 | | -Run the CLI locally for manual testing: `node packages/cli/dist/cli.js` (after `npm run bundle`). |
| 16 | +- `npm run typecheck`, `npm run lint`, `npm run format:check` — type/lint/format checks; `npm run check` runs all three. |
| 17 | +- `npm run build` — full build (core + CLI bundle + assets); `npm run bundle` — esbuild bundle + git info; `npm run build:vscode` — VSCode companion. |
| 18 | +- `npm test` — all workspace tests; `npm run start` — run the built CLI. |
| 19 | +- Single test: `node packages/core/src/tests/run-tests.mjs packages/core/src/tests/session.test.ts`. |
| 20 | +- Manual run: `node packages/cli/dist/cli.js` (after `npm run bundle`). |
70 | 21 |
|
71 | 22 | ## Coding Style & Naming Conventions |
72 | 23 |
|
73 | | -- **Indentation**: 2 spaces, no tabs |
74 | | -- **Quotes**: Double quotes (`"`) |
75 | | -- **Semicolons**: Required |
76 | | -- **Trailing commas**: `es5` (objects, arrays, etc.) |
77 | | -- **Line width**: 120 characters max |
78 | | -- **Line endings**: LF only |
79 | | - |
80 | | -**TypeScript**: Strict mode enabled (`strict: true`). Use `import type` for type-only imports (`@typescript-eslint/consistent-type-imports`). Unused variables prefixed with `_` are allowed (`argsIgnorePattern: "^_"`). Target ES2022, module ESNext with bundler resolution. JSX is `react-jsx`. |
81 | | - |
82 | | -**Formatting/Linting**: Prettier (double quotes, 2-space indent, semicolons) + ESLint (typescript-eslint, react-hooks). Run `npm run check` before pushing. On commit, Husky + lint-staged auto-formats staged `*.{ts,tsx,js,mjs,cjs,jsx}` and `*.json` files. |
83 | | - |
84 | | -**File naming**: `kebab-case.ts` for modules, `kebab-case.tsx` for React/Ink components. Test files: `*.test.ts` (always kebab-case). |
| 24 | +- 2-space indent, double quotes, semicolons, `es5` trailing commas, 120-char lines, LF endings. |
| 25 | +- TypeScript strict; `import type` for type-only imports; `_` prefix for unused vars; ES2022/ESNext; JSX `react-jsx`. |
| 26 | +- Prettier + ESLint; Husky/lint-staged formats staged files on commit. |
| 27 | +- Files: `kebab-case.ts`; components `kebab-case.tsx`; tests `*.test.ts`. |
85 | 28 |
|
86 | 29 | ## Testing Guidelines |
87 | 30 |
|
88 | | -- **Framework**: Node.js native test runner (`node:test`) with `tsx` for TypeScript |
89 | | -- **Assertions**: `node:assert/strict` |
90 | | -- **Coverage**: Target meaningful unit tests for core logic (session management, tool handlers, settings resolution, prompt buffer, permissions, MCP client, telemetry). Test files are in `packages/*/src/tests/` matching the source module name. |
91 | | -- **Test naming**: `describe`/`test` blocks with descriptive names. Example: `test("SessionManager preserves structured system content when building OpenAI messages", ...)` |
92 | | -- **Relaxed lint rules**: Test files allow `any` and unused vars. |
93 | | -- Run all tests with `npm test` before submitting a PR. Each package has its own `run-tests.mjs` cross-platform runner. |
| 31 | +- Node native test runner (`node:test`) via `tsx`; assertions with `node:assert/strict`. |
| 32 | +- Tests live in `packages/*/src/tests/` matching the source module name; descriptive `describe`/`test` names. |
| 33 | +- Run `npm test` before submitting a PR. |
94 | 34 |
|
95 | 35 | ## Commit & Pull Request Guidelines |
96 | 36 |
|
97 | | -**Commit messages** follow conventional commits: |
98 | | - |
99 | | -- `feat:` — new feature (e.g., `feat: add /model command`) |
100 | | -- `fix:` — bug fix (e.g., `fix(mcp): fix Windows MCP spawn double-quoting`) |
101 | | -- `chore:` — tooling, deps, hooks (e.g., `chore: add husky + lint-staged`) |
102 | | -- `refactor:` — code restructuring (e.g., `refactor(ui): optimize App hooks`) |
103 | | -- `style:` — formatting-only changes |
104 | | -- `test:` — adding or updating tests |
105 | | -- `docs:` — documentation changes |
106 | | -- `perf:` — performance improvements |
107 | | -- `build:` — build system changes |
108 | | - |
109 | | -**Pull requests** should include: |
110 | | -- A clear description of what changed and why |
111 | | -- Link to related issue(s) if applicable |
112 | | -- Screenshots or terminal recordings for UI changes |
113 | | -- All checks passing (`npm run check && npm test`) |
114 | | -- No unintended changes to `dist/` or `package-lock.json` without justification |
| 37 | +- Conventional commits: `feat:`, `fix:`, `chore:`, `refactor:`, `style:`, `test:`, `docs:`, `perf:`, `build:`. |
| 38 | +- PRs: clear description, linked issues, screenshots for UI changes, `npm run check && npm test` passing, no unintended `dist/` or `package-lock.json` changes. |
115 | 39 |
|
116 | 40 | ## Architecture Overview |
117 | 41 |
|
118 | | -The CLI (`@vegamo/deepcode-cli`) renders a terminal UI using [Ink](https://github.com/vadimdemedes/ink) (React for terminals). `SessionManager` (in `@vegamo/deepcode-core`) drives the LLM interaction loop: it builds system prompts, sends user messages with optional skills/images, streams responses, executes tool calls via `ToolExecutor`, and compacts context when token thresholds are exceeded (configurable via the `contextWindow` and `autoCompactWindow` settings). OpenAI client connectivity is managed by `createOpenAIClient()` with a 180-second keep-alive timeout; `resolveOpenAIConnection()` falls back to the DeepCode Plus endpoint when no API key is set but a DeepCode Plus key is available. API errors are normalized through `describeLlmError()` in `packages/core/src/common/llm-error.ts`, which produces credential-safe, structured error details. Image support is inferred per model by `supportsMultimodal()` in `packages/core/src/common/model-capabilities.ts`; the `multimodal` setting (`"default"`, `"on"`, or `"off"`, also settable via `MULTIMODAL` env) overrides that inference. |
119 | | - |
120 | | -Nine built-in tools are available to the LLM: `bash`, `read`, `write`, `edit`, `skill`, `AskUserQuestion`, `UpdatePlan`, `UnderstandImage`, and `WebSearch`. The `skill` tool loads full instructions for a skill listed in the session skill catalog. `UnderstandImage` and `WebSearch` are plugin-backed and normalize rate-limit responses; `WebSearch` is driven by the DeepSeek Responses API. The `read` tool returns a `snippet_id` that must be passed to subsequent `edit` calls, ensuring edits always operate on a known, session-local file snapshot. Tool definitions are registered in `packages/core/src/tools/executor.ts` and described to the LLM via `packages/core/src/prompt.ts`. |
121 | | - |
122 | | -A **permission system** (`packages/core/src/common/permissions.ts`) controls tool execution scopes (read/write/delete/network/git-log, etc.) with configurable allow/deny/ask decisions. |
123 | | - |
124 | | -A **file history system** (`packages/core/src/common/file-history.ts`) provides undo/checkpoint support via lightweight Git branches. |
125 | | - |
126 | | -**Slash commands**: `/skills`, `/model`, `/plan`, `/new`, `/init`, `/resume`, `/fork`, `/continue`, `/undo`, `/mcp`, `/raw`, `/exit`, plus dynamic `/skill-name` for each loaded skill. |
127 | | - |
128 | | -**Plan Mode** (`/plan` or `Shift+Tab`): Restricts the agent to read-only operations on the first turn and requires it to produce a task plan via `<proposed_plan>` for user approval before any file writes, deletions, or git mutations. When enabled, write/delete/mutate-git-log permissions are force-asked regardless of user settings. |
129 | | - |
130 | | -**Key UI features**: `@` file mentions in the prompt input, `Ctrl+O` to view live process stdout, `Ctrl+V` to paste images, `Ctrl+X` to clear images, Shift+Enter for newlines, `Shift+Tab` to toggle Plan Mode, pluggable statusline, MCP server status display, undo selector, and permission prompts. |
131 | | - |
132 | | -**CLI flags**: `-p <prompt>` / `--prompt` to auto-submit a prompt on launch, `-x` / `--exec` to run a prompt non-interactively, `-r [sessionId]` / `--resume [sessionId]` to resume a session or show the session picker, `-f [sessionId]` / `--fork` to fork a session, `-l` / `--last` to resume the most recent session, `-v` / `--version`, `-h` / `--help`. |
| 42 | +- `@vegamo/deepcode-cli` renders a terminal UI with Ink; `SessionManager` (`@vegamo/deepcode-core`) drives the LLM loop — prompts, streaming, `ToolExecutor`, context compaction (`contextWindow`/`autoCompactWindow`). |
| 43 | +- Connectivity: `createOpenAIClient()` (180s keep-alive) with DeepCode Plus fallback; errors normalized via `describeLlmError()`. |
| 44 | +- Tools: 10 built-ins — `bash`, `read`, `write`, `edit`, `skill`, `AskUserQuestion`, `UpdatePlan`, `WebSearch`, `ReadImage`, `UnderstandImage`. `ReadImage` (multimodal models) returns the image itself, validated/downscaled via Sharp; `UnderstandImage` is the plugin-backed fallback. `read` returns a `snippet_id` for subsequent `edit` calls. |
| 45 | +- Images: `supportsMultimodal()` + `multimodal` setting choose `ReadImage` vs `UnderstandImage`; `filesApiEnabled` uploads images to the DeepSeek Files API, caching file IDs in `~/.deepcode/files-api-cache.json`. |
| 46 | +- Permissions (`permissions.ts`) control allow/deny/ask by scope; `file-history.ts` provides undo via lightweight Git branches. |
| 47 | +- Models: default `deepseek-v4-flash`; `/model` offers `deepseek-v4-pro`, `deepseek-v4-flash`, `deepseek-v4-flash-vision-exp` with reasoning effort `low`/`high`/`max`. |
| 48 | +- Slash commands: `/skills`, `/model`, `/plan`, `/new`, `/init`, `/resume`, `/fork`, `/continue`, `/undo`, `/mcp`, `/raw`, `/exit`, plus dynamic `/skill-name`. Plan Mode (`/plan` or `Shift+Tab`) requires `<proposed_plan>` approval before writes. |
| 49 | +- CLI flags: `-p`, `-x`, `-r`, `-f`, `-l`, `-v`, `-h`. |
133 | 50 |
|
134 | 51 | ## Agent-Specific Instructions |
135 | 52 |
|
136 | | -- **AGENTS.md loading**: The CLI loads agent instructions from `./AGENTS.md`, `./.deepcode/AGENTS.md`, or `~/.deepcode/AGENTS.md` (first found wins). |
137 | | -- **Skills**: Place skill definitions in `~/.agents/skills/<name>/SKILL.md` (user-level) or `./.agents/skills/<name>/SKILL.md` (project-level); the legacy path `./.deepcode/skills/` is also scanned. Each SKILL.md uses YAML frontmatter with `name` and `description` fields. The session catalog contains skill summaries only — call the `skill` tool with the exact skill name to load full instructions before acting. Disable skills by name via the `enabledSkills` setting. |
138 | | -- **Built-in skills**: Four bundled skills ship with the CLI — `deepcode-self-refer` (Deep Code CLI documentation), `image-generator` (text-to-image generation & editing), `skill-digester` (digest & install skills), `skill-writer` (create & debug skills). |
139 | | -- **Prompt file references**: Use `@path/to/file` syntax in prompts to load file contents through the read tool. |
| 53 | +- AGENTS.md loads from `./AGENTS.md`, `./.deepcode/AGENTS.md`, or `~/.deepcode/AGENTS.md` (first found wins). |
| 54 | +- Skills: `~/.agents/skills/<name>/SKILL.md` (user) or `./.agents/skills/<name>/SKILL.md` (project); legacy `./.deepcode/skills/` also scanned. Call the `skill` tool for full instructions. Bundled: `deepcode-self-refer`, `image-generator`, `skill-digester`, `skill-writer`. |
| 55 | +- Prompt file references: `@path/to/file`. |
0 commit comments