tandem-mode 0.0.1

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.
Files changed (76) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +191 -0
  3. package/README.sr.md +194 -0
  4. package/dist/agent/clipboard.js +26 -0
  5. package/dist/agent/clipboard.js.map +1 -0
  6. package/dist/agent/loop.js +157 -0
  7. package/dist/agent/loop.js.map +1 -0
  8. package/dist/agent/pricing.js +21 -0
  9. package/dist/agent/pricing.js.map +1 -0
  10. package/dist/agent/session.js +78 -0
  11. package/dist/agent/session.js.map +1 -0
  12. package/dist/agent/tools/edit.js +78 -0
  13. package/dist/agent/tools/edit.js.map +1 -0
  14. package/dist/agent/tools/gitDiff.js +42 -0
  15. package/dist/agent/tools/gitDiff.js.map +1 -0
  16. package/dist/agent/tools/index.js +24 -0
  17. package/dist/agent/tools/index.js.map +1 -0
  18. package/dist/agent/tools/listDir.js +29 -0
  19. package/dist/agent/tools/listDir.js.map +1 -0
  20. package/dist/agent/tools/readFile.js +40 -0
  21. package/dist/agent/tools/readFile.js.map +1 -0
  22. package/dist/agent/tools/search.js +51 -0
  23. package/dist/agent/tools/search.js.map +1 -0
  24. package/dist/agent/tools/shell.js +95 -0
  25. package/dist/agent/tools/shell.js.map +1 -0
  26. package/dist/agent/tools/types.js +11 -0
  27. package/dist/agent/tools/types.js.map +1 -0
  28. package/dist/agent/tools/viewImage.js +34 -0
  29. package/dist/agent/tools/viewImage.js.map +1 -0
  30. package/dist/agent/tools/webSearch.js +27 -0
  31. package/dist/agent/tools/webSearch.js.map +1 -0
  32. package/dist/agent/usage.js +36 -0
  33. package/dist/agent/usage.js.map +1 -0
  34. package/dist/benchmark/runner.js +176 -0
  35. package/dist/benchmark/runner.js.map +1 -0
  36. package/dist/benchmark/tasks/bitwiseBulkPriceWizard.js +50 -0
  37. package/dist/benchmark/tasks/bitwiseBulkPriceWizard.js.map +1 -0
  38. package/dist/benchmark/types.js +2 -0
  39. package/dist/benchmark/types.js.map +1 -0
  40. package/dist/cli.js +442 -0
  41. package/dist/cli.js.map +1 -0
  42. package/dist/config/credentials.js +80 -0
  43. package/dist/config/credentials.js.map +1 -0
  44. package/dist/config/env.js +12 -0
  45. package/dist/config/env.js.map +1 -0
  46. package/dist/config/schema.js +6 -0
  47. package/dist/config/schema.js.map +1 -0
  48. package/dist/config/store.js +35 -0
  49. package/dist/config/store.js.map +1 -0
  50. package/dist/deepseek/client.js +145 -0
  51. package/dist/deepseek/client.js.map +1 -0
  52. package/dist/deepseek/types.js +2 -0
  53. package/dist/deepseek/types.js.map +1 -0
  54. package/dist/deepseek/vision.js +59 -0
  55. package/dist/deepseek/vision.js.map +1 -0
  56. package/dist/deepseek/webSearch.js +43 -0
  57. package/dist/deepseek/webSearch.js.map +1 -0
  58. package/dist/orchestrator/orchestrate.js +63 -0
  59. package/dist/orchestrator/orchestrate.js.map +1 -0
  60. package/dist/orchestrator/planner.js +48 -0
  61. package/dist/orchestrator/planner.js.map +1 -0
  62. package/dist/orchestrator/repoMap.js +52 -0
  63. package/dist/orchestrator/repoMap.js.map +1 -0
  64. package/dist/orchestrator/reviewer.js +53 -0
  65. package/dist/orchestrator/reviewer.js.map +1 -0
  66. package/dist/orchestrator/types.js +18 -0
  67. package/dist/orchestrator/types.js.map +1 -0
  68. package/dist/repl/commands.js +139 -0
  69. package/dist/repl/commands.js.map +1 -0
  70. package/dist/repl/state.js +2 -0
  71. package/dist/repl/state.js.map +1 -0
  72. package/dist/repl/system-prompt.js +5 -0
  73. package/dist/repl/system-prompt.js.map +1 -0
  74. package/dist/repl/wizard.js +34 -0
  75. package/dist/repl/wizard.js.map +1 -0
  76. package/package.json +49 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Zdravko Lukic
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 ADDED
@@ -0,0 +1,191 @@
1
+ # Tandem Mode
2
+
3
+ **English** | [Srpski](./README.sr.md)
4
+
5
+ A terminal coding agent built specifically for the DeepSeek API — not a generic
6
+ LLM harness with DeepSeek bolted on. Interactive REPL, planner/worker/reviewer
7
+ orchestration, cache-aware prompt architecture, and Windows-first from the
8
+ start.
9
+
10
+ > **Independent open-source project. Not affiliated with or endorsed by
11
+ > DeepSeek.**
12
+
13
+ ## Status
14
+
15
+ Early stage (M0–M3 of the [development plan](./deepseek-cli-development-plan.md)
16
+ are done, M4 in progress). Usable today for real coding tasks against a local
17
+ repo.
18
+
19
+ First benchmark run is in — see [full results](./docs/benchmark-results.md).
20
+ Headline: all three configurations (Pro-only, Flash-only, orchestration)
21
+ fixed 4/4 injected bugs correctly in a real WooCommerce plugin, with a clean
22
+ `php -l` and zero unnecessary file changes. But for this class of task
23
+ (single-file, well-scoped fixes), orchestration cost ~9.5× more and took
24
+ ~19× longer than Pro-only for the same correctness — the opposite of what
25
+ you'd want orchestration for. Read as: orchestration's overhead needs a
26
+ bigger, more decomposable task to pay for itself, which this first run didn't
27
+ test. Reported as-is, not adjusted to fit expectations.
28
+
29
+ ## Features
30
+
31
+ - **Agentic loop** — `deepseek-v4-pro`/`deepseek-v4-flash` with tool calling:
32
+ `read_file`, `list_dir`, `search`, `edit`, `git_diff`, `shell`, `view_image`,
33
+ `web_search`.
34
+ - **Two entry points** — interactive REPL for normal work, single-shot mode
35
+ (`tandem "task" --yes`) for scripting and CI.
36
+ - **Orchestration** (`/plan`) — a planner produces a JSON task list, workers
37
+ execute each task with a fresh minimal context, a reviewer checks the git
38
+ diff against the original task and either approves or requests corrections
39
+ (capped by `max_review_loops`).
40
+ - **Cache-aware prompts** — the worker's system prompt + repo map + plan stay
41
+ byte-identical across calls in one orchestration run, so DeepSeek's context
42
+ cache actually hits. Measured live: cache-hit tokens grew call over call
43
+ within a single `/plan` run.
44
+ - **Vision** — `view_image` lets the agent look at a screenshot you point it
45
+ to; `/paste` grabs an image straight from the Windows clipboard.
46
+ - **Web search** — isolated calls to DeepSeek's Responses API when the agent
47
+ needs something outside the repo (an error message, a library's docs).
48
+ - **Session persistence** — every session is a JSONL file; `/resume` continues
49
+ the latest (or a named) one, `/fork` branches off without touching the
50
+ original.
51
+ - **Safety** — destructive actions (file edits, shell commands not on a small
52
+ read-only allowlist) always ask for confirmation; `y`/`n`/`a` where `a`
53
+ remembers the choice for that tool for the rest of the session. `--yes`
54
+ bypasses this for CI but always prints what it auto-approved.
55
+ - **Cost control** — usage is read only from the API's own `usage` field,
56
+ never estimated. A budget (`/budget`, `--budget`) hard-stops the loop before
57
+ the next API call if exceeded, without losing the session. `/usage` also
58
+ shows what the session would have cost off-peak, and the REPL warns you at
59
+ startup if you're currently in a peak-pricing window.
60
+ - **ESC to interrupt** — cancels the in-flight call (and any running shell
61
+ command) cleanly, keeping whatever was generated so far.
62
+ - **Windows-first** — the shell tool runs PowerShell natively, file edits
63
+ preserve the original CRLF/LF line ending style, paths are handled with
64
+ `path.resolve` throughout.
65
+
66
+ ## Quick start
67
+
68
+ ```bash
69
+ git clone https://github.com/zdrave08/Tandem-Mode.git
70
+ cd Tandem-Mode
71
+ pnpm install
72
+ pnpm dev # interactive REPL
73
+ pnpm dev "explain what this repo does" --yes # one-shot
74
+ ```
75
+
76
+ (Not yet published to npm — `npm install -g tandem-mode` is a launch-day step,
77
+ not available today.)
78
+
79
+ To try it as a real installed `tandem` command instead of `pnpm dev` (useful
80
+ before publishing, or to use it in another project without cloning next to
81
+ it):
82
+
83
+ ```bash
84
+ pnpm build
85
+ npm link # registers `tandem` globally, pointing at this checkout
86
+ tandem # now works from any directory
87
+ ```
88
+
89
+ On first run you'll be asked for a DeepSeek API key (get one at
90
+ [platform.deepseek.com](https://platform.deepseek.com)) and a default
91
+ model/reasoning effort. On Windows the key is stored DPAPI-encrypted
92
+ (tied to your OS user account, same protection Credential Manager itself
93
+ relies on) in `%LOCALAPPDATA%\TandemMode\credentials.dat` — never in a
94
+ config file or log. Linux/macOS storage isn't implemented yet (`DEEPSEEK_API_KEY`
95
+ works everywhere in the meantime) — see good-first-issues.
96
+
97
+ ## Usage
98
+
99
+ ```bash
100
+ tandem # interactive REPL
101
+ tandem "fix the off-by-one in foo.ts"
102
+ tandem --plan "add dark mode to the settings page"
103
+ tandem "task" --model deepseek-v4-flash --effort low --budget 0.50 --yes
104
+ ```
105
+
106
+ | Flag | Effect |
107
+ |---|---|
108
+ | `--resume` / `-r` | Continue the latest session in this directory |
109
+ | `--yes` / `-y` | Auto-approve destructive actions (prints what it approved) |
110
+ | `--plan` | Run planner/worker/reviewer orchestration instead of a single turn |
111
+ | `--model` | `deepseek-v4-pro` or `deepseek-v4-flash` |
112
+ | `--effort` | `low`, `high`, or `max` reasoning effort |
113
+ | `--budget` | Hard USD cap for the run |
114
+ | `--max-review-loops` | Cap on orchestration correction cycles (default 3) |
115
+
116
+ ### REPL commands
117
+
118
+ | Command | Effect |
119
+ |---|---|
120
+ | `/plan <task>` | Planner/worker/reviewer orchestration |
121
+ | `/model [name]` | Show or switch model |
122
+ | `/thinking [on\|off]` | Toggle thinking mode |
123
+ | `/effort [low\|high\|max]` | Show or set reasoning effort |
124
+ | `/status` | Current session/settings |
125
+ | `/usage` | Tokens, cost, off-peak projection |
126
+ | `/budget [amount]` | Show or set the session budget |
127
+ | `/new` | Start a fresh session |
128
+ | `/fork` | New session, carrying over the current history |
129
+ | `/resume [id]` | Continue the latest (or a named) session |
130
+ | `/paste [message]` | Send a Windows-clipboard image to the agent |
131
+ | `/clear` | Clear the screen |
132
+ | `/help` | This list |
133
+ | `/exit` | Quit |
134
+
135
+ Press **ESC** at any time during a turn to interrupt it.
136
+
137
+ ## Architecture
138
+
139
+ ```
140
+ tandem (no args) ─┬─> interactive REPL ─┬─> single turn: agent loop (tools)
141
+ │ └─> /plan: planner → worker(s) → reviewer
142
+ tandem "task" ──┘ (single-shot, same agent loop, for scripts/CI)
143
+ ```
144
+
145
+ - `src/deepseek/` — thin client for DeepSeek's OpenAI-compatible API
146
+ (streaming + non-streaming chat completions, vision, web search via
147
+ Responses API). See [`docs/api-notes.en.md`](./docs/api-notes.en.md)
148
+ (Serbian original: [`docs/api-notes.md`](./docs/api-notes.md)) for the
149
+ API behavior this is built against, verified live rather than assumed.
150
+ - `src/agent/` — the tool-calling loop, tool implementations, session
151
+ persistence, usage/cost tracking.
152
+ - `src/orchestrator/` — planner/worker/reviewer, repo-map generation, the
153
+ cache-aware stable-prefix construction.
154
+ - `src/repl/` — slash commands, runtime config, the first-run wizard.
155
+ - `src/cli.tsx` — Ink-based terminal UI and the REPL/single-shot entry points.
156
+
157
+ ## Configuration
158
+
159
+ Layered: **session** (in-REPL commands) > **project** (`.tandem/config.json`
160
+ in the current directory) > **global** (`~/.tandem/config.json`).
161
+
162
+ ```json
163
+ {
164
+ "defaultModel": "deepseek-v4-pro",
165
+ "defaultReasoningEffort": "high",
166
+ "budgetUsd": 5,
167
+ "maxReviewLoops": 3
168
+ }
169
+ ```
170
+
171
+ The API key is never stored in these files — it lives DPAPI-encrypted on
172
+ Windows (or `DEEPSEEK_API_KEY` env var, which takes priority, for CI use).
173
+
174
+ ## Development
175
+
176
+ See [CONTRIBUTING.md](./CONTRIBUTING.md).
177
+
178
+ ```bash
179
+ pnpm install
180
+ pnpm typecheck
181
+ pnpm dev "some task"
182
+ ```
183
+
184
+ ## Disclaimer
185
+
186
+ This is an independent, community-run project. It is not affiliated with,
187
+ endorsed by, or sponsored by DeepSeek.
188
+
189
+ ## License
190
+
191
+ [MIT](./LICENSE)
package/README.sr.md ADDED
@@ -0,0 +1,194 @@
1
+ # Tandem Mode
2
+
3
+ [English](./README.md) | **Srpski**
4
+
5
+ Terminalski coding agent napravljen posebno za DeepSeek API — ne generički
6
+ LLM harness u koji je DeepSeek naknadno ugurana. Interaktivni REPL,
7
+ planner/worker/reviewer orkestracija, cache-aware arhitektura prompta, i
8
+ Windows kao prioritet od prvog dana.
9
+
10
+ > **Nezavisan open-source projekat. Nije povezan sa DeepSeek-om niti od
11
+ > njega podržan.**
12
+
13
+ ## Status
14
+
15
+ Rana faza (M0–M3 iz [plana razvoja](./deepseek-cli-development-plan.md) su
16
+ gotovi, M4 u toku). Upotrebljiv već danas za stvarne coding zadatke nad
17
+ lokalnim repozitorijumom.
18
+
19
+ Prvi benchmark je gotov — pun izveštaj u
20
+ [docs/benchmark-results.md](./docs/benchmark-results.md) (na engleskom;
21
+ srpska verzija: [docs/benchmark-results.sr.md](./docs/benchmark-results.sr.md)).
22
+ Ukratko: sve tri konfiguracije (Pro-only, Flash-only, orkestracija) su
23
+ ispravno rešile 4/4 ubačena bага u pravom WooCommerce pluginu, sa čistim
24
+ `php -l` i nula nepotrebnih izmena. Ali za ovu klasu zadatka (mali,
25
+ jednodatotečni fixevi) orkestracija je koštala ~9.5× više i trajala ~19×
26
+ duže od Pro-only, za isti kvalitet — suprotno onome zbog čega bi se
27
+ orkestracija tražila. Čitati kao: overhead orkestracije treba veći,
28
+ razdvojiv zadatak da bi se isplatio, a ovaj prvi test to nije proverio.
29
+ Prijavljeno onako kako jeste, ne prilagođeno očekivanjima.
30
+
31
+ ## Šta ima
32
+
33
+ - **Agentic petlja** — `deepseek-v4-pro`/`deepseek-v4-flash` sa tool-calling:
34
+ `read_file`, `list_dir`, `search`, `edit`, `git_diff`, `shell`, `view_image`,
35
+ `web_search`.
36
+ - **Dva načina rada** — interaktivni REPL za svakodnevni rad, single-shot
37
+ mod (`tandem "task" --yes`) za skriptovanje i CI.
38
+ - **Orkestracija** (`/plan`) — planner pravi JSON listu taskova, workeri
39
+ izvršavaju svaki task sa svežim minimalnim kontekstom, reviewer proverava
40
+ git diff naspram originalnog zadatka i ili odobrava ili traži korekcije
41
+ (ograničeno sa `max_review_loops`).
42
+ - **Cache-aware promptovi** — sistemski prompt workera + repo mapa + plan
43
+ ostaju bajt-za-bajt identični kroz pozive u jednoj orkestraciji, tako da
44
+ DeepSeek-ov keš stvarno pogađa. Izmereno uživo: cache-hit tokeni su rasli
45
+ iz poziva u poziv unutar jednog `/plan` pokretanja.
46
+ - **Vision** — `view_image` omogućava agentu da pogleda screenshot na koji
47
+ ga uputiš; `/paste` uzima sliku direktno iz Windows clipboard-a.
48
+ - **Web search** — izolovani pozivi ka DeepSeek Responses API-ju kad agentu
49
+ treba nešto van repozitorijuma (error poruka, dokumentacija biblioteke).
50
+ - **Perzistencija sesije** — svaka sesija je JSONL fajl; `/resume` nastavlja
51
+ poslednju (ili navedenu), `/fork` grana bez diranja originalne.
52
+ - **Bezbednost** — destruktivne akcije (izmene fajlova, shell komande van
53
+ male read-only bele liste) uvek traže potvrdu; `y`/`n`/`a` gde `a`
54
+ pamti izbor za taj alat do kraja sesije. `--yes` preskače ovo za CI, ali
55
+ uvek ispisuje šta je automatski odobreno.
56
+ - **Kontrola troškova** — usage se čita isključivo iz API-jevog `usage`
57
+ polja, nikad se ne procenjuje. Budžet (`/budget`, `--budget`) zaustavlja
58
+ petlju pre sledećeg poziva ako se pređe, bez gubitka sesije. `/usage`
59
+ takođe pokazuje koliko bi sesija koštala off-peak, a REPL upozorava pri
60
+ startu ako si trenutno u peak periodu.
61
+ - **ESC za prekid** — čisto prekida poziv u toku (i bilo koju shell komandu
62
+ koja radi), čuvajući ono što je do tada generisano.
63
+ - **Windows prioritet** — shell alat pokreće PowerShell nativno, izmene
64
+ fajlova čuvaju originalni CRLF/LF stil, putanje se svuda tretiraju preko
65
+ `path.resolve`.
66
+
67
+ ## Brzi početak
68
+
69
+ ```bash
70
+ git clone https://github.com/zdrave08/Tandem-Mode.git
71
+ cd Tandem-Mode
72
+ pnpm install
73
+ pnpm dev # interaktivni REPL
74
+ pnpm dev "objasni sta radi ovaj repo" --yes # jedan potez
75
+ ```
76
+
77
+ (Još nije objavljeno na npm-u — `npm install -g tandem-mode` je korak za
78
+ dan lansiranja, danas nije dostupan.)
79
+
80
+ Da probaš kao pravu instaliranu `tandem` komandu umesto `pnpm dev` (korisno
81
+ pre objave, ili da koristiš alat u drugom projektu bez kloniranja pored
82
+ njega):
83
+
84
+ ```bash
85
+ pnpm build
86
+ npm link # registruje `tandem` globalno, pokazuje na ovaj checkout
87
+ tandem # sad radi iz bilo kog direktorijuma
88
+ ```
89
+
90
+ Pri prvom pokretanju bićeš pitan za DeepSeek API ključ (napravi ga na
91
+ [platform.deepseek.com](https://platform.deepseek.com)) i podrazumevani
92
+ model/reasoning effort. Na Windows-u se ključ čuva DPAPI-šifrovan (vezan za
93
+ tvoj OS nalog, ista zaštita na kojoj se zasniva i sam Credential Manager) u
94
+ `%LOCALAPPDATA%\TandemMode\credentials.dat` — nikad u config fajlu ili logu.
95
+ Linux/macOS čuvanje još nije implementirano (`DEEPSEEK_API_KEY` radi svuda
96
+ u međuvremenu) — videti good-first-issues.
97
+
98
+ ## Upotreba
99
+
100
+ ```bash
101
+ tandem # interaktivni REPL
102
+ tandem "popravi off-by-one u foo.ts"
103
+ tandem --plan "dodaj dark mode na stranicu podešavanja"
104
+ tandem "task" --model deepseek-v4-flash --effort low --budget 0.50 --yes
105
+ ```
106
+
107
+ | Flag | Efekat |
108
+ |---|---|
109
+ | `--resume` / `-r` | Nastavi poslednju sesiju u ovom direktorijumu |
110
+ | `--yes` / `-y` | Automatski odobri destruktivne akcije (ispisuje šta je odobreno) |
111
+ | `--plan` | Pokreni planner/worker/reviewer orkestraciju umesto jednog poteza |
112
+ | `--model` | `deepseek-v4-pro` ili `deepseek-v4-flash` |
113
+ | `--effort` | `low`, `high`, ili `max` reasoning effort |
114
+ | `--budget` | Tvrd USD limit za pokretanje |
115
+ | `--max-review-loops` | Limit korekcionih ciklusa u orkestraciji (podrazumevano 3) |
116
+
117
+ ### REPL komande
118
+
119
+ | Komanda | Efekat |
120
+ |---|---|
121
+ | `/plan <zadatak>` | Planner/worker/reviewer orkestracija |
122
+ | `/model [ime]` | Prikaži ili promeni model |
123
+ | `/thinking [on\|off]` | Uključi/isključi thinking mode |
124
+ | `/effort [low\|high\|max]` | Prikaži ili postavi reasoning effort |
125
+ | `/status` | Trenutna sesija/podešavanja |
126
+ | `/usage` | Tokeni, cena, off-peak projekcija |
127
+ | `/budget [iznos]` | Prikaži ili postavi budžet sesije |
128
+ | `/new` | Nova sesija |
129
+ | `/fork` | Nova sesija sa kopijom trenutne istorije |
130
+ | `/resume [id]` | Nastavi poslednju (ili navedenu) sesiju |
131
+ | `/paste [poruka]` | Pošalji sliku iz Windows clipboard-a agentu |
132
+ | `/clear` | Očisti ekran |
133
+ | `/help` | Ova lista |
134
+ | `/exit` | Izlaz |
135
+
136
+ Pritisni **ESC** u bilo kom trenutku tokom poteza da ga prekineš.
137
+
138
+ ## Arhitektura
139
+
140
+ ```
141
+ tandem (bez argumenata) ─┬─> interaktivni REPL ─┬─> jedan potez: agent petlja (alati)
142
+ │ └─> /plan: planner → worker(i) → reviewer
143
+ tandem "task" ────────┘ (single-shot, ista agent petlja, za skripte/CI)
144
+ ```
145
+
146
+ - `src/deepseek/` — tanak klijent za DeepSeek-ov OpenAI-kompatibilan API
147
+ (streaming + non-streaming chat completions, vision, web search preko
148
+ Responses API-ja). Vidi [`docs/api-notes.md`](./docs/api-notes.md) za
149
+ ponašanje API-ja protiv kog je ovo napravljeno, verifikovano uživo, ne
150
+ pretpostavljeno.
151
+ - `src/agent/` — tool-calling petlja, implementacije alata, perzistencija
152
+ sesije, praćenje usage/troška.
153
+ - `src/orchestrator/` — planner/worker/reviewer, generisanje repo mape,
154
+ cache-aware konstrukcija stabilnog prefiksa.
155
+ - `src/repl/` — slash komande, runtime konfiguracija, first-run wizard.
156
+ - `src/cli.tsx` — Ink terminalski UI i REPL/single-shot ulazne tačke.
157
+
158
+ ## Konfiguracija
159
+
160
+ Slojevito: **sesija** (komande u REPL-u) > **projekat**
161
+ (`.tandem/config.json` u trenutnom direktorijumu) > **globalno**
162
+ (`~/.tandem/config.json`).
163
+
164
+ ```json
165
+ {
166
+ "defaultModel": "deepseek-v4-pro",
167
+ "defaultReasoningEffort": "high",
168
+ "budgetUsd": 5,
169
+ "maxReviewLoops": 3
170
+ }
171
+ ```
172
+
173
+ API ključ se nikad ne čuva u ovim fajlovima — živi DPAPI-šifrovan na
174
+ Windows-u (ili u `DEEPSEEK_API_KEY` env promenljivoj, koja ima prioritet,
175
+ za CI upotrebu).
176
+
177
+ ## Razvoj
178
+
179
+ Vidi [CONTRIBUTING.sr.md](./CONTRIBUTING.sr.md).
180
+
181
+ ```bash
182
+ pnpm install
183
+ pnpm typecheck
184
+ pnpm dev "neki zadatak"
185
+ ```
186
+
187
+ ## Disclaimer
188
+
189
+ Ovo je nezavisan projekat koji vodi zajednica. Nije povezan sa DeepSeek-om,
190
+ niti od njega podržan ili sponzorisan.
191
+
192
+ ## Licenca
193
+
194
+ [MIT](./LICENSE)
@@ -0,0 +1,26 @@
1
+ import { execFile } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ const execFileAsync = promisify(execFile);
4
+ /**
5
+ * Samo Windows za sada — Linux/macOS clipboard pristup ide u good-first-issues
6
+ * (xclip/pngpaste), u duhu "Windows first-class" principa iz plana.
7
+ */
8
+ export async function saveClipboardImage(destPath) {
9
+ if (process.platform !== "win32") {
10
+ throw new Error("Clipboard paste slike je trenutno podržan samo na Windows-u.");
11
+ }
12
+ const escapedPath = destPath.replace(/'/g, "''");
13
+ const script = `
14
+ Add-Type -AssemblyName System.Windows.Forms
15
+ Add-Type -AssemblyName System.Drawing
16
+ if ([System.Windows.Forms.Clipboard]::ContainsImage()) {
17
+ $img = [System.Windows.Forms.Clipboard]::GetImage()
18
+ $img.Save('${escapedPath}', [System.Drawing.Imaging.ImageFormat]::Png)
19
+ Write-Output "OK"
20
+ } else {
21
+ Write-Output "NO_IMAGE"
22
+ }`;
23
+ const { stdout } = await execFileAsync("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script]);
24
+ return stdout.trim() === "OK";
25
+ }
26
+ //# sourceMappingURL=clipboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clipboard.js","sourceRoot":"","sources":["../../src/agent/clipboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,QAAgB;IACvD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;IAClF,CAAC;IAED,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG;;;;;eAKF,WAAW;;;;EAIxB,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,gBAAgB,EAAE,CAAC,YAAY,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;IAChH,OAAO,MAAM,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC;AAChC,CAAC"}
@@ -0,0 +1,157 @@
1
+ import { streamChatCompletion } from "../deepseek/client.js";
2
+ import { findTool, toolSpecs } from "./tools/index.js";
3
+ import { appendSessionMessage } from "./session.js";
4
+ function isAbortError(err) {
5
+ return err instanceof Error && err.name === "AbortError";
6
+ }
7
+ /**
8
+ * `messages` mora već sadržati system + početni user zahtev (i istoriju ako
9
+ * se nastavlja sesija) — pozivalac je odgovoran da TE poruke upiše u sesiju
10
+ * pre poziva. Petlja perzistuje samo poruke koje sama generiše (assistant/tool).
11
+ */
12
+ export async function* runAgentLoop(messages, opts) {
13
+ const ctx = { cwd: opts.cwd, env: opts.env, usage: opts.usage, ...(opts.signal ? { signal: opts.signal } : {}) };
14
+ const maxIterations = opts.maxIterations ?? 25;
15
+ for (let iteration = 0; iteration < maxIterations; iteration++) {
16
+ if (opts.signal?.aborted) {
17
+ yield { type: "interrupted" };
18
+ return;
19
+ }
20
+ if (opts.budgetUsd !== undefined) {
21
+ const spent = opts.usage.estimatedCostUsd();
22
+ if (spent >= opts.budgetUsd) {
23
+ yield { type: "budget_exceeded", spentUsd: spent, budgetUsd: opts.budgetUsd };
24
+ return;
25
+ }
26
+ }
27
+ let reasoning = "";
28
+ let content = "";
29
+ const toolCallBuf = new Map();
30
+ try {
31
+ for await (const ev of streamChatCompletion(opts.env, {
32
+ model: opts.model,
33
+ messages,
34
+ tools: toolSpecs,
35
+ ...(opts.thinking !== undefined ? { thinking: opts.thinking } : {}),
36
+ ...(opts.signal ? { signal: opts.signal } : {}),
37
+ })) {
38
+ switch (ev.type) {
39
+ case "reasoning_delta":
40
+ reasoning += ev.delta;
41
+ yield { type: "reasoning_delta", delta: ev.delta };
42
+ break;
43
+ case "content_delta":
44
+ content += ev.delta;
45
+ yield { type: "content_delta", delta: ev.delta };
46
+ break;
47
+ case "tool_call_delta": {
48
+ const buf = toolCallBuf.get(ev.index) ?? { args: "" };
49
+ if (ev.id)
50
+ buf.id = ev.id;
51
+ if (ev.name)
52
+ buf.name = ev.name;
53
+ if (ev.argumentsDelta)
54
+ buf.args += ev.argumentsDelta;
55
+ toolCallBuf.set(ev.index, buf);
56
+ break;
57
+ }
58
+ case "usage":
59
+ opts.usage.add(opts.model, ev.usage);
60
+ yield { type: "usage", usage: ev.usage };
61
+ break;
62
+ case "done":
63
+ break;
64
+ }
65
+ }
66
+ }
67
+ catch (err) {
68
+ if (!isAbortError(err))
69
+ throw err;
70
+ // Prekinuto usred streama — sačuvaj šta god je stiglo do sad kao poruku,
71
+ // ali bez tool_calls (nepotpuni argumenti se ne mogu pouzdano izvršiti).
72
+ if (content || reasoning) {
73
+ const partialMessage = {
74
+ role: "assistant",
75
+ content: content || null,
76
+ ...(reasoning ? { reasoningContent: reasoning } : {}),
77
+ };
78
+ messages.push(partialMessage);
79
+ await appendSessionMessage(opts.session, partialMessage);
80
+ }
81
+ yield { type: "interrupted" };
82
+ return;
83
+ }
84
+ const toolCalls = [...toolCallBuf.entries()]
85
+ .sort(([a], [b]) => a - b)
86
+ .map(([, v]) => ({
87
+ id: v.id ?? "",
88
+ type: "function",
89
+ function: { name: v.name ?? "", arguments: v.args },
90
+ }));
91
+ // `tools` se šalje na SVAKI poziv u ovoj petlji, pa dokumentacija traži
92
+ // da se reasoning_content svakog prethodnog poteza vrati — ne samo onih
93
+ // koji su zvali alat (inače dokumentovano 400, videti docs/api-notes.md #2).
94
+ const assistantMessage = {
95
+ role: "assistant",
96
+ content: content || null,
97
+ ...(reasoning ? { reasoningContent: reasoning } : {}),
98
+ ...(toolCalls.length > 0 ? { toolCalls } : {}),
99
+ };
100
+ messages.push(assistantMessage);
101
+ await appendSessionMessage(opts.session, assistantMessage);
102
+ if (toolCalls.length === 0) {
103
+ yield { type: "final", content };
104
+ return;
105
+ }
106
+ for (const call of toolCalls) {
107
+ if (opts.signal?.aborted) {
108
+ yield { type: "interrupted" };
109
+ return;
110
+ }
111
+ let args = {};
112
+ try {
113
+ args = JSON.parse(call.function.arguments || "{}");
114
+ }
115
+ catch {
116
+ // Ostaje {} — alat će prijaviti nedostajuće/neispravne argumente.
117
+ }
118
+ const tool = findTool(call.function.name);
119
+ if (!tool) {
120
+ const toolMsg = {
121
+ role: "tool",
122
+ toolCallId: call.id,
123
+ content: `Nepoznat alat: ${call.function.name}`,
124
+ };
125
+ messages.push(toolMsg);
126
+ await appendSessionMessage(opts.session, toolMsg);
127
+ continue;
128
+ }
129
+ yield { type: "tool_call_start", id: call.id, name: tool.name, args };
130
+ if (tool.isDestructive(args)) {
131
+ const approved = await opts.approve(tool.name, args);
132
+ if (!approved) {
133
+ yield { type: "tool_call_denied", id: call.id, name: tool.name };
134
+ const toolMsg = {
135
+ role: "tool",
136
+ toolCallId: call.id,
137
+ content: "Korisnik je odbio izvršavanje ovog alata.",
138
+ };
139
+ messages.push(toolMsg);
140
+ await appendSessionMessage(opts.session, toolMsg);
141
+ continue;
142
+ }
143
+ }
144
+ const result = await tool.execute(args, ctx);
145
+ if (opts.signal?.aborted) {
146
+ yield { type: "interrupted" };
147
+ return;
148
+ }
149
+ yield { type: "tool_call_result", id: call.id, name: tool.name, result };
150
+ const toolMsg = { role: "tool", toolCallId: call.id, content: result.output };
151
+ messages.push(toolMsg);
152
+ await appendSessionMessage(opts.session, toolMsg);
153
+ }
154
+ }
155
+ yield { type: "max_iterations_reached" };
156
+ }
157
+ //# sourceMappingURL=loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.js","sourceRoot":"","sources":["../../src/agent/loop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export const PRICING = {
2
+ "deepseek-v4-flash": { inputPerMillion: 0.22, outputPerMillion: 0.66, cacheHitInputPerMillion: 0.007 },
3
+ "deepseek-v4-pro": { inputPerMillion: 0.66, outputPerMillion: 1.98, cacheHitInputPerMillion: 0.022 },
4
+ };
5
+ const PEAK_WINDOWS_UTC = [
6
+ [1, 4],
7
+ [6, 10],
8
+ ];
9
+ export function isPeakHour(date) {
10
+ const hour = date.getUTCHours();
11
+ return PEAK_WINDOWS_UTC.some(([start, end]) => hour >= start && hour < end);
12
+ }
13
+ export function estimateCallCost(model, usage, isPeak) {
14
+ const p = PRICING[model];
15
+ const peakMultiplier = isPeak ? 2 : 1;
16
+ const inputCost = (usage.promptCacheMissTokens / 1_000_000) * p.inputPerMillion * peakMultiplier +
17
+ (usage.promptCacheHitTokens / 1_000_000) * p.cacheHitInputPerMillion * peakMultiplier;
18
+ const outputCost = (usage.completionTokens / 1_000_000) * p.outputPerMillion * peakMultiplier;
19
+ return inputCost + outputCost;
20
+ }
21
+ //# sourceMappingURL=pricing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing.js","sourceRoot":"","sources":["../../src/agent/pricing.ts"],"names":[],"mappings":"AAUA,MAAM,CAAC,MAAM,OAAO,GAAkE;IACpF,mBAAmB,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,uBAAuB,EAAE,KAAK,EAAE;IACtG,iBAAiB,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,uBAAuB,EAAE,KAAK,EAAE;CACrG,CAAC;AAEF,MAAM,gBAAgB,GAA4B;IAChD,CAAC,CAAC,EAAE,CAAC,CAAC;IACN,CAAC,CAAC,EAAE,EAAE,CAAC;CACR,CAAC;AAEF,MAAM,UAAU,UAAU,CAAC,IAAU;IACnC,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAChC,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,KAAK,IAAI,IAAI,GAAG,GAAG,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,KAA2B,EAC3B,KAAgG,EAChG,MAAe;IAEf,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IACzB,MAAM,cAAc,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,SAAS,GACb,CAAC,KAAK,CAAC,qBAAqB,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,eAAe,GAAG,cAAc;QAC9E,CAAC,KAAK,CAAC,oBAAoB,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,uBAAuB,GAAG,cAAc,CAAC;IACxF,MAAM,UAAU,GAAG,CAAC,KAAK,CAAC,gBAAgB,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,gBAAgB,GAAG,cAAc,CAAC;IAC9F,OAAO,SAAS,GAAG,UAAU,CAAC;AAChC,CAAC"}