klyro 0.1.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.
- package/LICENSE +21 -0
- package/README.md +50 -0
- package/dist/agent/anthropic-adapter.d.ts +75 -0
- package/dist/agent/anthropic-adapter.js +297 -0
- package/dist/agent/message.d.ts +40 -0
- package/dist/agent/message.js +21 -0
- package/dist/agent/observation.d.ts +47 -0
- package/dist/agent/observation.js +53 -0
- package/dist/agent/provider-adapter.d.ts +101 -0
- package/dist/agent/provider-adapter.js +254 -0
- package/dist/agent/registry.d.ts +42 -0
- package/dist/agent/registry.js +86 -0
- package/dist/agent/retry.d.ts +34 -0
- package/dist/agent/retry.js +91 -0
- package/dist/agent/runtime.d.ts +130 -0
- package/dist/agent/runtime.js +221 -0
- package/dist/agent/worker-spawner.d.ts +41 -0
- package/dist/agent/worker-spawner.js +76 -0
- package/dist/chat.d.ts +39 -0
- package/dist/chat.js +235 -0
- package/dist/chat.js.map +1 -0
- package/dist/cli/eval.d.ts +75 -0
- package/dist/cli/eval.js +190 -0
- package/dist/cli/repl.d.ts +15 -0
- package/dist/cli/repl.js +194 -0
- package/dist/cli/run.d.ts +67 -0
- package/dist/cli/run.js +198 -0
- package/dist/cli/slash/parser.d.ts +39 -0
- package/dist/cli/slash/parser.js +47 -0
- package/dist/context/level6.d.ts +45 -0
- package/dist/context/level6.js +231 -0
- package/dist/context/level7.d.ts +84 -0
- package/dist/context/level7.js +156 -0
- package/dist/context/project-map.d.ts +48 -0
- package/dist/context/project-map.js +438 -0
- package/dist/context/repo-map.d.ts +30 -0
- package/dist/context/repo-map.js +168 -0
- package/dist/context/selector.d.ts +22 -0
- package/dist/context/selector.js +37 -0
- package/dist/context/snippets.d.ts +17 -0
- package/dist/context/snippets.js +15 -0
- package/dist/context/tokenizer.d.ts +49 -0
- package/dist/context/tokenizer.js +97 -0
- package/dist/eval/harness.d.ts +48 -0
- package/dist/eval/harness.js +149 -0
- package/dist/eval/tasks.d.ts +6 -0
- package/dist/eval/tasks.js +98 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +128 -0
- package/dist/index.js.map +1 -0
- package/dist/persistence/audit.d.ts +75 -0
- package/dist/persistence/audit.js +15 -0
- package/dist/persistence/store.d.ts +67 -0
- package/dist/persistence/store.js +106 -0
- package/dist/policy/approval.d.ts +35 -0
- package/dist/policy/approval.js +54 -0
- package/dist/policy/engine.d.ts +76 -0
- package/dist/policy/engine.js +163 -0
- package/dist/policy/path-guard.d.ts +30 -0
- package/dist/policy/path-guard.js +100 -0
- package/dist/policy/secret-redactor.d.ts +19 -0
- package/dist/policy/secret-redactor.js +52 -0
- package/dist/providers.d.ts +23 -0
- package/dist/providers.js +83 -0
- package/dist/repl.d.ts +9 -0
- package/dist/repl.js +170 -0
- package/dist/repl.js.map +1 -0
- package/dist/tools/fs/edit-file.d.ts +48 -0
- package/dist/tools/fs/edit-file.js +84 -0
- package/dist/tools/fs/list-dir.d.ts +40 -0
- package/dist/tools/fs/list-dir.js +72 -0
- package/dist/tools/fs/read-file.d.ts +66 -0
- package/dist/tools/fs/read-file.js +75 -0
- package/dist/tools/fs/write-file.d.ts +24 -0
- package/dist/tools/fs/write-file.js +48 -0
- package/dist/tools/git/git-diff.d.ts +35 -0
- package/dist/tools/git/git-diff.js +68 -0
- package/dist/tools/git/git-status.d.ts +29 -0
- package/dist/tools/git/git-status.js +57 -0
- package/dist/tools/normalize.d.ts +31 -0
- package/dist/tools/normalize.js +88 -0
- package/dist/tools/registry.d.ts +23 -0
- package/dist/tools/registry.js +87 -0
- package/dist/tools/schema.d.ts +29 -0
- package/dist/tools/schema.js +183 -0
- package/dist/tools/search/dependencies.d.ts +44 -0
- package/dist/tools/search/dependencies.js +188 -0
- package/dist/tools/search/glob.d.ts +26 -0
- package/dist/tools/search/glob.js +88 -0
- package/dist/tools/search/grep.d.ts +52 -0
- package/dist/tools/search/grep.js +125 -0
- package/dist/tools/search/recent-files.d.ts +33 -0
- package/dist/tools/search/recent-files.js +100 -0
- package/dist/tools/search/search-files.d.ts +39 -0
- package/dist/tools/search/search-files.js +110 -0
- package/dist/tools/shell/shell-exec.d.ts +60 -0
- package/dist/tools/shell/shell-exec.js +133 -0
- package/dist/tools/types.d.ts +54 -0
- package/dist/tools/types.js +15 -0
- package/dist/tools/verify/run-verify.d.ts +60 -0
- package/dist/tools/verify/run-verify.js +115 -0
- package/dist/tui/app.d.ts +27 -0
- package/dist/tui/app.js +79 -0
- package/dist/tui/app.test.d.ts +1 -0
- package/dist/tui/app.test.js +77 -0
- package/dist/tui/status.d.ts +21 -0
- package/dist/tui/status.js +13 -0
- package/dist/tui/status.test.d.ts +1 -0
- package/dist/tui/status.test.js +39 -0
- package/dist/tui/transcript.d.ts +40 -0
- package/dist/tui/transcript.js +28 -0
- package/dist/tui/transcript.test.d.ts +1 -0
- package/dist/tui/transcript.test.js +71 -0
- package/dist/verification/detect.d.ts +29 -0
- package/dist/verification/detect.js +85 -0
- package/dist/verification/engine.d.ts +25 -0
- package/dist/verification/engine.js +57 -0
- package/package.json +58 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Failure-type classifier + diagnostic parser. Given the stderr/stdout of
|
|
3
|
+
* a verify command, decide which kind of failure it represents and pull
|
|
4
|
+
* out a structured Failure object the runtime can feed back to the model.
|
|
5
|
+
*
|
|
6
|
+
* Supported types: 'type' (TypeScript tsc), 'test' (vitest/jest/mocha),
|
|
7
|
+
* 'lint' (eslint), 'build' (esbuild/webpack/tsc bundled), 'runtime'
|
|
8
|
+
* (uncaught exception).
|
|
9
|
+
*
|
|
10
|
+
* This is intentionally a heuristic, not a parser. The model still sees
|
|
11
|
+
* the raw output; we just pre-structure the high-signal lines.
|
|
12
|
+
*/
|
|
13
|
+
export type FailureType = 'type' | 'test' | 'lint' | 'build' | 'runtime' | 'unknown';
|
|
14
|
+
export interface FailureFile {
|
|
15
|
+
path: string;
|
|
16
|
+
line?: number;
|
|
17
|
+
column?: number;
|
|
18
|
+
message: string;
|
|
19
|
+
code?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface Failure {
|
|
22
|
+
type: FailureType;
|
|
23
|
+
files: FailureFile[];
|
|
24
|
+
raw: string;
|
|
25
|
+
exitCode: number;
|
|
26
|
+
}
|
|
27
|
+
export declare function detect(stdout: string, stderr: string, exitCode: number): Failure;
|
|
28
|
+
/** Build a short, structured summary the model can act on. */
|
|
29
|
+
export declare function summarize(failure: Failure): string;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Failure-type classifier + diagnostic parser. Given the stderr/stdout of
|
|
3
|
+
* a verify command, decide which kind of failure it represents and pull
|
|
4
|
+
* out a structured Failure object the runtime can feed back to the model.
|
|
5
|
+
*
|
|
6
|
+
* Supported types: 'type' (TypeScript tsc), 'test' (vitest/jest/mocha),
|
|
7
|
+
* 'lint' (eslint), 'build' (esbuild/webpack/tsc bundled), 'runtime'
|
|
8
|
+
* (uncaught exception).
|
|
9
|
+
*
|
|
10
|
+
* This is intentionally a heuristic, not a parser. The model still sees
|
|
11
|
+
* the raw output; we just pre-structure the high-signal lines.
|
|
12
|
+
*/
|
|
13
|
+
const TS_LINE = /^(.+?)\((\d+),(\d+)\):\s+error\s+(TS\d+):\s+(.+)$/;
|
|
14
|
+
const TEST_FAIL = /^\s*✘|FAIL\s+(\S+)|✗\s+(\S+)|×\s+(.+?)\s/;
|
|
15
|
+
const LINT_LINE = /^(.+?)\s*$/;
|
|
16
|
+
const RUNTIME_LINE = /^(?:Error|TypeError|ReferenceError):\s+(.+)$/;
|
|
17
|
+
export function detect(stdout, stderr, exitCode) {
|
|
18
|
+
const combined = stderr + '\n' + stdout;
|
|
19
|
+
if (exitCode === 0) {
|
|
20
|
+
return { type: 'unknown', files: [], raw: combined, exitCode };
|
|
21
|
+
}
|
|
22
|
+
// TypeScript tsc.
|
|
23
|
+
const tsMatches = [];
|
|
24
|
+
for (const line of combined.split(/\r?\n/)) {
|
|
25
|
+
const m = TS_LINE.exec(line);
|
|
26
|
+
if (m && m[1] && m[2] && m[3] && m[4] && m[5]) {
|
|
27
|
+
tsMatches.push({ path: m[1], line: Number(m[2]), column: Number(m[3]), code: m[4], message: m[5] });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (tsMatches.length > 0)
|
|
31
|
+
return { type: 'type', files: tsMatches, raw: combined, exitCode };
|
|
32
|
+
// Test runner.
|
|
33
|
+
if (/Test Suites:|FAIL\s|Tests:.*failed|✘|✗/.test(combined)) {
|
|
34
|
+
const files = [];
|
|
35
|
+
for (const line of combined.split(/\r?\n/)) {
|
|
36
|
+
const m = TEST_FAIL.exec(line);
|
|
37
|
+
if (m) {
|
|
38
|
+
const target = m[1] ?? m[2] ?? m[3] ?? line.trim();
|
|
39
|
+
files.push({ path: target, message: line.trim() });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return { type: 'test', files, raw: combined, exitCode };
|
|
43
|
+
}
|
|
44
|
+
// ESLint.
|
|
45
|
+
if (/error\s+at\s+|eslint.*problem|✖/.test(combined)) {
|
|
46
|
+
return { type: 'lint', files: extractFirstLines(combined, 5), raw: combined, exitCode };
|
|
47
|
+
}
|
|
48
|
+
// Runtime exception.
|
|
49
|
+
const lines = combined.split(/\r?\n/);
|
|
50
|
+
const rt = lines.some((l) => RUNTIME_LINE.test(l));
|
|
51
|
+
if (rt) {
|
|
52
|
+
return { type: 'runtime', files: extractFirstLines(combined, 5), raw: combined, exitCode };
|
|
53
|
+
}
|
|
54
|
+
// Generic build.
|
|
55
|
+
if (/error/i.test(combined)) {
|
|
56
|
+
return { type: 'build', files: extractFirstLines(combined, 5), raw: combined, exitCode };
|
|
57
|
+
}
|
|
58
|
+
return { type: 'unknown', files: extractFirstLines(combined, 3), raw: combined, exitCode };
|
|
59
|
+
}
|
|
60
|
+
function extractFirstLines(s, n) {
|
|
61
|
+
return s
|
|
62
|
+
.split(/\r?\n/)
|
|
63
|
+
.filter((l) => l.trim().length > 0)
|
|
64
|
+
.slice(0, n)
|
|
65
|
+
.map((message) => ({ path: '', message }));
|
|
66
|
+
}
|
|
67
|
+
/** Build a short, structured summary the model can act on. */
|
|
68
|
+
export function summarize(failure) {
|
|
69
|
+
if (failure.files.length === 0) {
|
|
70
|
+
return `Verification failed (exit ${failure.exitCode}, type=${failure.type}). No structured files parsed; see raw output below.\n\n${truncate(failure.raw, 2000)}`;
|
|
71
|
+
}
|
|
72
|
+
const lines = [`Verification failed (${failure.type}, exit ${failure.exitCode}).`];
|
|
73
|
+
for (const f of failure.files.slice(0, 8)) {
|
|
74
|
+
const loc = f.line ? `:${f.line}${f.column ? `:${f.column}` : ''}` : '';
|
|
75
|
+
const code = f.code ? ` [${f.code}]` : '';
|
|
76
|
+
lines.push(`- ${f.path}${loc}${code} — ${f.message}`);
|
|
77
|
+
}
|
|
78
|
+
lines.push('');
|
|
79
|
+
lines.push('Raw output (truncated):');
|
|
80
|
+
lines.push(truncate(failure.raw, 1500));
|
|
81
|
+
return lines.join('\n');
|
|
82
|
+
}
|
|
83
|
+
function truncate(s, n) {
|
|
84
|
+
return s.length > n ? s.slice(0, n) + '\n... [truncated]' : s;
|
|
85
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verification engine — run a command, classify failures, and run a
|
|
3
|
+
* bounded repair loop. The model is asked to fix the same task again
|
|
4
|
+
* with the structured diagnostic injected as a user message.
|
|
5
|
+
*
|
|
6
|
+
* On success: returns { ok: true }.
|
|
7
|
+
* On failure: returns { ok: false, failure } with the most recent
|
|
8
|
+
* structured Failure (and the model has had up to N attempts to fix).
|
|
9
|
+
*/
|
|
10
|
+
import { type Failure } from './detect.js';
|
|
11
|
+
export interface VerifyOptions {
|
|
12
|
+
cwd: string;
|
|
13
|
+
command: string;
|
|
14
|
+
timeoutMs?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface VerifyResult {
|
|
17
|
+
ok: boolean;
|
|
18
|
+
exitCode: number;
|
|
19
|
+
stdout: string;
|
|
20
|
+
stderr: string;
|
|
21
|
+
failure?: Failure;
|
|
22
|
+
}
|
|
23
|
+
export declare function verify(opts: VerifyOptions): Promise<VerifyResult>;
|
|
24
|
+
/** Format a failure for injection into the model's transcript. */
|
|
25
|
+
export declare function diagnosticForModel(result: VerifyResult): string;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verification engine — run a command, classify failures, and run a
|
|
3
|
+
* bounded repair loop. The model is asked to fix the same task again
|
|
4
|
+
* with the structured diagnostic injected as a user message.
|
|
5
|
+
*
|
|
6
|
+
* On success: returns { ok: true }.
|
|
7
|
+
* On failure: returns { ok: false, failure } with the most recent
|
|
8
|
+
* structured Failure (and the model has had up to N attempts to fix).
|
|
9
|
+
*/
|
|
10
|
+
import { spawn } from 'node:child_process';
|
|
11
|
+
import { detect, summarize } from './detect.js';
|
|
12
|
+
export async function verify(opts) {
|
|
13
|
+
const timeout = opts.timeoutMs ?? 5 * 60 * 1000;
|
|
14
|
+
return new Promise((resolve) => {
|
|
15
|
+
const child = spawn(opts.command, { cwd: opts.cwd, shell: true, env: process.env });
|
|
16
|
+
let stdout = '';
|
|
17
|
+
let stderr = '';
|
|
18
|
+
let done = false;
|
|
19
|
+
const timer = setTimeout(() => {
|
|
20
|
+
if (done)
|
|
21
|
+
return;
|
|
22
|
+
child.kill();
|
|
23
|
+
done = true;
|
|
24
|
+
const raw = stderr + '\n' + stdout;
|
|
25
|
+
resolve({
|
|
26
|
+
ok: false,
|
|
27
|
+
exitCode: -1,
|
|
28
|
+
stdout,
|
|
29
|
+
stderr: stderr + '\n[verify timeout]',
|
|
30
|
+
failure: { type: 'runtime', files: [], raw, exitCode: -1 },
|
|
31
|
+
});
|
|
32
|
+
}, timeout);
|
|
33
|
+
child.stdout.on('data', (b) => { stdout += b.toString(); });
|
|
34
|
+
child.stderr.on('data', (b) => { stderr += b.toString(); });
|
|
35
|
+
child.on('close', (code) => {
|
|
36
|
+
if (done)
|
|
37
|
+
return;
|
|
38
|
+
done = true;
|
|
39
|
+
clearTimeout(timer);
|
|
40
|
+
const exit = typeof code === 'number' ? code : -1;
|
|
41
|
+
if (exit === 0) {
|
|
42
|
+
resolve({ ok: true, exitCode: 0, stdout, stderr });
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const failure = detect(stdout, stderr, exit);
|
|
46
|
+
resolve({ ok: false, exitCode: exit, stdout, stderr, failure });
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/** Format a failure for injection into the model's transcript. */
|
|
51
|
+
export function diagnosticForModel(result) {
|
|
52
|
+
if (result.ok)
|
|
53
|
+
return 'Verification passed.';
|
|
54
|
+
if (!result.failure)
|
|
55
|
+
return `Verification failed with exit ${result.exitCode}.`;
|
|
56
|
+
return summarize(result.failure);
|
|
57
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "klyro",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Klyro — autonomous coding harness CLI that streams from any OpenAI-compatible or Anthropic LLM endpoint.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"klyro": "dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=20"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc",
|
|
21
|
+
"start": "node dist/index.js",
|
|
22
|
+
"dev": "tsx src/index.ts",
|
|
23
|
+
"dev:watch": "tsx watch src/index.ts",
|
|
24
|
+
"typecheck": "tsc --noEmit",
|
|
25
|
+
"test": "vitest run",
|
|
26
|
+
"test:watch": "vitest",
|
|
27
|
+
"prepublishOnly": "npm run typecheck && npm test && npm run build",
|
|
28
|
+
"pack:dry": "npm pack --dry-run",
|
|
29
|
+
"publish:public": "npm publish --access public"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"llm",
|
|
33
|
+
"ai",
|
|
34
|
+
"cli",
|
|
35
|
+
"openai",
|
|
36
|
+
"anthropic",
|
|
37
|
+
"harness",
|
|
38
|
+
"agent",
|
|
39
|
+
"streaming",
|
|
40
|
+
"klyro"
|
|
41
|
+
],
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"commander": "^12.1.0",
|
|
45
|
+
"ink": "^7.1.1",
|
|
46
|
+
"ink-spinner": "^5.0.0",
|
|
47
|
+
"react": "^19.2.0",
|
|
48
|
+
"zod": "^4.5.4"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/node": "^22.9.0",
|
|
52
|
+
"@types/react": "^19.2.18",
|
|
53
|
+
"ink-testing-library": "^4.0.0",
|
|
54
|
+
"tsx": "^4.23.13",
|
|
55
|
+
"typescript": "^5.5.4",
|
|
56
|
+
"vitest": "^4.1.11"
|
|
57
|
+
}
|
|
58
|
+
}
|