Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,22 @@ jobs:
cache: 'pnpm'
registry-url: https://registry.npmjs.org
- run: pnpm install --frozen-lockfile
- run: pnpm build

# Before `pnpm build`: core's VERSION is compiled into dist, and it is what
# `deepcode --version`, `--help`, `/upgrade` and `/bug` print.
- name: Stamp core VERSION from tag
run: |
sed -i.bak -E "s/^export const VERSION = '.*';/export const VERSION = '${{ needs.validate.outputs.version }}';/" packages/core/src/index.ts
rm -f packages/core/src/index.ts.bak
grep -q "export const VERSION = '${{ needs.validate.outputs.version }}';" packages/core/src/index.ts

- name: Set CLI version from tag
run: |
cd apps/cli
npm version "${{ needs.validate.outputs.version }}" --no-git-tag-version

- run: pnpm build

- name: Publish
run: |
cd apps/cli
Expand Down Expand Up @@ -123,6 +132,12 @@ jobs:
cache: 'pnpm'
- run: pnpm install --frozen-lockfile

# The extension bundles its own app-server, which bundles core.
- name: Stamp core VERSION from tag
run: |
sed -i.bak -E "s/^export const VERSION = '.*';/export const VERSION = '${{ needs.validate.outputs.version }}';/" packages/core/src/index.ts
rm -f packages/core/src/index.ts.bak

- name: Set extension version from tag
run: npm version "${{ needs.validate.outputs.version }}" --no-git-tag-version
working-directory: apps/vscode
Expand Down Expand Up @@ -187,6 +202,9 @@ jobs:

- name: Set version
run: |
# core VERSION first — the sidecar it builds into reports it.
sed -i.bak -E "s/^export const VERSION = '.*';/export const VERSION = '${{ needs.validate.outputs.version }}';/" packages/core/src/index.ts
rm -f packages/core/src/index.ts.bak
cd apps/desktop
npm version "${{ needs.validate.outputs.version }}" --no-git-tag-version
# Sync the tauri.conf.json version too
Expand All @@ -197,9 +215,19 @@ jobs:
c.version='${{ needs.validate.outputs.version }}';
fs.writeFileSync(p, JSON.stringify(c,null,2)+'\n');
"
# And Cargo.toml
# And Cargo.toml + the lockfile entry, which must agree or a --locked
# cargo invocation refuses to build.
sed -i.bak -E 's/^version = ".*"/version = "${{ needs.validate.outputs.version }}"/' src-tauri/Cargo.toml
rm -f src-tauri/Cargo.toml.bak
node -e "
const fs=require('fs');
const p='src-tauri/Cargo.lock';
const s=fs.readFileSync(p,'utf8');
fs.writeFileSync(p, s.replace(
/name = \"deepcode_desktop\"\nversion = \"[^\"]+\"/,
'name = \"deepcode_desktop\"\nversion = \"${{ needs.validate.outputs.version }}\"'
));
"

