@sworddut/myclaw 0.1.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/README.md +93 -0
- package/bin/dev.js +5 -0
- package/bin/run.js +5 -0
- package/dist/commands/chat.d.ts +5 -0
- package/dist/commands/chat.js +8 -0
- package/dist/commands/chat.js.map +1 -0
- package/dist/commands/config.d.ts +5 -0
- package/dist/commands/config.js +10 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.js +26 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/run.d.ts +13 -0
- package/dist/commands/run.js +84 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/config/load-config.d.ts +2 -0
- package/dist/config/load-config.js +10 -0
- package/dist/config/load-config.js.map +1 -0
- package/dist/config/schema.d.ts +18 -0
- package/dist/config/schema.js +8 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/core/agent.d.ts +39 -0
- package/dist/core/agent.js +277 -0
- package/dist/core/agent.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/mock-provider.d.ts +5 -0
- package/dist/providers/mock-provider.js +10 -0
- package/dist/providers/mock-provider.js.map +1 -0
- package/dist/providers/openai-provider.d.ts +14 -0
- package/dist/providers/openai-provider.js +63 -0
- package/dist/providers/openai-provider.js.map +1 -0
- package/dist/providers/types.d.ts +8 -0
- package/dist/providers/types.js +2 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/tools/filesystem.d.ts +6 -0
- package/dist/tools/filesystem.js +49 -0
- package/dist/tools/filesystem.js.map +1 -0
- package/dist/tools/shell.d.ts +1 -0
- package/dist/tools/shell.js +9 -0
- package/dist/tools/shell.js.map +1 -0
- package/package.json +42 -0
package/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# myclaw
|
|
2
|
+
|
|
3
|
+
A CLI coding agent scaffold (TypeScript + oclif).
|
|
4
|
+
|
|
5
|
+
## Tech stack
|
|
6
|
+
|
|
7
|
+
- Node.js 20+
|
|
8
|
+
- TypeScript
|
|
9
|
+
- oclif
|
|
10
|
+
- execa (tool execution)
|
|
11
|
+
- cosmiconfig + dotenv (config)
|
|
12
|
+
- zod (schema)
|
|
13
|
+
- better-sqlite3 (storage, reserved for next step)
|
|
14
|
+
- vitest (tests)
|
|
15
|
+
|
|
16
|
+
## Quick start
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install
|
|
20
|
+
npm run build
|
|
21
|
+
cp .env.example .env
|
|
22
|
+
# fill OPENAI_API_KEY in .env
|
|
23
|
+
# optional: set model in env
|
|
24
|
+
# OPENAI_MODEL=gpt-4o-mini
|
|
25
|
+
# optional: for openai-compatible third-party endpoint
|
|
26
|
+
# OPENAI_BASE_URL=https://your-endpoint/v1
|
|
27
|
+
node ./bin/run.js init -f
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`OPENAI_BASE_URL` and `.myclawrc.json` `baseURL` both support OpenAI-compatible providers.
|
|
31
|
+
Model priority: `.myclawrc.json` `model` > `OPENAI_MODEL` > `gpt-4o-mini`.
|
|
32
|
+
|
|
33
|
+
## Commands
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Show resolved config
|
|
37
|
+
node ./bin/run.js config
|
|
38
|
+
|
|
39
|
+
# One-shot task
|
|
40
|
+
node ./bin/run.js run "implement hello world"
|
|
41
|
+
|
|
42
|
+
# Hide step logs and print only final answer
|
|
43
|
+
node ./bin/run.js run --quiet "implement hello world"
|
|
44
|
+
|
|
45
|
+
# Show raw model responses for each step (debug)
|
|
46
|
+
node ./bin/run.js run --verboseModel "implement hello world"
|
|
47
|
+
|
|
48
|
+
# Disable interactive approval prompts (sensitive commands auto-denied)
|
|
49
|
+
node ./bin/run.js run --nonInteractive "implement hello world"
|
|
50
|
+
|
|
51
|
+
# Init local config files
|
|
52
|
+
node ./bin/run.js init
|
|
53
|
+
|
|
54
|
+
# Scaffolded chat mode
|
|
55
|
+
node ./bin/run.js chat
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
File mutation safety rules:
|
|
59
|
+
- Existing files must be `read_file` before `write_file`/`apply_patch`.
|
|
60
|
+
- New file creation is blocked by default. Use `write_file` with `allowCreate=true` only when explicitly needed.
|
|
61
|
+
- Destructive shell commands (for example `rm`, `rmdir`, `unlink`, `del`, `git reset --hard`, `git clean`) are treated as sensitive.
|
|
62
|
+
- Sensitive shell commands require interactive approval (`WAITING FOR USER INPUT`), otherwise they are denied.
|
|
63
|
+
- Multiple reads are allowed in one step.
|
|
64
|
+
- Only one mutation (`write_file` or `apply_patch`) is allowed per step.
|
|
65
|
+
|
|
66
|
+
## Project structure
|
|
67
|
+
|
|
68
|
+
```txt
|
|
69
|
+
bin/ # CLI entrypoints (prod/dev)
|
|
70
|
+
src/commands/ # CLI commands
|
|
71
|
+
src/core/ # agent orchestration
|
|
72
|
+
src/providers/ # LLM provider abstraction
|
|
73
|
+
src/tools/ # executable tools
|
|
74
|
+
src/config/ # config loader + schema
|
|
75
|
+
test/ # tests
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Known Limitations (v0.1-alpha)
|
|
79
|
+
|
|
80
|
+
- Tool-calling protocol is JSON-in-text parsing, not native function-calling.
|
|
81
|
+
- No persistent conversation/session memory yet.
|
|
82
|
+
- No git-aware safety flow (branching, checkpoint, rollback) yet.
|
|
83
|
+
- Network/API retries and timeout policies are still basic.
|
|
84
|
+
- Permission model is coarse-grained; no per-tool policy profile yet.
|
|
85
|
+
|
|
86
|
+
## TODO
|
|
87
|
+
|
|
88
|
+
- Add interactive `chat` mode with persistent SQLite session history.
|
|
89
|
+
- Add per-step command timeout/retry/backoff controls in config.
|
|
90
|
+
- Add git checkpoint + rollback command before mutation steps.
|
|
91
|
+
- Add path allowlist/denylist policy with per-tool enforcement.
|
|
92
|
+
- Add native tool/function-calling mode when provider supports it.
|
|
93
|
+
- Add E2E regression tests for multi-file debug scenarios.
|
package/bin/dev.js
ADDED
package/bin/run.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class Chat extends Command {
|
|
3
|
+
static description = 'Interactive chat mode (scaffold only)';
|
|
4
|
+
async run() {
|
|
5
|
+
this.log('chat mode is scaffolded; interactive session will be implemented in next step.');
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=chat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../../src/commands/chat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,aAAa,CAAA;AAEnC,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,OAAO;IACvC,MAAM,CAAU,WAAW,GAAG,uCAAuC,CAAA;IAE9D,KAAK,CAAC,GAAG;QACd,IAAI,CAAC,GAAG,CAAC,gFAAgF,CAAC,CAAA;IAC5F,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
import { loadConfig } from '../config/load-config.js';
|
|
3
|
+
export default class Config extends Command {
|
|
4
|
+
static description = 'Print resolved config';
|
|
5
|
+
async run() {
|
|
6
|
+
const config = await loadConfig();
|
|
7
|
+
this.log(JSON.stringify(config, null, 2));
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,aAAa,CAAA;AACnC,OAAO,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAA;AAEnD,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,OAAO;IACzC,MAAM,CAAU,WAAW,GAAG,uBAAuB,CAAA;IAE9C,KAAK,CAAC,GAAG;QACd,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAA;QACjC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;IAC3C,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Command, Flags } from '@oclif/core';
|
|
2
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
export default class Init extends Command {
|
|
5
|
+
static description = 'Initialize myclaw config in current directory';
|
|
6
|
+
static flags = {
|
|
7
|
+
force: Flags.boolean({ char: 'f', description: 'overwrite existing config' })
|
|
8
|
+
};
|
|
9
|
+
async run() {
|
|
10
|
+
const { flags } = await this.parse(Init);
|
|
11
|
+
const targetDir = process.cwd();
|
|
12
|
+
const configPath = resolve(targetDir, '.myclawrc.json');
|
|
13
|
+
const envPath = resolve(targetDir, '.env.example');
|
|
14
|
+
await mkdir(targetDir, { recursive: true });
|
|
15
|
+
await writeFile(configPath, JSON.stringify({
|
|
16
|
+
provider: 'openai',
|
|
17
|
+
model: '',
|
|
18
|
+
baseURL: '',
|
|
19
|
+
workspace: targetDir
|
|
20
|
+
}, null, 2) + '\n', { flag: flags.force ? 'w' : 'wx' });
|
|
21
|
+
await writeFile(envPath, 'OPENAI_API_KEY=\nOPENAI_MODEL=gpt-4o-mini\nOPENAI_BASE_URL=\nANTHROPIC_API_KEY=\n', { flag: flags.force ? 'w' : 'wx' });
|
|
22
|
+
this.log(`Created ${configPath}`);
|
|
23
|
+
this.log(`Created ${envPath}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAE,KAAK,EAAC,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAC,KAAK,EAAE,SAAS,EAAC,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AAEjC,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,OAAO;IACvC,MAAM,CAAU,WAAW,GAAG,+CAA+C,CAAA;IAE7E,MAAM,CAAU,KAAK,GAAG;QACtB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,EAAC,IAAI,EAAE,GAAG,EAAE,WAAW,EAAE,2BAA2B,EAAC,CAAC;KAC5E,CAAA;IAEM,KAAK,CAAC,GAAG;QACd,MAAM,EAAC,KAAK,EAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACtC,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;QAC/B,MAAM,UAAU,GAAG,OAAO,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAA;QACvD,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,EAAE,cAAc,CAAC,CAAA;QAElD,MAAM,KAAK,CAAC,SAAS,EAAE,EAAC,SAAS,EAAE,IAAI,EAAC,CAAC,CAAA;QACzC,MAAM,SAAS,CACb,UAAU,EACV,IAAI,CAAC,SAAS,CACZ;YACE,QAAQ,EAAE,QAAQ;YAClB,KAAK,EAAE,EAAE;YACT,OAAO,EAAE,EAAE;YACX,SAAS,EAAE,SAAS;SACrB,EACD,IAAI,EACJ,CAAC,CACF,GAAG,IAAI,EACR,EAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAC,CACjC,CAAA;QAED,MAAM,SAAS,CACb,OAAO,EACP,mFAAmF,EACnF,EAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAC,CACjC,CAAA;QAED,IAAI,CAAC,GAAG,CAAC,WAAW,UAAU,EAAE,CAAC,CAAA;QACjC,IAAI,CAAC,GAAG,CAAC,WAAW,OAAO,EAAE,CAAC,CAAA;IAChC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class Run extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
quiet: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
6
|
+
verboseModel: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
7
|
+
nonInteractive: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
};
|
|
9
|
+
static args: {
|
|
10
|
+
task: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
11
|
+
};
|
|
12
|
+
run(): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
2
|
+
import { createInterface } from 'node:readline/promises';
|
|
3
|
+
import { stdin as stdIn, stdout as stdOut } from 'node:process';
|
|
4
|
+
import { runAgentTask } from '../core/agent.js';
|
|
5
|
+
const ANSI = {
|
|
6
|
+
reset: '\x1b[0m',
|
|
7
|
+
red: '\x1b[31m',
|
|
8
|
+
bold: '\x1b[1m'
|
|
9
|
+
};
|
|
10
|
+
function red(text) {
|
|
11
|
+
return `${ANSI.red}${text}${ANSI.reset}`;
|
|
12
|
+
}
|
|
13
|
+
function redBold(text) {
|
|
14
|
+
return `${ANSI.red}${ANSI.bold}${text}${ANSI.reset}`;
|
|
15
|
+
}
|
|
16
|
+
function now() {
|
|
17
|
+
return new Date().toISOString();
|
|
18
|
+
}
|
|
19
|
+
function shorten(text, max = 500) {
|
|
20
|
+
if (text.length <= max)
|
|
21
|
+
return text;
|
|
22
|
+
return `${text.slice(0, max)}\n...[truncated]`;
|
|
23
|
+
}
|
|
24
|
+
function formatEvent(event) {
|
|
25
|
+
switch (event.type) {
|
|
26
|
+
case 'start':
|
|
27
|
+
return `[${now()}] START provider=${event.provider} model=${event.model} workspace=${event.workspace}`;
|
|
28
|
+
case 'model_response':
|
|
29
|
+
return `[${now()}] MODEL_RESPONSE step=${event.step}\n${shorten(event.content)}`;
|
|
30
|
+
case 'tool_call':
|
|
31
|
+
return `[${now()}] TOOL_CALL step=${event.step} tool=${event.tool} input=${JSON.stringify(event.input)}`;
|
|
32
|
+
case 'tool_result':
|
|
33
|
+
return `[${now()}] TOOL_RESULT step=${event.step} tool=${event.tool} ok=${event.ok}\n${shorten(event.output)}`;
|
|
34
|
+
case 'final':
|
|
35
|
+
return `[${now()}] FINAL step=${event.step}\n${shorten(event.content)}`;
|
|
36
|
+
case 'max_steps':
|
|
37
|
+
return `[${now()}] MAX_STEPS step=${event.step}`;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export default class Run extends Command {
|
|
41
|
+
static description = 'Run a one-shot coding task';
|
|
42
|
+
static flags = {
|
|
43
|
+
quiet: Flags.boolean({ description: 'hide execution logs and print only final output' }),
|
|
44
|
+
verboseModel: Flags.boolean({ description: 'show raw model responses for each step' }),
|
|
45
|
+
nonInteractive: Flags.boolean({ description: 'disable interactive approval for sensitive commands' })
|
|
46
|
+
};
|
|
47
|
+
static args = {
|
|
48
|
+
task: Args.string({ description: 'task prompt', required: true })
|
|
49
|
+
};
|
|
50
|
+
async run() {
|
|
51
|
+
const { args, flags } = await this.parse(Run);
|
|
52
|
+
const output = await runAgentTask(args.task, {
|
|
53
|
+
onSensitiveAction: async ({ tool, command }) => {
|
|
54
|
+
if (flags.nonInteractive || !stdIn.isTTY) {
|
|
55
|
+
this.log(red(`[${now()}] ⚠️ SENSITIVE_REQUEST tool=${tool} auto=deny (non-interactive) command=${command}`));
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
this.log(redBold(`[${now()}] 🚨 WAITING FOR USER INPUT`));
|
|
59
|
+
this.log(red(`[${now()}] ⚠️ SENSITIVE_REQUEST tool=${tool} command=${command}`));
|
|
60
|
+
const rl = createInterface({ input: stdIn, output: stdOut });
|
|
61
|
+
try {
|
|
62
|
+
const answer = (await rl.question(redBold('🛑 Allow this sensitive command? [y/N] ')))
|
|
63
|
+
.trim()
|
|
64
|
+
.toLowerCase();
|
|
65
|
+
return answer === 'y' || answer === 'yes';
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
rl.close();
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
onEvent: flags.quiet
|
|
72
|
+
? undefined
|
|
73
|
+
: (event) => {
|
|
74
|
+
if (event.type === 'model_response' && !flags.verboseModel)
|
|
75
|
+
return;
|
|
76
|
+
if (event.type === 'final')
|
|
77
|
+
return;
|
|
78
|
+
this.log(formatEvent(event));
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
this.log(output);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { cosmiconfig } from 'cosmiconfig';
|
|
2
|
+
import dotenv from 'dotenv';
|
|
3
|
+
import { appConfigSchema } from './schema.js';
|
|
4
|
+
dotenv.config();
|
|
5
|
+
export async function loadConfig() {
|
|
6
|
+
const explorer = cosmiconfig('myclaw');
|
|
7
|
+
const result = await explorer.search();
|
|
8
|
+
return appConfigSchema.parse(result?.config ?? {});
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=load-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-config.js","sourceRoot":"","sources":["../../src/config/load-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAAC,MAAM,aAAa,CAAA;AACvC,OAAO,MAAM,MAAM,QAAQ,CAAA;AAC3B,OAAO,EAAC,eAAe,EAAiB,MAAM,aAAa,CAAA;AAE3D,MAAM,CAAC,MAAM,EAAE,CAAA;AAEf,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAA;IACtC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAA;IACtC,OAAO,eAAe,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,IAAI,EAAE,CAAC,CAAA;AACpD,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const appConfigSchema: z.ZodObject<{
|
|
3
|
+
provider: z.ZodDefault<z.ZodEnum<["mock", "openai", "anthropic"]>>;
|
|
4
|
+
model: z.ZodEffects<z.ZodOptional<z.ZodString>, string | undefined, unknown>;
|
|
5
|
+
baseURL: z.ZodEffects<z.ZodOptional<z.ZodString>, string | undefined, unknown>;
|
|
6
|
+
workspace: z.ZodDefault<z.ZodString>;
|
|
7
|
+
}, "strip", z.ZodTypeAny, {
|
|
8
|
+
provider: "mock" | "openai" | "anthropic";
|
|
9
|
+
workspace: string;
|
|
10
|
+
model?: string | undefined;
|
|
11
|
+
baseURL?: string | undefined;
|
|
12
|
+
}, {
|
|
13
|
+
provider?: "mock" | "openai" | "anthropic" | undefined;
|
|
14
|
+
model?: unknown;
|
|
15
|
+
baseURL?: unknown;
|
|
16
|
+
workspace?: string | undefined;
|
|
17
|
+
}>;
|
|
18
|
+
export type AppConfig = z.infer<typeof appConfigSchema>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const appConfigSchema = z.object({
|
|
3
|
+
provider: z.enum(['mock', 'openai', 'anthropic']).default('openai'),
|
|
4
|
+
model: z.preprocess((value) => (typeof value === 'string' && value.trim() === '' ? undefined : value), z.string().trim().optional()),
|
|
5
|
+
baseURL: z.preprocess((value) => (typeof value === 'string' && value.trim() === '' ? undefined : value), z.string().trim().optional()),
|
|
6
|
+
workspace: z.string().default(process.cwd())
|
|
7
|
+
});
|
|
8
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAA;AAErB,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;IACnE,KAAK,EAAE,CAAC,CAAC,UAAU,CACjB,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,EACjF,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,CAC7B;IACD,OAAO,EAAE,CAAC,CAAC,UAAU,CACnB,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,EACjF,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,CAC7B;IACD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;CAC7C,CAAC,CAAA"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
type ToolName = 'read_file' | 'write_file' | 'apply_patch' | 'list_files' | 'run_shell';
|
|
2
|
+
export type AgentEvent = {
|
|
3
|
+
type: 'start';
|
|
4
|
+
provider: string;
|
|
5
|
+
model: string;
|
|
6
|
+
workspace: string;
|
|
7
|
+
} | {
|
|
8
|
+
type: 'model_response';
|
|
9
|
+
step: number;
|
|
10
|
+
content: string;
|
|
11
|
+
} | {
|
|
12
|
+
type: 'tool_call';
|
|
13
|
+
step: number;
|
|
14
|
+
tool: ToolName;
|
|
15
|
+
input: Record<string, unknown>;
|
|
16
|
+
} | {
|
|
17
|
+
type: 'tool_result';
|
|
18
|
+
step: number;
|
|
19
|
+
tool: ToolName;
|
|
20
|
+
ok: boolean;
|
|
21
|
+
output: string;
|
|
22
|
+
} | {
|
|
23
|
+
type: 'final';
|
|
24
|
+
step: number;
|
|
25
|
+
content: string;
|
|
26
|
+
} | {
|
|
27
|
+
type: 'max_steps';
|
|
28
|
+
step: number;
|
|
29
|
+
};
|
|
30
|
+
type AgentRunOptions = {
|
|
31
|
+
onEvent?: (event: AgentEvent) => void;
|
|
32
|
+
maxSteps?: number;
|
|
33
|
+
onSensitiveAction?: (request: {
|
|
34
|
+
tool: ToolName;
|
|
35
|
+
command: string;
|
|
36
|
+
}) => Promise<boolean> | boolean;
|
|
37
|
+
};
|
|
38
|
+
export declare function runAgentTask(task: string, options?: AgentRunOptions): Promise<string>;
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { loadConfig } from '../config/load-config.js';
|
|
2
|
+
import { MockProvider } from '../providers/mock-provider.js';
|
|
3
|
+
import { OpenAIProvider } from '../providers/openai-provider.js';
|
|
4
|
+
import { applyTextPatch, fileExists, listFiles, readTextFile, resolveWorkspacePath, writeTextFile } from '../tools/filesystem.js';
|
|
5
|
+
import { runShell } from '../tools/shell.js';
|
|
6
|
+
function nonEmpty(value) {
|
|
7
|
+
if (!value)
|
|
8
|
+
return undefined;
|
|
9
|
+
const trimmed = value.trim();
|
|
10
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
11
|
+
}
|
|
12
|
+
function resolveModel(configModel) {
|
|
13
|
+
return nonEmpty(configModel) ?? nonEmpty(process.env.OPENAI_MODEL) ?? 'gpt-4o-mini';
|
|
14
|
+
}
|
|
15
|
+
function providerFromConfig(name, model, baseURL) {
|
|
16
|
+
if (name === 'mock')
|
|
17
|
+
return new MockProvider();
|
|
18
|
+
if (name === 'openai') {
|
|
19
|
+
const apiKey = process.env.OPENAI_API_KEY;
|
|
20
|
+
if (!apiKey) {
|
|
21
|
+
throw new Error('OPENAI_API_KEY is missing. Set it in your environment or .env file.');
|
|
22
|
+
}
|
|
23
|
+
return new OpenAIProvider({
|
|
24
|
+
apiKey,
|
|
25
|
+
model,
|
|
26
|
+
baseUrl: nonEmpty(baseURL) ?? nonEmpty(process.env.OPENAI_BASE_URL)
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
throw new Error(`Provider '${name}' is not implemented yet.`);
|
|
30
|
+
}
|
|
31
|
+
function extractJsonBlock(text) {
|
|
32
|
+
const trimmed = text.trim();
|
|
33
|
+
if (trimmed.startsWith('{') && trimmed.endsWith('}'))
|
|
34
|
+
return trimmed;
|
|
35
|
+
const fenceMatch = trimmed.match(/```json\s*([\s\S]*?)\s*```/i);
|
|
36
|
+
if (fenceMatch?.[1])
|
|
37
|
+
return fenceMatch[1];
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
function extractJsonObjects(text) {
|
|
41
|
+
const blocks = [];
|
|
42
|
+
let start = -1;
|
|
43
|
+
let depth = 0;
|
|
44
|
+
let inString = false;
|
|
45
|
+
let escaped = false;
|
|
46
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
47
|
+
const ch = text[i];
|
|
48
|
+
if (inString) {
|
|
49
|
+
if (escaped) {
|
|
50
|
+
escaped = false;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (ch === '\\') {
|
|
54
|
+
escaped = true;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (ch === '"')
|
|
58
|
+
inString = false;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (ch === '"') {
|
|
62
|
+
inString = true;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (ch === '{') {
|
|
66
|
+
if (depth === 0)
|
|
67
|
+
start = i;
|
|
68
|
+
depth += 1;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (ch === '}') {
|
|
72
|
+
if (depth === 0)
|
|
73
|
+
continue;
|
|
74
|
+
depth -= 1;
|
|
75
|
+
if (depth === 0 && start >= 0) {
|
|
76
|
+
blocks.push(text.slice(start, i + 1));
|
|
77
|
+
start = -1;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return blocks;
|
|
82
|
+
}
|
|
83
|
+
function parseToolCalls(text) {
|
|
84
|
+
const block = extractJsonBlock(text);
|
|
85
|
+
const candidates = block ? [block] : extractJsonObjects(text);
|
|
86
|
+
const calls = [];
|
|
87
|
+
for (const candidate of candidates) {
|
|
88
|
+
try {
|
|
89
|
+
const parsed = JSON.parse(candidate);
|
|
90
|
+
if (parsed.type !== 'tool_call')
|
|
91
|
+
continue;
|
|
92
|
+
if (!parsed.tool || !parsed.input)
|
|
93
|
+
continue;
|
|
94
|
+
calls.push(parsed);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return calls;
|
|
101
|
+
}
|
|
102
|
+
function mutationCount(calls) {
|
|
103
|
+
return calls.filter((call) => call.tool === 'write_file' || call.tool === 'apply_patch').length;
|
|
104
|
+
}
|
|
105
|
+
function readBeforeWriteError(tool, path) {
|
|
106
|
+
return `${tool} rejected: existing file '${path}' must be read_file first in this run.`;
|
|
107
|
+
}
|
|
108
|
+
function createFileRejectedError(path) {
|
|
109
|
+
return `write_file rejected: '${path}' does not exist. Read related files first and use apply_patch, or set allowCreate=true only when explicit file creation is required.`;
|
|
110
|
+
}
|
|
111
|
+
function shellDangerRejectedError(command) {
|
|
112
|
+
return `run_shell rejected: destructive command blocked. command=${command}`;
|
|
113
|
+
}
|
|
114
|
+
function looksDestructiveCommand(command) {
|
|
115
|
+
const text = command.toLowerCase().trim();
|
|
116
|
+
const patterns = [
|
|
117
|
+
/\brm\b/,
|
|
118
|
+
/\brmdir\b/,
|
|
119
|
+
/\bunlink\b/,
|
|
120
|
+
/\bdel\b/,
|
|
121
|
+
/\brd\b/, // windows remove directory shorthand can appear in scripts
|
|
122
|
+
/\bmv\b.+\s\/dev\/null/,
|
|
123
|
+
/\bgit\s+reset\s+--hard\b/,
|
|
124
|
+
/\bgit\s+clean\b/
|
|
125
|
+
];
|
|
126
|
+
return patterns.some((pattern) => pattern.test(text));
|
|
127
|
+
}
|
|
128
|
+
async function executeTool(toolCall, workspace, state, options) {
|
|
129
|
+
try {
|
|
130
|
+
switch (toolCall.tool) {
|
|
131
|
+
case 'read_file': {
|
|
132
|
+
const path = String(toolCall.input.path ?? '');
|
|
133
|
+
const content = await readTextFile(workspace, path);
|
|
134
|
+
state.readPaths.add(resolveWorkspacePath(workspace, path));
|
|
135
|
+
return { ok: true, output: content };
|
|
136
|
+
}
|
|
137
|
+
case 'write_file': {
|
|
138
|
+
const path = String(toolCall.input.path ?? '');
|
|
139
|
+
const content = String(toolCall.input.content ?? '');
|
|
140
|
+
const allowCreate = Boolean(toolCall.input.allowCreate ?? false);
|
|
141
|
+
const existing = await fileExists(workspace, path);
|
|
142
|
+
const canonicalPath = resolveWorkspacePath(workspace, path);
|
|
143
|
+
if (!existing && !allowCreate) {
|
|
144
|
+
return { ok: false, output: createFileRejectedError(path) };
|
|
145
|
+
}
|
|
146
|
+
if (existing && !state.readPaths.has(canonicalPath)) {
|
|
147
|
+
return { ok: false, output: readBeforeWriteError('write_file', path) };
|
|
148
|
+
}
|
|
149
|
+
await writeTextFile(workspace, path, content);
|
|
150
|
+
state.readPaths.add(canonicalPath);
|
|
151
|
+
return { ok: true, output: `Wrote file: ${path}` };
|
|
152
|
+
}
|
|
153
|
+
case 'apply_patch': {
|
|
154
|
+
const path = String(toolCall.input.path ?? '');
|
|
155
|
+
const search = String(toolCall.input.search ?? '');
|
|
156
|
+
const replace = String(toolCall.input.replace ?? '');
|
|
157
|
+
const replaceAll = Boolean(toolCall.input.replaceAll ?? false);
|
|
158
|
+
const existing = await fileExists(workspace, path);
|
|
159
|
+
const canonicalPath = resolveWorkspacePath(workspace, path);
|
|
160
|
+
if (!existing) {
|
|
161
|
+
return { ok: false, output: `apply_patch rejected: '${path}' does not exist.` };
|
|
162
|
+
}
|
|
163
|
+
if (existing && !state.readPaths.has(canonicalPath)) {
|
|
164
|
+
return { ok: false, output: readBeforeWriteError('apply_patch', path) };
|
|
165
|
+
}
|
|
166
|
+
const output = await applyTextPatch(workspace, path, search, replace, replaceAll);
|
|
167
|
+
state.readPaths.add(canonicalPath);
|
|
168
|
+
return { ok: true, output };
|
|
169
|
+
}
|
|
170
|
+
case 'list_files': {
|
|
171
|
+
const path = String(toolCall.input.path ?? '.');
|
|
172
|
+
const files = await listFiles(workspace, path);
|
|
173
|
+
return { ok: true, output: files.join('\n') || '(empty directory)' };
|
|
174
|
+
}
|
|
175
|
+
case 'run_shell': {
|
|
176
|
+
const command = String(toolCall.input.command ?? '');
|
|
177
|
+
if (looksDestructiveCommand(command)) {
|
|
178
|
+
const approved = (await options.onSensitiveAction?.({ tool: 'run_shell', command })) ?? false;
|
|
179
|
+
if (!approved) {
|
|
180
|
+
return { ok: false, output: shellDangerRejectedError(command) };
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
const output = await runShell(command, workspace);
|
|
184
|
+
return { ok: true, output };
|
|
185
|
+
}
|
|
186
|
+
default:
|
|
187
|
+
return { ok: false, output: `Unknown tool: ${String(toolCall.tool)}` };
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
192
|
+
return { ok: false, output: message };
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
export async function runAgentTask(task, options = {}) {
|
|
196
|
+
const config = await loadConfig();
|
|
197
|
+
const resolvedModel = resolveModel(config.model);
|
|
198
|
+
const provider = providerFromConfig(config.provider, resolvedModel, config.baseURL);
|
|
199
|
+
const workspace = config.workspace;
|
|
200
|
+
const maxSteps = options.maxSteps ?? 8;
|
|
201
|
+
options.onEvent?.({
|
|
202
|
+
type: 'start',
|
|
203
|
+
provider: config.provider,
|
|
204
|
+
model: resolvedModel,
|
|
205
|
+
workspace
|
|
206
|
+
});
|
|
207
|
+
const messages = [
|
|
208
|
+
{
|
|
209
|
+
role: 'system',
|
|
210
|
+
content: [
|
|
211
|
+
`You are a coding agent running in workspace: ${workspace}.`,
|
|
212
|
+
'When you need to operate files or shell, respond with ONLY JSON:',
|
|
213
|
+
'{"type":"tool_call","tool":"read_file|write_file|apply_patch|list_files|run_shell","input":{...}}',
|
|
214
|
+
'Available tools:',
|
|
215
|
+
'- read_file: {"path":"relative/path"}',
|
|
216
|
+
'- write_file: {"path":"relative/path","content":"...","allowCreate":false} (single-file full rewrite)',
|
|
217
|
+
'- apply_patch: {"path":"relative/path","search":"old text","replace":"new text","replaceAll":false}',
|
|
218
|
+
'- list_files: {"path":"relative/path optional"}',
|
|
219
|
+
'- run_shell: {"command":"..."}',
|
|
220
|
+
'Rules:',
|
|
221
|
+
'- Existing files MUST be read_file before write_file/apply_patch.',
|
|
222
|
+
'- New file creation is blocked by default.',
|
|
223
|
+
'- To create files, write_file input.allowCreate=true is required.',
|
|
224
|
+
'- Destructive shell commands (e.g., rm/rmdir/unlink/del/git reset --hard/git clean) are blocked.',
|
|
225
|
+
'- You may call multiple read_file tools in one response.',
|
|
226
|
+
'- At most one mutation tool (write_file or apply_patch) per response.',
|
|
227
|
+
'Use relative paths. Never wrap JSON with extra prose when calling tools.',
|
|
228
|
+
'When finished, return a normal natural-language summary.'
|
|
229
|
+
].join('\n')
|
|
230
|
+
},
|
|
231
|
+
{ role: 'user', content: task }
|
|
232
|
+
];
|
|
233
|
+
const state = { readPaths: new Set() };
|
|
234
|
+
for (let step = 0; step < maxSteps; step += 1) {
|
|
235
|
+
const assistantText = await provider.chat(messages);
|
|
236
|
+
options.onEvent?.({ type: 'model_response', step, content: assistantText });
|
|
237
|
+
const toolCalls = parseToolCalls(assistantText);
|
|
238
|
+
if (toolCalls.length === 0) {
|
|
239
|
+
options.onEvent?.({ type: 'final', step, content: assistantText });
|
|
240
|
+
return assistantText;
|
|
241
|
+
}
|
|
242
|
+
messages.push({ role: 'assistant', content: assistantText });
|
|
243
|
+
if (mutationCount(toolCalls) > 1) {
|
|
244
|
+
const output = 'Batch rejected: only one mutation tool (write_file/apply_patch) is allowed per step.';
|
|
245
|
+
options.onEvent?.({
|
|
246
|
+
type: 'tool_result',
|
|
247
|
+
step,
|
|
248
|
+
tool: toolCalls.find((call) => call.tool === 'write_file' || call.tool === 'apply_patch')?.tool ?? 'write_file',
|
|
249
|
+
ok: false,
|
|
250
|
+
output
|
|
251
|
+
});
|
|
252
|
+
messages.push({
|
|
253
|
+
role: 'user',
|
|
254
|
+
content: `TOOL_RESULT ${JSON.stringify({ tool: 'batch_validation', ok: false, output })}`
|
|
255
|
+
});
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
for (const toolCall of toolCalls) {
|
|
259
|
+
options.onEvent?.({ type: 'tool_call', step, tool: toolCall.tool, input: toolCall.input });
|
|
260
|
+
const result = await executeTool(toolCall, workspace, state, options);
|
|
261
|
+
options.onEvent?.({
|
|
262
|
+
type: 'tool_result',
|
|
263
|
+
step,
|
|
264
|
+
tool: toolCall.tool,
|
|
265
|
+
ok: result.ok,
|
|
266
|
+
output: result.output
|
|
267
|
+
});
|
|
268
|
+
messages.push({
|
|
269
|
+
role: 'user',
|
|
270
|
+
content: `TOOL_RESULT ${JSON.stringify({ tool: toolCall.tool, ...result })}`
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
options.onEvent?.({ type: 'max_steps', step: maxSteps });
|
|
275
|
+
return 'Stopped after maximum tool steps. Please refine the task and retry.';
|
|
276
|
+
}
|
|
277
|
+
//# sourceMappingURL=agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/core/agent.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,aAAa,CAAA;AAEnC,MAAM,OAAO,CAAC,EAAC,WAAW,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-provider.js","sourceRoot":"","sources":["../../src/providers/mock-provider.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,YAAY;IACd,IAAI,GAAG,MAAM,CAAA;IAEtB,KAAK,CAAC,IAAI,CAAC,QAAuB;QAChC,MAAM,IAAI,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;QAC5B,IAAI,CAAC,IAAI;YAAE,OAAO,oBAAoB,CAAA;QACtC,OAAO,kBAAkB,IAAI,CAAC,OAAO,EAAE,CAAA;IACzC,CAAC;CACF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ChatMessage, LLMProvider } from './types.js';
|
|
2
|
+
type OpenAIProviderOptions = {
|
|
3
|
+
apiKey: string;
|
|
4
|
+
model: string;
|
|
5
|
+
baseUrl?: string;
|
|
6
|
+
};
|
|
7
|
+
export declare class OpenAIProvider implements LLMProvider {
|
|
8
|
+
readonly name = "openai";
|
|
9
|
+
private readonly client;
|
|
10
|
+
private readonly model;
|
|
11
|
+
constructor(options: OpenAIProviderOptions);
|
|
12
|
+
chat(messages: ChatMessage[]): Promise<string>;
|
|
13
|
+
}
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import OpenAI from 'openai';
|
|
2
|
+
function safeJsonSnippet(value) {
|
|
3
|
+
try {
|
|
4
|
+
return JSON.stringify(value).slice(0, 500);
|
|
5
|
+
}
|
|
6
|
+
catch {
|
|
7
|
+
return '[unserializable response]';
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function extractText(data) {
|
|
11
|
+
const messageContent = data?.choices?.[0]?.message?.content;
|
|
12
|
+
if (typeof messageContent === 'string' && messageContent.trim()) {
|
|
13
|
+
return messageContent;
|
|
14
|
+
}
|
|
15
|
+
if (Array.isArray(messageContent)) {
|
|
16
|
+
const joined = messageContent
|
|
17
|
+
.map((part) => {
|
|
18
|
+
if (typeof part === 'string')
|
|
19
|
+
return part;
|
|
20
|
+
if (typeof part?.text === 'string')
|
|
21
|
+
return part.text;
|
|
22
|
+
return '';
|
|
23
|
+
})
|
|
24
|
+
.join('')
|
|
25
|
+
.trim();
|
|
26
|
+
if (joined)
|
|
27
|
+
return joined;
|
|
28
|
+
}
|
|
29
|
+
const textField = data?.choices?.[0]?.text;
|
|
30
|
+
if (typeof textField === 'string' && textField.trim()) {
|
|
31
|
+
return textField;
|
|
32
|
+
}
|
|
33
|
+
if (typeof data?.output_text === 'string' && data.output_text.trim()) {
|
|
34
|
+
return data.output_text;
|
|
35
|
+
}
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
export class OpenAIProvider {
|
|
39
|
+
name = 'openai';
|
|
40
|
+
client;
|
|
41
|
+
model;
|
|
42
|
+
constructor(options) {
|
|
43
|
+
this.model = options.model;
|
|
44
|
+
const rawBaseUrl = options.baseUrl ?? 'https://api.openai.com/v1';
|
|
45
|
+
const baseURL = rawBaseUrl.replace(/\/+$/, '');
|
|
46
|
+
this.client = new OpenAI({
|
|
47
|
+
apiKey: options.apiKey,
|
|
48
|
+
baseURL
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
async chat(messages) {
|
|
52
|
+
const completion = await this.client.chat.completions.create({
|
|
53
|
+
model: this.model,
|
|
54
|
+
messages
|
|
55
|
+
});
|
|
56
|
+
const content = extractText(completion);
|
|
57
|
+
if (!content) {
|
|
58
|
+
throw new Error(`OpenAI API returned no readable text. Response snippet: ${safeJsonSnippet(completion)}`);
|
|
59
|
+
}
|
|
60
|
+
return content;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=openai-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-provider.js","sourceRoot":"","sources":["../../src/providers/openai-provider.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAA;AAS3B,SAAS,eAAe,CAAC,KAAc;IACrC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,2BAA2B,CAAA;IACpC,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,IAAS;IAC5B,MAAM,cAAc,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAA;IAC3D,IAAI,OAAO,cAAc,KAAK,QAAQ,IAAI,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC;QAChE,OAAO,cAAc,CAAA;IACvB,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;QAClC,MAAM,MAAM,GAAG,cAAc;aAC1B,GAAG,CAAC,CAAC,IAAS,EAAE,EAAE;YACjB,IAAI,OAAO,IAAI,KAAK,QAAQ;gBAAE,OAAO,IAAI,CAAA;YACzC,IAAI,OAAO,IAAI,EAAE,IAAI,KAAK,QAAQ;gBAAE,OAAO,IAAI,CAAC,IAAI,CAAA;YACpD,OAAO,EAAE,CAAA;QACX,CAAC,CAAC;aACD,IAAI,CAAC,EAAE,CAAC;aACR,IAAI,EAAE,CAAA;QACT,IAAI,MAAM;YAAE,OAAO,MAAM,CAAA;IAC3B,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAA;IAC1C,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;QACtD,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,IAAI,OAAO,IAAI,EAAE,WAAW,KAAK,QAAQ,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC;QACrE,OAAO,IAAI,CAAC,WAAW,CAAA;IACzB,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,MAAM,OAAO,cAAc;IAChB,IAAI,GAAG,QAAQ,CAAA;IACP,MAAM,CAAQ;IACd,KAAK,CAAQ;IAE9B,YAAY,OAA8B;QACxC,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAA;QAC1B,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,IAAI,2BAA2B,CAAA;QACjE,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;QAC9C,IAAI,CAAC,MAAM,GAAG,IAAI,MAAM,CAAC;YACvB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,OAAO;SACR,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,QAAuB;QAChC,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;YAC3D,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,QAAQ;SACT,CAAC,CAAA;QACF,MAAM,OAAO,GAAG,WAAW,CAAC,UAAU,CAAC,CAAA;QAEvC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,2DAA2D,eAAe,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;QAC3G,CAAC;QAED,OAAO,OAAO,CAAA;IAChB,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function resolveWorkspacePath(workspace: string, path: string): string;
|
|
2
|
+
export declare function fileExists(workspace: string, path: string): Promise<boolean>;
|
|
3
|
+
export declare function readTextFile(workspace: string, path: string): Promise<string>;
|
|
4
|
+
export declare function writeTextFile(workspace: string, path: string, content: string): Promise<void>;
|
|
5
|
+
export declare function listFiles(workspace: string, path?: string): Promise<string[]>;
|
|
6
|
+
export declare function applyTextPatch(workspace: string, path: string, search: string, replace: string, replaceAll?: boolean): Promise<string>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { mkdir, readFile, readdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname, resolve, sep } from 'node:path';
|
|
3
|
+
import { access, constants } from 'node:fs';
|
|
4
|
+
function assertInsideWorkspace(workspace, inputPath) {
|
|
5
|
+
const workspaceRoot = resolve(workspace);
|
|
6
|
+
const fullPath = resolve(workspaceRoot, inputPath);
|
|
7
|
+
const inWorkspace = fullPath === workspaceRoot || fullPath.startsWith(`${workspaceRoot}${sep}`);
|
|
8
|
+
if (!inWorkspace) {
|
|
9
|
+
throw new Error(`Path '${inputPath}' is outside workspace.`);
|
|
10
|
+
}
|
|
11
|
+
return fullPath;
|
|
12
|
+
}
|
|
13
|
+
export function resolveWorkspacePath(workspace, path) {
|
|
14
|
+
return assertInsideWorkspace(workspace, path);
|
|
15
|
+
}
|
|
16
|
+
export async function fileExists(workspace, path) {
|
|
17
|
+
const fullPath = assertInsideWorkspace(workspace, path);
|
|
18
|
+
return new Promise((resolvePromise) => {
|
|
19
|
+
access(fullPath, constants.F_OK, (error) => {
|
|
20
|
+
resolvePromise(!error);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
export async function readTextFile(workspace, path) {
|
|
25
|
+
const fullPath = assertInsideWorkspace(workspace, path);
|
|
26
|
+
return readFile(fullPath, 'utf8');
|
|
27
|
+
}
|
|
28
|
+
export async function writeTextFile(workspace, path, content) {
|
|
29
|
+
const fullPath = assertInsideWorkspace(workspace, path);
|
|
30
|
+
await mkdir(dirname(fullPath), { recursive: true });
|
|
31
|
+
await writeFile(fullPath, content, 'utf8');
|
|
32
|
+
}
|
|
33
|
+
export async function listFiles(workspace, path = '.') {
|
|
34
|
+
const fullPath = assertInsideWorkspace(workspace, path);
|
|
35
|
+
return readdir(fullPath);
|
|
36
|
+
}
|
|
37
|
+
export async function applyTextPatch(workspace, path, search, replace, replaceAll = false) {
|
|
38
|
+
if (!search) {
|
|
39
|
+
throw new Error('apply_patch requires non-empty "search".');
|
|
40
|
+
}
|
|
41
|
+
const original = await readTextFile(workspace, path);
|
|
42
|
+
if (!original.includes(search)) {
|
|
43
|
+
throw new Error(`apply_patch could not find target text in ${path}.`);
|
|
44
|
+
}
|
|
45
|
+
const updated = replaceAll ? original.split(search).join(replace) : original.replace(search, replace);
|
|
46
|
+
await writeTextFile(workspace, path, updated);
|
|
47
|
+
return `Patched file: ${path}`;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=filesystem.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filesystem.js","sourceRoot":"","sources":["../../src/tools/filesystem.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runShell(command: string, cwd?: string): Promise<string>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { execa } from 'execa';
|
|
2
|
+
export async function runShell(command, cwd = process.cwd()) {
|
|
3
|
+
const { stdout, stderr, exitCode } = await execa('zsh', ['-lc', command], { cwd, reject: false });
|
|
4
|
+
const header = `exit_code=${exitCode}`;
|
|
5
|
+
if (!stdout && !stderr)
|
|
6
|
+
return '(no output)';
|
|
7
|
+
return [header, stdout, stderr].filter(Boolean).join('\n');
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=shell.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell.js","sourceRoot":"","sources":["../../src/tools/shell.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,EAAC,MAAM,OAAO,CAAA;AAE3B,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,OAAe,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IACjE,MAAM,EAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAC,GAAG,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,EAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAC,CAAC,CAAA;IAC7F,MAAM,MAAM,GAAG,aAAa,QAAQ,EAAE,CAAA;IACtC,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM;QAAE,OAAO,aAAa,CAAA;IAC5C,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC5D,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sworddut/myclaw",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "A CLI coding agent inspired by Claude Code",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"myclaw": "bin/run.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"bin",
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc -p tsconfig.json",
|
|
16
|
+
"dev": "tsx bin/dev.js",
|
|
17
|
+
"test": "vitest run",
|
|
18
|
+
"lint": "tsc --noEmit"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@oclif/core": "^4.2.9",
|
|
22
|
+
"better-sqlite3": "^11.8.1",
|
|
23
|
+
"cosmiconfig": "^9.0.0",
|
|
24
|
+
"dotenv": "^16.5.0",
|
|
25
|
+
"execa": "^9.6.0",
|
|
26
|
+
"openai": "^6.22.0",
|
|
27
|
+
"zod": "^3.24.2"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/node": "^22.13.10",
|
|
31
|
+
"tsx": "^4.19.3",
|
|
32
|
+
"typescript": "^5.8.2",
|
|
33
|
+
"vitest": "^3.0.9"
|
|
34
|
+
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=20"
|
|
37
|
+
},
|
|
38
|
+
"oclif": {
|
|
39
|
+
"commands": "./dist/commands",
|
|
40
|
+
"topicSeparator": " "
|
|
41
|
+
}
|
|
42
|
+
}
|