@manishbht/helpcode 0.2.2
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/LICENSE +21 -0
- package/README.md +186 -0
- package/dist/bin/helpcode.d.ts +5 -0
- package/dist/bin/helpcode.js +10 -0
- package/dist/bin/helpcode.js.map +1 -0
- package/dist/src/commands/apply.d.ts +15 -0
- package/dist/src/commands/apply.js +195 -0
- package/dist/src/commands/apply.js.map +1 -0
- package/dist/src/commands/ask.d.ts +12 -0
- package/dist/src/commands/ask.js +93 -0
- package/dist/src/commands/ask.js.map +1 -0
- package/dist/src/commands/init.d.ts +13 -0
- package/dist/src/commands/init.js +91 -0
- package/dist/src/commands/init.js.map +1 -0
- package/dist/src/commands/reset.d.ts +8 -0
- package/dist/src/commands/reset.js +19 -0
- package/dist/src/commands/reset.js.map +1 -0
- package/dist/src/commands/run.d.ts +15 -0
- package/dist/src/commands/run.js +109 -0
- package/dist/src/commands/run.js.map +1 -0
- package/dist/src/commands/status.d.ts +4 -0
- package/dist/src/commands/status.js +53 -0
- package/dist/src/commands/status.js.map +1 -0
- package/dist/src/core/llmSelector.d.ts +65 -0
- package/dist/src/core/llmSelector.js +134 -0
- package/dist/src/core/llmSelector.js.map +1 -0
- package/dist/src/core/ollama.d.ts +43 -0
- package/dist/src/core/ollama.js +128 -0
- package/dist/src/core/ollama.js.map +1 -0
- package/dist/src/core/parser.d.ts +78 -0
- package/dist/src/core/parser.js +273 -0
- package/dist/src/core/parser.js.map +1 -0
- package/dist/src/core/patcher.d.ts +31 -0
- package/dist/src/core/patcher.js +128 -0
- package/dist/src/core/patcher.js.map +1 -0
- package/dist/src/core/project.d.ts +26 -0
- package/dist/src/core/project.js +199 -0
- package/dist/src/core/project.js.map +1 -0
- package/dist/src/core/prompt.d.ts +19 -0
- package/dist/src/core/prompt.js +121 -0
- package/dist/src/core/prompt.js.map +1 -0
- package/dist/src/core/selector.d.ts +46 -0
- package/dist/src/core/selector.js +193 -0
- package/dist/src/core/selector.js.map +1 -0
- package/dist/src/core/state.d.ts +11 -0
- package/dist/src/core/state.js +63 -0
- package/dist/src/core/state.js.map +1 -0
- package/dist/src/core/tools.d.ts +32 -0
- package/dist/src/core/tools.js +67 -0
- package/dist/src/core/tools.js.map +1 -0
- package/dist/src/core/triage.d.ts +37 -0
- package/dist/src/core/triage.js +69 -0
- package/dist/src/core/triage.js.map +1 -0
- package/dist/src/index.d.ts +12 -0
- package/dist/src/index.js +120 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/lib/compress.d.ts +14 -0
- package/dist/src/lib/compress.js +35 -0
- package/dist/src/lib/compress.js.map +1 -0
- package/dist/src/lib/errors.d.ts +25 -0
- package/dist/src/lib/errors.js +32 -0
- package/dist/src/lib/errors.js.map +1 -0
- package/dist/src/lib/git.d.ts +7 -0
- package/dist/src/lib/git.js +45 -0
- package/dist/src/lib/git.js.map +1 -0
- package/dist/src/lib/runclass.d.ts +24 -0
- package/dist/src/lib/runclass.js +66 -0
- package/dist/src/lib/runclass.js.map +1 -0
- package/dist/src/lib/ui.d.ts +41 -0
- package/dist/src/lib/ui.js +92 -0
- package/dist/src/lib/ui.js.map +1 -0
- package/dist/src/types.d.ts +70 -0
- package/dist/src/types.js +7 -0
- package/dist/src/types.js.map +1 -0
- package/package.json +53 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 helpcode 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
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# helpcode
|
|
2
|
+
|
|
3
|
+
> A local agent that makes Claude.ai conversations efficient enough to ship real projects on a Pro subscription.
|
|
4
|
+
|
|
5
|
+
[](https://github.com/merolaagi/helpcode/actions/workflows/ci.yml)
|
|
6
|
+
[](https://www.npmjs.com/package/helpcode)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
[](https://nodejs.org)
|
|
9
|
+
|
|
10
|
+
helpcode is a small local CLI for developers who use Claude.ai to write code. It does the mechanical work of an AI coding loop — selecting the right files, running tests, applying diffs, capturing errors — so the conversation turns you spend on Claude get used for actual thinking.
|
|
11
|
+
|
|
12
|
+
**It does not call Claude.** You stay in Claude.ai, copy-paste with it as normal, and helpcode handles everything around that conversation. Optionally, it uses a **local model on your own machine** (via [Ollama](https://ollama.com)) to do the cheap reasoning — like working out which files matter for a task — so even that doesn't cost you a Claude turn.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Why this exists
|
|
17
|
+
|
|
18
|
+
A year ago, you could build a real piece of software in a day or two with Claude Code. The tool was new, the usage envelope was generous, and the iteration loop was fast.
|
|
19
|
+
|
|
20
|
+
Today, Claude Code is significantly better — and significantly more in demand. Per-task pricing is fair for what you get, but at the $20/month Pro tier, a few iterations on a real codebase can consume more budget than a casual developer can sustain. Meanwhile, every routine "did the test pass?" or "which files are even relevant?" step burns frontier-model effort on work that doesn't need a frontier model.
|
|
21
|
+
|
|
22
|
+
helpcode addresses both:
|
|
23
|
+
|
|
24
|
+
- **For the developer:** each Claude conversation does more, because helpcode compresses context, structures prompts, and parses replies. One turn produces real progress instead of three turns of setup.
|
|
25
|
+
- **For energy and cost:** routine plumbing runs locally — on a small model on your own hardware, or as plain deterministic code — instead of in a datacenter. Claude is reserved for actual reasoning. The right tool for the right job.
|
|
26
|
+
|
|
27
|
+
This is the **two-layer model**: cheap local intelligence for the plumbing, expensive remote intelligence (Claude) for the thinking.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## What it does
|
|
32
|
+
|
|
33
|
+
Six commands. No daemons, no watchers, no background processes.
|
|
34
|
+
|
|
35
|
+
| Command | What it does |
|
|
36
|
+
|---|---|
|
|
37
|
+
| `helpcode init` | Detect your project — language, framework, test runner, and any local Ollama model — and write `.helpcode/project.json` |
|
|
38
|
+
| `helpcode ask "..."` | Compose a structured prompt for Claude.ai. Picks the relevant files (with a local model if available), includes last test output, and a response-format spec |
|
|
39
|
+
| `helpcode apply` | Paste Claude's reply; helpcode parses it, shows the planned changes, applies the diffs, runs tests |
|
|
40
|
+
| `helpcode run "..."` | Run any shell command, get the output in compact form (perfect for pasting back to Claude) |
|
|
41
|
+
| `helpcode status` | What does helpcode think the current state is? |
|
|
42
|
+
| `helpcode reset` | Clear state and start fresh (your code is never touched) |
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## The local-model layer (optional)
|
|
47
|
+
|
|
48
|
+
If you have [Ollama](https://ollama.com) installed with a coding model pulled (e.g. `qwen2.5-coder`), `helpcode init` detects it automatically and `helpcode ask` will use it to **reason about which files are relevant** to your task — not just keyword-match them.
|
|
49
|
+
|
|
50
|
+
The difference, on a real task:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
$ helpcode ask "add a glucose variability calculation" --explain-selection
|
|
54
|
+
selecting files (local model: qwen2.5-coder:7b)...
|
|
55
|
+
✓ selected 2 file(s) via local model
|
|
56
|
+
src/analyze.py — contains the time-in-range function a variability calc would extend
|
|
57
|
+
tests/test_analyze.py — where the new calculation's tests belong
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
A plain keyword search would match files that literally contain "glucose." A local model understands that a *variability* calculation naturally extends the *time-in-range* function already in `analyze.py` — reasoning the keyword approach can't do.
|
|
61
|
+
|
|
62
|
+
**It never gets in the way.** If Ollama isn't installed, isn't running, times out, or returns nothing useful, helpcode silently falls back to a fast keyword heuristic. The local model is a free upgrade when present, never a dependency.
|
|
63
|
+
|
|
64
|
+
Useful flags:
|
|
65
|
+
- `--no-llm` — force the keyword heuristic for this run
|
|
66
|
+
- `--explain-selection` — show why each file was chosen
|
|
67
|
+
|
|
68
|
+
Configure the model in `.helpcode/project.json`:
|
|
69
|
+
|
|
70
|
+
```jsonc
|
|
71
|
+
"ollama": {
|
|
72
|
+
"enabled": true,
|
|
73
|
+
"model": "qwen2.5-coder:7b", // or 14b / deepseek-coder-v2 for more reasoning
|
|
74
|
+
"host": "http://localhost:11434",
|
|
75
|
+
"timeoutMs": 20000
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Install
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
npm install -g helpcode
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Requires Node.js 20 or later. Tested on macOS, Linux, and Windows.
|
|
88
|
+
|
|
89
|
+
You don't need an API key. You don't need to sign up for anything. helpcode never calls Claude or any other remote AI service — it just helps you talk to Claude.ai more efficiently. The only optional integration is a local Ollama server on your own machine.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## A typical session
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# In your project, once:
|
|
97
|
+
$ helpcode init
|
|
98
|
+
✓ Initialised .helpcode/project.json
|
|
99
|
+
|
|
100
|
+
Detected:
|
|
101
|
+
language: python
|
|
102
|
+
framework: Flask
|
|
103
|
+
source dirs: app, tests
|
|
104
|
+
test cmd: pytest -q --tb=short
|
|
105
|
+
ollama: enabled, model: qwen2.5-coder:7b
|
|
106
|
+
|
|
107
|
+
# Start a task:
|
|
108
|
+
$ helpcode ask "fix the login bug where uppercase emails fail"
|
|
109
|
+
selecting files (local model: qwen2.5-coder:7b)...
|
|
110
|
+
✓ selected 2 file(s) via local model
|
|
111
|
+
|
|
112
|
+
────────────────────────────────────────────────────────────
|
|
113
|
+
COPY EVERYTHING BELOW INTO CLAUDE.AI
|
|
114
|
+
────────────────────────────────────────────────────────────
|
|
115
|
+
## Project context
|
|
116
|
+
- Language: python
|
|
117
|
+
- Framework: Flask
|
|
118
|
+
|
|
119
|
+
## Files (2)
|
|
120
|
+
### `app/auth.py`
|
|
121
|
+
... (relevant code)
|
|
122
|
+
|
|
123
|
+
## My task
|
|
124
|
+
fix the login bug where uppercase emails fail
|
|
125
|
+
|
|
126
|
+
## Please respond in this format
|
|
127
|
+
...
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
You paste that into Claude.ai. Claude replies in the structured format. You paste the reply back:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
$ helpcode apply
|
|
134
|
+
# (paste Claude's reply, press Ctrl-D)
|
|
135
|
+
|
|
136
|
+
Plan:
|
|
137
|
+
Lowercase the email before lookup in USERS.
|
|
138
|
+
|
|
139
|
+
Files to change:
|
|
140
|
+
• app/auth.py
|
|
141
|
+
|
|
142
|
+
Apply these changes? [y/N] y
|
|
143
|
+
✓ patched app/auth.py
|
|
144
|
+
running: pytest tests/test_auth.py -v
|
|
145
|
+
Exit: 0 Time: 0.32s
|
|
146
|
+
3 passed in 0.32s
|
|
147
|
+
|
|
148
|
+
✓ Tests pass. Ready to commit when you are.
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Each turn with Claude does real work — no re-pasting the test output, the imports, and your Python version every time.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## What it is not
|
|
156
|
+
|
|
157
|
+
- **Not an agent that calls Claude.** No API key, no surprise costs. You stay in the loop.
|
|
158
|
+
- **Not a replacement for Claude Code** — which is excellent at autonomous, multi-step work. helpcode is for people who'd rather stay inside their Pro subscription.
|
|
159
|
+
- **Not a sandbox.** It runs your code with your normal permissions. Don't run code you don't trust.
|
|
160
|
+
- **Not multi-provider orchestration — yet.** Routing across several models with budget caps is the v0.3 horizon. See [`docs/ROADMAP.md`](docs/ROADMAP.md).
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Privacy
|
|
165
|
+
|
|
166
|
+
Everything stays on your machine. helpcode makes no network calls except to npm (once, during install) and — if you enable it — to a local Ollama server on `localhost`. It never sends your code to any remote service. Read [`docs/PRIVACY.md`](docs/PRIVACY.md) for the full breakdown.
|
|
167
|
+
|
|
168
|
+
The only thing that leaves your machine is whatever **you** paste into Claude.ai, which is your existing relationship with Anthropic.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Contributing
|
|
173
|
+
|
|
174
|
+
Yes please. helpcode is small enough that the entire CLI is readable in an evening, and the architecture is explicitly designed for community evolution. Start with:
|
|
175
|
+
|
|
176
|
+
- [`CONTRIBUTING.md`](CONTRIBUTING.md) — how to set up and where to start
|
|
177
|
+
- [`ARCHITECTURE.md`](ARCHITECTURE.md) — the design doc this is built from
|
|
178
|
+
- [`docs/ROADMAP.md`](docs/ROADMAP.md) — what's planned and why
|
|
179
|
+
|
|
180
|
+
Good first issues are labelled [`good first issue`](https://github.com/merolaagi/helpcode/issues?q=label%3A%22good+first+issue%22) on the issue tracker.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## License
|
|
185
|
+
|
|
186
|
+
MIT. See [`LICENSE`](LICENSE).
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Entry shim for the published `helpcode` command.
|
|
4
|
+
*/
|
|
5
|
+
import { run } from '../src/index.js';
|
|
6
|
+
run(process.argv.slice(2)).then(code => process.exit(code), err => {
|
|
7
|
+
console.error(err);
|
|
8
|
+
process.exit(1);
|
|
9
|
+
});
|
|
10
|
+
//# sourceMappingURL=helpcode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpcode.js","sourceRoot":"","sources":["../../bin/helpcode.ts"],"names":[],"mappings":";AACA;;GAEG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAEtC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAC7B,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAC1B,GAAG,CAAC,EAAE;IACJ,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CACF,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `helpcode apply` — parse Claude's reply (from stdin), apply diffs,
|
|
3
|
+
* run the test command. Updates state with the verdict.
|
|
4
|
+
*
|
|
5
|
+
* v0.1 is intentionally conservative:
|
|
6
|
+
* - Shows planned changes before applying
|
|
7
|
+
* - Asks for confirmation (unless --yes)
|
|
8
|
+
* - On any diff failure, stops and reports — does NOT roll back yet
|
|
9
|
+
* (v0.2 will add rollback via core/rollback.ts)
|
|
10
|
+
*/
|
|
11
|
+
export interface ApplyOptions {
|
|
12
|
+
yes?: boolean;
|
|
13
|
+
dryRun?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function handleApply(opts?: ApplyOptions): Promise<number>;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `helpcode apply` — parse Claude's reply (from stdin), apply diffs,
|
|
3
|
+
* run the test command. Updates state with the verdict.
|
|
4
|
+
*
|
|
5
|
+
* v0.1 is intentionally conservative:
|
|
6
|
+
* - Shows planned changes before applying
|
|
7
|
+
* - Asks for confirmation (unless --yes)
|
|
8
|
+
* - On any diff failure, stops and reports — does NOT roll back yet
|
|
9
|
+
* (v0.2 will add rollback via core/rollback.ts)
|
|
10
|
+
*/
|
|
11
|
+
import * as fs from 'fs';
|
|
12
|
+
import * as path from 'path';
|
|
13
|
+
import { loadState, saveState } from '../core/state.js';
|
|
14
|
+
import { loadProjectConfig } from '../core/project.js';
|
|
15
|
+
import { parseClaudeResponse, validateParsedResponse } from '../core/parser.js';
|
|
16
|
+
import { applyLinePatch } from '../core/patcher.js';
|
|
17
|
+
import { runShellCommand } from '../core/tools.js';
|
|
18
|
+
import { classifyRunFailure } from '../lib/runclass.js';
|
|
19
|
+
import { truncateLines, extractTraceback } from '../lib/compress.js';
|
|
20
|
+
import { readStdin, confirm, c, log } from '../lib/ui.js';
|
|
21
|
+
import { HelpcodeError } from '../lib/errors.js';
|
|
22
|
+
export async function handleApply(opts = {}) {
|
|
23
|
+
const state = loadState();
|
|
24
|
+
if (!state.currentTask) {
|
|
25
|
+
log.err('No current task. Run `helpcode ask "<task>"` first.');
|
|
26
|
+
return 1;
|
|
27
|
+
}
|
|
28
|
+
const task = state.currentTask;
|
|
29
|
+
// Get Claude's response. Prefer stdin; fall back to .helpcode/response.txt.
|
|
30
|
+
const raw = await getResponseText();
|
|
31
|
+
if (!raw.trim()) {
|
|
32
|
+
log.err('No input received.');
|
|
33
|
+
log.dim('Paste Claude\'s reply and press Ctrl-D, or save it to .helpcode/response.txt first.');
|
|
34
|
+
return 1;
|
|
35
|
+
}
|
|
36
|
+
task.lastResponseRaw = raw;
|
|
37
|
+
const parsed = parseClaudeResponse(raw);
|
|
38
|
+
if (parsed.parseWarning) {
|
|
39
|
+
log.warn('Claude\'s reply doesn\'t match the expected format.');
|
|
40
|
+
log.dim('Helpcode expects sections like `## PLAN`, `## DIFF: <file>`, `## TEST`.');
|
|
41
|
+
log.dim('Save the reply, fix the format, and re-run `helpcode apply`.');
|
|
42
|
+
task.status = 'failed';
|
|
43
|
+
saveState(state);
|
|
44
|
+
return 1;
|
|
45
|
+
}
|
|
46
|
+
if (parsed.repairsApplied) {
|
|
47
|
+
log.dim('(auto-repaired copy-paste corruption in Claude\'s reply — review the plan below carefully)');
|
|
48
|
+
}
|
|
49
|
+
const issues = validateParsedResponse(parsed);
|
|
50
|
+
if (issues.length > 0) {
|
|
51
|
+
log.err('Response failed validation:');
|
|
52
|
+
for (const i of issues)
|
|
53
|
+
log.err(' ' + i);
|
|
54
|
+
task.status = 'failed';
|
|
55
|
+
saveState(state);
|
|
56
|
+
return 1;
|
|
57
|
+
}
|
|
58
|
+
showPlan(parsed);
|
|
59
|
+
if (opts.dryRun) {
|
|
60
|
+
log.dim('--dry-run: not applying anything.');
|
|
61
|
+
return 0;
|
|
62
|
+
}
|
|
63
|
+
if (!opts.yes) {
|
|
64
|
+
const ok = await confirm('Apply these changes?');
|
|
65
|
+
if (!ok) {
|
|
66
|
+
log.dim('Cancelled.');
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
task.status = 'applying';
|
|
71
|
+
saveState(state);
|
|
72
|
+
const applied = [];
|
|
73
|
+
let allOk = true;
|
|
74
|
+
for (const diff of parsed.diffs) {
|
|
75
|
+
try {
|
|
76
|
+
const r = applyLinePatch(diff.filepath, diff.patchLines);
|
|
77
|
+
applied.push({
|
|
78
|
+
filepath: r.filepath,
|
|
79
|
+
hunks: r.hunksApplied,
|
|
80
|
+
ok: true,
|
|
81
|
+
created: r.created,
|
|
82
|
+
});
|
|
83
|
+
log.ok(`patched ${r.filepath}${r.created ? ' (new file)' : ''}`);
|
|
84
|
+
}
|
|
85
|
+
catch (e) {
|
|
86
|
+
const msg = e instanceof HelpcodeError ? e.message : e.message;
|
|
87
|
+
const hint = e instanceof HelpcodeError ? e.hint : '';
|
|
88
|
+
log.err(`failed: ${diff.filepath} — ${msg}`);
|
|
89
|
+
if (hint)
|
|
90
|
+
log.dim(' ' + hint);
|
|
91
|
+
applied.push({
|
|
92
|
+
filepath: diff.filepath,
|
|
93
|
+
hunks: 0,
|
|
94
|
+
ok: false,
|
|
95
|
+
created: false,
|
|
96
|
+
});
|
|
97
|
+
allOk = false;
|
|
98
|
+
break; // stop on first failure for v0.1
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
task.lastDiffsApplied = applied;
|
|
102
|
+
if (!allOk) {
|
|
103
|
+
task.status = 'failed';
|
|
104
|
+
saveState(state);
|
|
105
|
+
log.warn('Some patches failed. Files written before the failure are still on disk.');
|
|
106
|
+
log.dim('v0.2 will add automatic rollback. For now, use `git checkout -- <file>` or your editor\'s undo.');
|
|
107
|
+
return 1;
|
|
108
|
+
}
|
|
109
|
+
// Run the test command Claude suggested, or the project default
|
|
110
|
+
const config = loadProjectConfig();
|
|
111
|
+
const testCmd = parsed.testCommand ?? config.testCommand;
|
|
112
|
+
if (!testCmd) {
|
|
113
|
+
log.dim('No test command available — skipping test run.');
|
|
114
|
+
task.status = 'resolved';
|
|
115
|
+
saveState(state);
|
|
116
|
+
log.ok('Done.');
|
|
117
|
+
return 0;
|
|
118
|
+
}
|
|
119
|
+
task.status = 'testing';
|
|
120
|
+
saveState(state);
|
|
121
|
+
log.dim(`running: ${testCmd}`);
|
|
122
|
+
const result = await runShellCommand(testCmd, { timeoutSecs: 120 });
|
|
123
|
+
const testReport = formatTestReport(testCmd, result);
|
|
124
|
+
task.lastTestOutput = testReport;
|
|
125
|
+
console.log();
|
|
126
|
+
console.log(testReport);
|
|
127
|
+
if (result.exitCode === 0) {
|
|
128
|
+
task.status = 'resolved';
|
|
129
|
+
saveState(state);
|
|
130
|
+
console.log();
|
|
131
|
+
log.ok('Tests pass. Ready to commit when you are.');
|
|
132
|
+
return 0;
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
task.status = 'failed';
|
|
136
|
+
saveState(state);
|
|
137
|
+
console.log();
|
|
138
|
+
const classification = classifyRunFailure(result);
|
|
139
|
+
if (classification.kind === 'test') {
|
|
140
|
+
log.warn(classification.message);
|
|
141
|
+
log.dim(classification.hint);
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
// setup or timeout: not a Claude problem
|
|
145
|
+
log.warn(classification.message);
|
|
146
|
+
if (classification.hint)
|
|
147
|
+
log.dim(classification.hint);
|
|
148
|
+
}
|
|
149
|
+
return result.exitCode;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async function getResponseText() {
|
|
153
|
+
// If stdin is a TTY and there's a saved response, prefer that
|
|
154
|
+
const savedPath = path.join('.helpcode', 'response.txt');
|
|
155
|
+
if (process.stdin.isTTY && fs.existsSync(savedPath)) {
|
|
156
|
+
log.dim(`using saved response from ${savedPath}`);
|
|
157
|
+
return fs.readFileSync(savedPath, 'utf-8');
|
|
158
|
+
}
|
|
159
|
+
return readStdin();
|
|
160
|
+
}
|
|
161
|
+
function showPlan(parsed) {
|
|
162
|
+
console.log();
|
|
163
|
+
console.log(c.bold('Plan:'));
|
|
164
|
+
console.log(' ' + parsed.plan.split('\n').join('\n '));
|
|
165
|
+
console.log();
|
|
166
|
+
console.log(c.bold('Files to change:'));
|
|
167
|
+
for (const d of parsed.diffs) {
|
|
168
|
+
console.log(` ${c.cyan('•')} ${d.filepath}`);
|
|
169
|
+
}
|
|
170
|
+
if (parsed.testCommand) {
|
|
171
|
+
console.log();
|
|
172
|
+
console.log(c.bold('Test command:'));
|
|
173
|
+
console.log(` ${parsed.testCommand}`);
|
|
174
|
+
}
|
|
175
|
+
if (parsed.notes) {
|
|
176
|
+
console.log();
|
|
177
|
+
console.log(c.bold('Notes from Claude:'));
|
|
178
|
+
console.log(' ' + parsed.notes.split('\n').join('\n '));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function formatTestReport(cmd, result) {
|
|
182
|
+
const parts = [];
|
|
183
|
+
parts.push(`$ ${cmd}`);
|
|
184
|
+
parts.push(`Exit: ${result.exitCode} Time: ${(result.durationMs / 1000).toFixed(2)}s`);
|
|
185
|
+
if (result.stdout.trim()) {
|
|
186
|
+
parts.push('--- stdout ---');
|
|
187
|
+
parts.push(truncateLines(result.stdout.trimEnd(), 40, 'stdout lines'));
|
|
188
|
+
}
|
|
189
|
+
if (result.stderr.trim()) {
|
|
190
|
+
parts.push('--- stderr ---');
|
|
191
|
+
parts.push(extractTraceback(result.stderr));
|
|
192
|
+
}
|
|
193
|
+
return parts.join('\n');
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=apply.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../../src/commands/apply.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `helpcode ask "<task>"` — assemble a structured prompt for Claude.ai
|
|
3
|
+
* based on the project state and selected files. Prints a paste block.
|
|
4
|
+
*/
|
|
5
|
+
export interface AskOptions {
|
|
6
|
+
files?: string[];
|
|
7
|
+
/** Force the heuristic selector even if Ollama is enabled. */
|
|
8
|
+
noLlm?: boolean;
|
|
9
|
+
/** Print the reason each file was selected. */
|
|
10
|
+
explainSelection?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function handleAsk(taskDescription: string, opts?: AskOptions): Promise<number>;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `helpcode ask "<task>"` — assemble a structured prompt for Claude.ai
|
|
3
|
+
* based on the project state and selected files. Prints a paste block.
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import { loadProjectConfig } from '../core/project.js';
|
|
8
|
+
import { loadState, saveState, createTask } from '../core/state.js';
|
|
9
|
+
import { selectFilesWithStrategy } from '../core/selector.js';
|
|
10
|
+
import { buildPrompt } from '../core/prompt.js';
|
|
11
|
+
import { printPasteBlock, log, c } from '../lib/ui.js';
|
|
12
|
+
const STATE_DIR = '.helpcode';
|
|
13
|
+
export async function handleAsk(taskDescription, opts = {}) {
|
|
14
|
+
if (!taskDescription || !taskDescription.trim()) {
|
|
15
|
+
log.err('Usage: helpcode ask "<task description>"');
|
|
16
|
+
return 1;
|
|
17
|
+
}
|
|
18
|
+
const config = loadProjectConfig();
|
|
19
|
+
const state = loadState();
|
|
20
|
+
// If there's no current task, or the user is starting fresh, create one
|
|
21
|
+
let task = state.currentTask;
|
|
22
|
+
if (!task || task.status === 'resolved' || task.status === 'failed') {
|
|
23
|
+
task = createTask(taskDescription);
|
|
24
|
+
state.currentTask = task;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
task.iterations += 1;
|
|
28
|
+
}
|
|
29
|
+
// Resolve files: explicit override, else LLM-or-heuristic strategy
|
|
30
|
+
let selectedFiles;
|
|
31
|
+
if (opts.files && opts.files.length > 0) {
|
|
32
|
+
selectedFiles = opts.files
|
|
33
|
+
.map(f => path.resolve(f))
|
|
34
|
+
.filter(f => {
|
|
35
|
+
if (!fs.existsSync(f)) {
|
|
36
|
+
log.warn(`File not found, skipping: ${f}`);
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
return true;
|
|
40
|
+
});
|
|
41
|
+
if (opts.explainSelection) {
|
|
42
|
+
for (const f of selectedFiles) {
|
|
43
|
+
log.dim(` ${path.relative(config.root, f)} — explicitly provided via --files`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
if (config.ollama?.enabled && !opts.noLlm) {
|
|
49
|
+
log.dim(`selecting files (local model: ${config.ollama.model})...`);
|
|
50
|
+
}
|
|
51
|
+
const result = await selectFilesWithStrategy(taskDescription, config, {
|
|
52
|
+
forceHeuristic: opts.noLlm,
|
|
53
|
+
});
|
|
54
|
+
selectedFiles = result.files.map(f => f.filepath);
|
|
55
|
+
if (result.strategy === 'llm') {
|
|
56
|
+
log.ok(`selected ${result.files.length} file(s) via local model`);
|
|
57
|
+
}
|
|
58
|
+
else if (result.fallbackReason) {
|
|
59
|
+
log.dim(`local-model selection unavailable (${result.fallbackReason}) — used keyword heuristic`);
|
|
60
|
+
}
|
|
61
|
+
if (opts.explainSelection) {
|
|
62
|
+
for (const f of result.files) {
|
|
63
|
+
log.dim(` ${path.relative(config.root, f.filepath)} — ${f.reason}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (selectedFiles.length === 0) {
|
|
68
|
+
log.warn('No relevant files found. The prompt will contain context only.');
|
|
69
|
+
log.dim('Tip: pass --files <paths> to include specific files.');
|
|
70
|
+
}
|
|
71
|
+
const prompt = buildPrompt({
|
|
72
|
+
taskDescription,
|
|
73
|
+
selectedFiles,
|
|
74
|
+
lastTestOutput: task.lastTestOutput,
|
|
75
|
+
config,
|
|
76
|
+
});
|
|
77
|
+
// Persist
|
|
78
|
+
task.lastPrompt = prompt;
|
|
79
|
+
task.status = 'awaiting_paste';
|
|
80
|
+
saveState(state);
|
|
81
|
+
// Also save the prompt to a file the user can re-copy from
|
|
82
|
+
const pendingPath = path.join(STATE_DIR, 'pending.txt');
|
|
83
|
+
fs.writeFileSync(pendingPath, prompt, 'utf-8');
|
|
84
|
+
printPasteBlock(prompt);
|
|
85
|
+
console.log();
|
|
86
|
+
log.dim(`(saved a copy at ${pendingPath})`);
|
|
87
|
+
log.dim(`(~${Math.round(prompt.length / 4)} tokens approx)`);
|
|
88
|
+
console.log();
|
|
89
|
+
console.log(`${c.bold('Next:')} paste this into Claude.ai, copy the reply, then run:`);
|
|
90
|
+
console.log(` ${c.cyan('helpcode apply')}`);
|
|
91
|
+
return 0;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=ask.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ask.js","sourceRoot":"","sources":["../../../src/commands/ask.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,cAAc,CAAC;AAEvD,MAAM,SAAS,GAAG,WAAW,CAAC;AAU9B,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,eAAuB,EAAE,OAAmB,EAAE;IAC5E,IAAI,CAAC,eAAe,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,EAAE,CAAC;QAChD,GAAG,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;QACpD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,MAAM,GAAG,iBAAiB,EAAE,CAAC;IACnC,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;IAE1B,wEAAwE;IACxE,IAAI,IAAI,GAAG,KAAK,CAAC,WAAW,CAAC;IAC7B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QACpE,IAAI,GAAG,UAAU,CAAC,eAAe,CAAC,CAAC;QACnC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC;IAC3B,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC;IACvB,CAAC;IAED,mEAAmE;IACnE,IAAI,aAAuB,CAAC;IAC5B,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxC,aAAa,GAAG,IAAI,CAAC,KAAK;aACvB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;aACzB,MAAM,CAAC,CAAC,CAAC,EAAE;YACV,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;gBACtB,GAAG,CAAC,IAAI,CAAC,6BAA6B,CAAC,EAAE,CAAC,CAAC;gBAC3C,OAAO,KAAK,CAAC;YACf,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;QACL,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC1B,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;gBAC9B,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,oCAAoC,CAAC,CAAC;YAClF,CAAC;QACH,CAAC;IACH,CAAC;SAAM,CAAC;QACN,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAC1C,GAAG,CAAC,GAAG,CAAC,iCAAiC,MAAM,CAAC,MAAM,CAAC,KAAK,MAAM,CAAC,CAAC;QACtE,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,uBAAuB,CAAC,eAAe,EAAE,MAAM,EAAE;YACpE,cAAc,EAAE,IAAI,CAAC,KAAK;SAC3B,CAAC,CAAC;QACH,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QAElD,IAAI,MAAM,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;YAC9B,GAAG,CAAC,EAAE,CAAC,YAAY,MAAM,CAAC,KAAK,CAAC,MAAM,0BAA0B,CAAC,CAAC;QACpE,CAAC;aAAM,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;YACjC,GAAG,CAAC,GAAG,CAAC,sCAAsC,MAAM,CAAC,cAAc,4BAA4B,CAAC,CAAC;QACnG,CAAC;QAED,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC1B,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBAC7B,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;YACvE,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,GAAG,CAAC,IAAI,CAAC,gEAAgE,CAAC,CAAC;QAC3E,GAAG,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC;IAClE,CAAC;IAED,MAAM,MAAM,GAAG,WAAW,CAAC;QACzB,eAAe;QACf,aAAa;QACb,cAAc,EAAE,IAAI,CAAC,cAAc;QACnC,MAAM;KACP,CAAC,CAAC;IAEH,UAAU;IACV,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC;IACzB,IAAI,CAAC,MAAM,GAAG,gBAAgB,CAAC;IAC/B,SAAS,CAAC,KAAK,CAAC,CAAC;IAEjB,2DAA2D;IAC3D,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IACxD,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAE/C,eAAe,CAAC,MAAM,CAAC,CAAC;IAExB,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,GAAG,CAAC,GAAG,CAAC,oBAAoB,WAAW,GAAG,CAAC,CAAC;IAC5C,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,iBAAiB,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,uDAAuD,CAAC,CAAC;IACvF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;IAC7C,OAAO,CAAC,CAAC;AACX,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `helpcode init` — detect the project, write .helpcode/project.json,
|
|
3
|
+
* make sure .helpcode/ is gitignored.
|
|
4
|
+
*/
|
|
5
|
+
export interface InitOptions {
|
|
6
|
+
force?: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Skip the Ollama liveness probe. Used by tests so they never do real
|
|
9
|
+
* network I/O. In normal use this is always false.
|
|
10
|
+
*/
|
|
11
|
+
skipOllamaDetection?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function handleInit(opts?: InitOptions): Promise<number>;
|