- name: Import Developer ID certificate
env:
Expand Down
4 changes: 2 additions & 2 deletions apps/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "deepcode-cli",
"version": "0.1.6",
"description": "DeepCode CLI — DeepSeek-powered AI coding agent, parity with Claude Code",
"version": "0.2.0",
"description": "DeepCode CLI — DeepSeek-powered AI coding agent for real codebases",
"license": "MIT",
"type": "module",
"bin": {
Expand Down
11 changes: 10 additions & 1 deletion apps/cli/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ async function main(): Promise<number> {
return 2;
}

// Accepted-but-inert flags. Warn rather than exit: they used to be listed in
// `--help` and may already sit in someone's scripts, but silently ignoring a
// flag the user deliberately passed is worse than a noisy line on stderr.
if (args.unimplementedFlags.length > 0) {
for (const flag of args.unimplementedFlags) {
process.stderr.write(`Warning: ${flag} is not implemented yet and was ignored.\n`);
}
}

// -C / --cd <dir>: change the working directory before anything resolves cwd
// (Codex parity). Done here — after --help/--version short-circuit but before
// every subcommand/REPL/headless path that reads process.cwd() — so a single
Expand All @@ -61,7 +70,7 @@ async function main(): Promise<number> {
}
if (args.upgrade) {
process.stdout.write(`Run: npm i -g deepcode-cli@latest\n`);
process.stdout.write(`(Self-update via electron-updater is Mac-client only — see §4b.)\n`);
process.stdout.write(`(The Mac client updates itself; only the CLI needs this.)\n`);
return 0;
}

Expand Down
54 changes: 53 additions & 1 deletion apps/cli/src/parse-args.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest';
import { parseArgs, resolveEffort } from './parse-args.js';
import { helpText, parseArgs, resolveEffort } from './parse-args.js';

describe('parseArgs', () => {
it('parses empty argv', () => {
Expand Down Expand Up @@ -185,3 +185,55 @@ describe('resolveEffort (precedence)', () => {
expect(resolveEffort({ envVar: '', settingsLevel: 'max' })).toBe('max');
});
});

describe('flags that parse but do nothing', () => {
it('reports each inert flag instead of silently ignoring it', () => {
const p = parseArgs([
'--agents',
'/tmp/a',
'--mcp-config',
'/tmp/m.json',
'--plugin-dir',
'/tmp/p',
'--plugin-url',
'gh:o/r',
'--strict',
]);
expect(p.unimplementedFlags).toEqual([
'--agents',
'--mcp-config',
'--plugin-dir',
'--plugin-url',
'--strict',
]);
// Still accepted, so existing scripts keep running rather than exiting 2.
expect(p.unknownFlags).toEqual([]);
});

it('leaves implemented flags out of the report', () => {
const p = parseArgs(['--settings', '/tmp/s.json', '--no-plugins', '--bare']);
expect(p.unimplementedFlags).toEqual([]);
expect(p.settingsFile).toBe('/tmp/s.json');
expect(p.noPlugins).toBe(true);
expect(p.bare).toBe(true);
});
});

describe('helpText', () => {
const help = helpText('9.9.9');

it('does not advertise flags nothing consumes', () => {
for (const flag of ['--agents', '--mcp-config', '--plugin-dir', '--plugin-url', '--strict']) {
expect(help).not.toContain(flag);
}
});

it('still documents the overrides that work', () => {
expect(help).toContain('--settings');
expect(help).toContain('--no-plugins');
});

it('describes --bare as what it actually does', () => {
expect(help).toMatch(/--bare\s+Suppress the REPL startup banner/);
});
});
29 changes: 20 additions & 9 deletions apps/cli/src/parse-args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ export interface ParsedArgs {

// Diagnostics
unknownFlags: string[];
/**
* Flags that parse but have no consumer yet. They are accepted (so existing
* scripts keep running) and reported once at startup, rather than silently
* doing nothing — which is how `--permission-mode` shipped broken for months.
* Not listed in `--help`: `--help` documents what works.
*/
unimplementedFlags: string[];

// Positional args (rarely used)
positional: string[];
Expand Down Expand Up @@ -114,6 +121,7 @@ export function parseArgs(argv: string[]): ParsedArgs {
noPlugins: false,
strict: false,
unknownFlags: [],
unimplementedFlags: [],
positional: [],
};

Expand Down Expand Up @@ -237,23 +245,31 @@ export function parseArgs(argv: string[]): ParsedArgs {
case a === '--settings':
out.settingsFile = next();
break;
// The four override flags below and `--strict` are still parsed so old
// invocations don't hard-fail, but nothing consumes them yet. Record them
// so the CLI can say so instead of pretending they took effect.
case a === '--agents':
out.agentsDir = next();
out.unimplementedFlags.push('--agents');
break;
case a === '--mcp-config':
out.mcpConfig = next();
out.unimplementedFlags.push('--mcp-config');
break;
case a === '--plugin-dir':
out.pluginDir = next();
out.unimplementedFlags.push('--plugin-dir');
break;
case a === '--plugin-url':
out.pluginUrl = next();
out.unimplementedFlags.push('--plugin-url');
break;
case a === '--no-plugins':
out.noPlugins = true;
break;
case a === '--strict':
out.strict = true;
out.unimplementedFlags.push('--strict');
break;
case a.startsWith('--'):
out.unknownFlags.push(a);
Expand All @@ -271,7 +287,7 @@ export function parseArgs(argv: string[]): ParsedArgs {
}

export function helpText(version: string): string {
return `DeepCode v${version} — DeepSeek-powered AI coding agent (Claude Code parity)
return `DeepCode v${version} — DeepSeek-powered AI coding agent

USAGE
deepcode Interactive REPL
Expand All @@ -297,8 +313,8 @@ USAGE

MODE
--mode <name> default / acceptEdits / plan / auto / dontAsk / bypassPermissions
--permission-mode <name> Alias for --mode (Claude Code parity)
--bare No plugins / MCP / skills — just kernel + tools
--permission-mode <name> Alias for --mode (Claude Code compatibility)
--bare Suppress the REPL startup banner (scripting / minimal output)

WORKING DIRECTORY
-C, --cd <dir> Change to <dir> before running (default: current dir)
Expand Down Expand Up @@ -326,13 +342,8 @@ HEADLESS / CI (-p mode only)
Exit codes (headless): 0 ok · 1 generic · 2 bad-input · 3 api/auth · 4 max-turns · 5 aborted

OVERRIDES
--settings <path> Override settings.json discovery
--agents <dir> Override sub-agents dir
--mcp-config <path> Override MCP server config
--plugin-dir <dir> Temporarily mount a plugin dir
--plugin-url <gh:user/repo> Temporarily mount a remote plugin
--settings <path> Override settings.json discovery (highest-precedence layer)
--no-plugins Disable all plugins for this run
--strict Strict mode: only official-marketplace plugins, no hooks

DIAGNOSTICS
-h, --help Show this
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@deepcode/desktop",
"version": "0.1.6",
"version": "0.2.0",
"private": true,
"description": "DeepCode Mac desktop client — Tauri + React",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apps/desktop/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "deepcode_desktop"
version = "0.1.6"
version = "0.2.0"
description = "DeepCode Mac desktop client"
authors = ["oratis"]
edition = "2021"
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "DeepCode",
"version": "0.1.6",
"version": "0.2.0",
"identifier": "dev.deepcode.desktop",
"build": {
"frontendDist": "../dist",
Expand Down
2 changes: 1 addition & 1 deletion apps/vscode/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "deepcode",
"displayName": "DeepCode",
"description": "DeepSeek-powered coding agent — Claude-Code parity inside VS Code.",
"description": "DeepSeek-powered coding agent inside VS Code — chat, review, and apply.",
"version": "0.0.0",
"publisher": "deepcode",
"private": true,
Expand Down
42 changes: 23 additions & 19 deletions docs/MIGRATION_FROM_CLAUDE_CODE.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# Migrating from Claude Code

DeepCode targets Claude Code parity. If you already use Claude Code,
most of your workflow ports over with renames + a different API key.
DeepCode started as a Claude Code-compatible tool and still reads the same
file formats, so most of your workflow ports over with renames + a different
API key. It is no longer chasing 1:1 parity — see
[`THREE_WAY_REVIEW.md`](THREE_WAY_REVIEW.md) for where the two now differ.

## TL;DR — the 5-minute switch

Expand Down Expand Up @@ -34,18 +36,18 @@ deepcode

## Field-by-field mapping

| Claude Code | DeepCode | Notes |
| ---------------------------------- | --------------------------------------- | ------------------------------------------------------------- |
| `~/.claude/credentials.json` | `~/.deepcode/credentials.json` | Same shape; just rename. |
| `~/.claude/settings.json` | `~/.deepcode/settings.json` | Schema mostly identical; see Settings table below. |
| `<proj>/.claude/settings.json` | `<proj>/.deepcode/settings.json` | Same. |
| `~/.claude/skills/<name>/SKILL.md` | `~/.deepcode/skills/<name>/SKILL.md` | Same frontmatter format. |
| `~/.claude/agents/*.md` | `~/.deepcode/agents/*.md` | Same shape. |
| `~/.claude/plugins/` | `~/.deepcode/plugins/` | Plugin manifest is identical (plugin.json). |
| `CLAUDE.md` (project root) | `AGENTS.md` (project root) | Or `DEEPCODE.md`. Both names recognized; AGENTS.md preferred. |
| `claude` CLI | `deepcode` CLI | Most flags identical (-p, --mode, --model, --effort). |
| `claude doctor` | `deepcode doctor` | Same. |
| `/login` | n/a — re-onboard via `deepcode` no-args | We don't have separate login state. |
| Claude Code | DeepCode | Notes |
| ---------------------------------- | ------------------------------------ | ------------------------------------------------------------- |
| `~/.claude/credentials.json` | `~/.deepcode/credentials.json` | Same shape; just rename. |
| `~/.claude/settings.json` | `~/.deepcode/settings.json` | Schema mostly identical; see Settings table below. |
| `<proj>/.claude/settings.json` | `<proj>/.deepcode/settings.json` | Same. |
| `~/.claude/skills/<name>/SKILL.md` | `~/.deepcode/skills/<name>/SKILL.md` | Same frontmatter format. |
| `~/.claude/agents/*.md` | `~/.deepcode/agents/*.md` | Same shape. |
| `~/.claude/plugins/` | `~/.deepcode/plugins/` | Plugin manifest is identical (plugin.json). |
| `CLAUDE.md` (project root) | `AGENTS.md` (project root) | Or `DEEPCODE.md`. Both names recognized; AGENTS.md preferred. |
| `claude` CLI | `deepcode` CLI | Most flags identical (-p, --mode, --model, --effort). |
| `claude doctor` | `deepcode doctor` | Same. |
| `/login` | `/login [<key>]` | Stores a new key; `/logout` clears it. No hosted account. |

## Settings.json — model field

Expand Down Expand Up @@ -144,9 +146,11 @@ sub-agents. Both reference systems work.
bridge once IDE-provider-routing lands — TBD).
2. **Pricing**: DeepSeek is 10-20× cheaper than Claude for similar
token counts. `/cost` reflects DeepSeek pricing.
3. **No image input yet**: vision provider abstraction exists but no
provider configured (v1.1).
4. **`/rewind`**: skeleton only — full rewind UX is in M7 (Mac client).
3. **No image input**: the vision abstraction exists but DeepSeek ships no
vision model, so nothing is wired to it. Screenshots/pasted images are
Claude Code-only.
4. **Terminal UI**: DeepCode's REPL is line-based, not a full-screen TUI.
No inline diffs, no `Shift+Tab` mode cycling, no `Ctrl+R` transcript.

## Behaviors that are NEW in DeepCode

Expand All @@ -155,11 +159,11 @@ sub-agents. Both reference systems work.
cost/latency per tier
- Pipeline-aware sandbox bypass (vs Claude Code's leading-token-only)
- LSP bridge (Neovim / Emacs / Sublime via `deepcode-lsp`)
- VS Code extension (skeleton; ships in v1.1)
- VS Code extension + LSP bridge, both driving the same app-server protocol

## Getting help

- `deepcode doctor` — diagnostic dump
- `deepcode --help` — flag reference
- `~/.deepcode/sessions/<id>.jsonl` — transcript of every session
- `~/.deepcode/sessions/<id>.v1.jsonl` — transcript of every session
- File issues at https://github.com/oratis/deepcode/issues
6 changes: 5 additions & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
// See docs/DEVELOPMENT_PLAN.md §3 for module structure.
// M1 surface: DeepSeekProvider + agent loop + 6 P0 tools + sessions

export const VERSION = '0.1.0';
// The string `deepcode --version`, `--help`, `/upgrade` and `/bug` all print.
// Kept in lockstep with apps/cli/package.json by scripts/version-consistency.test.ts,
// and rewritten from the tag by .github/workflows/release.yml at publish time —
// before this it stayed at 0.1.0 while the CLI shipped as 0.1.6.
export const VERSION = '0.2.0';
export const PROJECT_NAME = 'DeepCode';

// Types
Expand Down
Loading
Loading