codehere 1.0.2 → 2.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -2
- package/README.md +89 -46
- package/bin/codehere.js +90 -0
- package/package.json +20 -64
- package/src/brain.js +186 -0
- package/src/commands.js +445 -0
- package/src/gemma.js +48 -0
- package/src/hooks.js +442 -0
- package/src/signals.js +186 -0
- package/dist/application/use-cases/check-claimed-tests.js +0 -81
- package/dist/application/use-cases/detect-test-weakening.js +0 -237
- package/dist/application/use-cases/rerun-tests.js +0 -329
- package/dist/index.js +0 -111
- package/dist/infrastructure/orchestration/artifacts-extractor.js +0 -66
- package/dist/presentation/cli/commands/check-command.js +0 -251
- package/dist/presentation/cli/commands/help-command.js +0 -77
- package/dist/ui.js +0 -53
- package/dist/utils/typo-guard.js +0 -133
- package/dist/utils/version.js +0 -40
package/dist/utils/typo-guard.js
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Typo guard for the bare `codehere <word>` action.
|
|
3
|
-
*
|
|
4
|
-
* Why this exists: codehere's bare action treats any string as a one-shot task
|
|
5
|
-
* prompt for the Conductor. Without a guard, a typo like `codehere helpp`
|
|
6
|
-
* silently spawns a Claude task to interpret "helpp" as a question, burning
|
|
7
|
-
* API tokens for what was clearly meant to be `codehere help`.
|
|
8
|
-
*
|
|
9
|
-
* Earlier rc.15 attempt (greedy edit-check + prefix match) over-matched and
|
|
10
|
-
* blocked legitimate single-word prompts like "task-runner" or "h". Codex
|
|
11
|
-
* caught the regression in review. The rc.16 version uses real Levenshtein,
|
|
12
|
-
* a length floor, and explicit kebab-case exemption.
|
|
13
|
-
*
|
|
14
|
-
* v0.6 extension: handle multi-token input. Original guard bailed on any
|
|
15
|
-
* whitespace, which let `setupp foo bar` and `daemon start` silently route to
|
|
16
|
-
* the task spawner. Now: checkTypo tokenizes and runs typo-detection on the
|
|
17
|
-
* first token. looksLikeUnknownCommand catches the narrow `cmd subcmd` shape
|
|
18
|
-
* (two short alphabetic tokens, first not a known command, not a typo) so
|
|
19
|
-
* cases like `daemon start` get an "unknown command" message instead of
|
|
20
|
-
* silently spawning an LLM task.
|
|
21
|
-
*/
|
|
22
|
-
/** Standard Levenshtein distance. Bounded inputs only — no allocation guard. */
|
|
23
|
-
export function levenshtein(a, b) {
|
|
24
|
-
const m = a.length;
|
|
25
|
-
const n = b.length;
|
|
26
|
-
if (m === 0)
|
|
27
|
-
return n;
|
|
28
|
-
if (n === 0)
|
|
29
|
-
return m;
|
|
30
|
-
const dp = new Array(n + 1);
|
|
31
|
-
for (let j = 0; j <= n; j++)
|
|
32
|
-
dp[j] = j;
|
|
33
|
-
for (let i = 1; i <= m; i++) {
|
|
34
|
-
let prev = dp[0];
|
|
35
|
-
dp[0] = i;
|
|
36
|
-
for (let j = 1; j <= n; j++) {
|
|
37
|
-
const tmp = dp[j];
|
|
38
|
-
dp[j] = a[i - 1] === b[j - 1] ? prev : Math.min(prev, dp[j], dp[j - 1]) + 1;
|
|
39
|
-
prev = tmp;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return dp[n];
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Internal: typo-check a single token against known commands.
|
|
46
|
-
* Returns up to 3 closest matches (Lev ≤ 2, distance < input length) or null.
|
|
47
|
-
*/
|
|
48
|
-
function checkTypoSingle(token, knownCommands) {
|
|
49
|
-
if (token.length < 4 || token.length > 14)
|
|
50
|
-
return null;
|
|
51
|
-
if (!/^[a-z]+$/i.test(token))
|
|
52
|
-
return null;
|
|
53
|
-
const lower = token.toLowerCase();
|
|
54
|
-
// Defensively normalize knownCommands to lowercase too — Codex rc.16 review
|
|
55
|
-
// flagged this for symmetry. Currently every Commander subcommand is lower
|
|
56
|
-
// already, but a future addition that registers an uppercase name shouldn't
|
|
57
|
-
// silently slip through the equality check.
|
|
58
|
-
const knownLower = knownCommands.map((n) => n.toLowerCase());
|
|
59
|
-
if (knownLower.includes(lower))
|
|
60
|
-
return null;
|
|
61
|
-
// Length-prefilter cheap reject before computing DP — same outcome, less work.
|
|
62
|
-
const scored = knownLower
|
|
63
|
-
.filter((n) => Math.abs(n.length - lower.length) <= 2)
|
|
64
|
-
.map((n) => ({ n, d: levenshtein(lower, n) }))
|
|
65
|
-
.filter((s) => s.d > 0 && s.d <= 2 && s.d < lower.length)
|
|
66
|
-
// Deterministic tie-breaker (alphabetical) so ranking is stable across runs.
|
|
67
|
-
.sort((a, b) => a.d - b.d || a.n.localeCompare(b.n))
|
|
68
|
-
.slice(0, 3);
|
|
69
|
-
return scored.length > 0 ? scored.map((s) => s.n) : null;
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Decide whether a bare-action input contains a typo of a known subcommand.
|
|
73
|
-
* Returns suggestions if the FIRST token looks like a typo; null otherwise.
|
|
74
|
-
*
|
|
75
|
-
* Multi-token inputs (e.g. `setupp foo bar`) tokenize on whitespace and only
|
|
76
|
-
* the first token is typo-checked — the rest are treated as positional args
|
|
77
|
-
* the user meant to pass to the suggested command.
|
|
78
|
-
*
|
|
79
|
-
* Heuristics (intentionally narrow — false positives are worse than false negatives):
|
|
80
|
-
* - First token is 4–14 chars, pure alphabetic, no hyphens (kebab-case is a likely real prompt)
|
|
81
|
-
* - True Levenshtein distance ≤ 2 to a known command
|
|
82
|
-
* - Distance must be < input length (avoid 2-char words matching anything)
|
|
83
|
-
* - Returns up to 3 closest commands ranked by ascending distance
|
|
84
|
-
*/
|
|
85
|
-
export function checkTypo(input, knownCommands) {
|
|
86
|
-
const trimmed = input.trim();
|
|
87
|
-
if (!trimmed)
|
|
88
|
-
return null;
|
|
89
|
-
const first = trimmed.split(/\s+/)[0];
|
|
90
|
-
return checkTypoSingle(first, knownCommands);
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Detect inputs shaped like a typed-but-unknown subcommand invocation:
|
|
94
|
-
* exactly two short alphabetic tokens, first token NOT a known command and NOT
|
|
95
|
-
* a near-typo of one. Returns the unknown first token (for error formatting)
|
|
96
|
-
* or null if input doesn't match the shape.
|
|
97
|
-
*
|
|
98
|
-
* Catches cases the typo guard misses — e.g. `daemon start`, `webui open`,
|
|
99
|
-
* `nuke session` — where the first word isn't close enough to a real command
|
|
100
|
-
* for Levenshtein suggestions but is clearly a command attempt rather than a
|
|
101
|
-
* natural-language prompt.
|
|
102
|
-
*
|
|
103
|
-
* Conservative on purpose:
|
|
104
|
-
* - Exactly 2 tokens (3+ tokens are usually prompts: "fix the login bug")
|
|
105
|
-
* - Both tokens pure alphabetic (a slash/period in token 2 → file path → prompt)
|
|
106
|
-
* - First token 4-14 chars (skip "go run", "h x"); second 2-14 chars
|
|
107
|
-
* - First not a known command and not a typo (those branches handled elsewhere)
|
|
108
|
-
*/
|
|
109
|
-
export function looksLikeUnknownCommand(input, knownCommands) {
|
|
110
|
-
const trimmed = input.trim();
|
|
111
|
-
if (!trimmed)
|
|
112
|
-
return null;
|
|
113
|
-
const tokens = trimmed.split(/\s+/);
|
|
114
|
-
if (tokens.length !== 2)
|
|
115
|
-
return null;
|
|
116
|
-
const [first, second] = tokens;
|
|
117
|
-
if (first.length < 4 || first.length > 14)
|
|
118
|
-
return null;
|
|
119
|
-
if (second.length < 2 || second.length > 14)
|
|
120
|
-
return null;
|
|
121
|
-
if (!/^[a-z]+$/i.test(first))
|
|
122
|
-
return null;
|
|
123
|
-
if (!/^[a-z]+$/i.test(second))
|
|
124
|
-
return null;
|
|
125
|
-
const lower = first.toLowerCase();
|
|
126
|
-
const knownLower = knownCommands.map((n) => n.toLowerCase());
|
|
127
|
-
if (knownLower.includes(lower))
|
|
128
|
-
return null;
|
|
129
|
-
if (checkTypoSingle(first, knownCommands))
|
|
130
|
-
return null;
|
|
131
|
-
return first;
|
|
132
|
-
}
|
|
133
|
-
//# sourceMappingURL=typo-guard.js.map
|
package/dist/utils/version.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Centralized Version Utility
|
|
3
|
-
* Single source of truth for version information
|
|
4
|
-
* Reads from package.json to ensure consistency
|
|
5
|
-
*
|
|
6
|
-
* Clean Architecture: Infrastructure/Utils Layer
|
|
7
|
-
*/
|
|
8
|
-
import { readFileSync, existsSync } from 'fs';
|
|
9
|
-
import { join, dirname } from 'path';
|
|
10
|
-
import { fileURLToPath } from 'url';
|
|
11
|
-
let cachedVersion = null;
|
|
12
|
-
/**
|
|
13
|
-
* Get the current version from package.json
|
|
14
|
-
* Caches the result for performance
|
|
15
|
-
*/
|
|
16
|
-
export function getVersion() {
|
|
17
|
-
if (cachedVersion) {
|
|
18
|
-
return cachedVersion;
|
|
19
|
-
}
|
|
20
|
-
try {
|
|
21
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
22
|
-
const __dirname = dirname(__filename);
|
|
23
|
-
const agentDir = join(__dirname, '../..');
|
|
24
|
-
const packageJsonPath = join(agentDir, 'package.json');
|
|
25
|
-
if (existsSync(packageJsonPath)) {
|
|
26
|
-
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
27
|
-
const version = packageJson.version || '0.3.0';
|
|
28
|
-
cachedVersion = version;
|
|
29
|
-
return version;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
catch {
|
|
33
|
-
// Fallback if can't read package.json
|
|
34
|
-
console.warn('Warning: Could not read version from package.json, using fallback');
|
|
35
|
-
}
|
|
36
|
-
// Fallback version (should match package.json)
|
|
37
|
-
cachedVersion = '0.3.0';
|
|
38
|
-
return cachedVersion;
|
|
39
|
-
}
|
|
40
|
-
//# sourceMappingURL=version.js.map
|