@jc20231028/local-code-agent 0.1.0 → 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/src/config.js CHANGED
@@ -1,106 +1,106 @@
1
- import fs from "node:fs/promises";
2
- import path from "node:path";
3
-
4
- const DEFAULTS = {
5
- provider: "",
6
- model: "",
7
- workspace: process.cwd(),
8
- ollamaBaseUrl: "http://127.0.0.1:11434",
9
- lmStudioBaseUrl: "http://127.0.0.1:1234",
10
- maxSteps: 12,
11
- allowCommands: false,
12
- temperature: 0.2
13
- };
14
-
15
- export async function loadConfig(cwd, cliOptions = {}) {
16
- const configPath = path.join(cwd, ".local-code.json");
17
- const fileConfig = await readConfigFile(configPath);
18
-
19
- const merged = {
20
- ...DEFAULTS,
21
- ...fileConfig,
22
- ...compactObject(readEnvConfig()),
23
- ...compactObject(cliOptions)
24
- };
25
-
26
- merged.workspace = path.resolve(cwd, merged.workspace);
27
- merged.maxSteps = Number(merged.maxSteps) || DEFAULTS.maxSteps;
28
- merged.temperature = Number(merged.temperature);
29
- if (Number.isNaN(merged.temperature)) {
30
- merged.temperature = DEFAULTS.temperature;
31
- }
32
- merged.configPath = configPath;
33
- merged.statePath = path.join(cwd, ".local-code-state.json");
34
-
35
- return merged;
36
- }
37
-
38
- export async function saveConfigSelections(configPath, selections) {
39
- const current = await readConfigFile(configPath);
40
- const next = {
41
- ...current,
42
- ...compactObject(selections)
43
- };
44
-
45
- await fs.writeFile(configPath, `${JSON.stringify(next, null, 2)}\n`, "utf8");
46
- }
47
-
48
- export async function loadAppState(statePath) {
49
- return readJsonFile(statePath);
50
- }
51
-
52
- export async function saveAppState(statePath, patch) {
53
- const current = await readJsonFile(statePath);
54
- const next = {
55
- ...current,
56
- ...compactObject(patch)
57
- };
58
-
59
- await fs.writeFile(statePath, `${JSON.stringify(next, null, 2)}\n`, "utf8");
60
- }
61
-
62
- function readEnvConfig() {
63
- return {
64
- provider: process.env.LOCAL_CODE_PROVIDER,
65
- model: process.env.LOCAL_CODE_MODEL,
66
- ollamaBaseUrl: process.env.OLLAMA_BASE_URL,
67
- lmStudioBaseUrl: process.env.LM_STUDIO_BASE_URL,
68
- allowCommands: parseBoolean(process.env.LOCAL_CODE_ALLOW_COMMANDS)
69
- };
70
- }
71
-
72
- function parseBoolean(value) {
73
- if (value == null || value === "") {
74
- return undefined;
75
- }
76
-
77
- return ["1", "true", "yes", "on"].includes(String(value).toLowerCase());
78
- }
79
-
80
- function compactObject(value) {
81
- return Object.fromEntries(
82
- Object.entries(value).filter(([, entryValue]) => entryValue !== undefined)
83
- );
84
- }
85
-
86
- async function readConfigFile(configPath) {
87
- const parsed = await readJsonFile(configPath);
88
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
89
- return parsed;
90
- }
91
-
92
- return {};
93
- }
94
-
95
- async function readJsonFile(filePath) {
96
- try {
97
- const raw = await fs.readFile(filePath, "utf8");
98
- return JSON.parse(raw);
99
- } catch (error) {
100
- if (error && error.code !== "ENOENT") {
101
- throw new Error(`Failed to read file: ${filePath}\n${error.message}`);
102
- }
103
- }
104
-
105
- return {};
106
- }
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+
4
+ const DEFAULTS = {
5
+ provider: "",
6
+ model: "",
7
+ workspace: process.cwd(),
8
+ ollamaBaseUrl: "http://127.0.0.1:11434",
9
+ lmStudioBaseUrl: "http://127.0.0.1:1234",
10
+ maxSteps: 12,
11
+ allowCommands: false,
12
+ temperature: 0.2
13
+ };
14
+
15
+ export async function loadConfig(cwd, cliOptions = {}) {
16
+ const configPath = path.join(cwd, ".local-code.json");
17
+ const fileConfig = await readConfigFile(configPath);
18
+
19
+ const merged = {
20
+ ...DEFAULTS,
21
+ ...fileConfig,
22
+ ...compactObject(readEnvConfig()),
23
+ ...compactObject(cliOptions)
24
+ };
25
+
26
+ merged.workspace = path.resolve(cwd, merged.workspace);
27
+ merged.maxSteps = Number(merged.maxSteps) || DEFAULTS.maxSteps;
28
+ merged.temperature = Number(merged.temperature);
29
+ if (Number.isNaN(merged.temperature)) {
30
+ merged.temperature = DEFAULTS.temperature;
31
+ }
32
+ merged.configPath = configPath;
33
+ merged.statePath = path.join(cwd, ".local-code-state.json");
34
+
35
+ return merged;
36
+ }
37
+
38
+ export async function saveConfigSelections(configPath, selections) {
39
+ const current = await readConfigFile(configPath);
40
+ const next = {
41
+ ...current,
42
+ ...compactObject(selections)
43
+ };
44
+
45
+ await fs.writeFile(configPath, `${JSON.stringify(next, null, 2)}\n`, "utf8");
46
+ }
47
+
48
+ export async function loadAppState(statePath) {
49
+ return readJsonFile(statePath);
50
+ }
51
+
52
+ export async function saveAppState(statePath, patch) {
53
+ const current = await readJsonFile(statePath);
54
+ const next = {
55
+ ...current,
56
+ ...compactObject(patch)
57
+ };
58
+
59
+ await fs.writeFile(statePath, `${JSON.stringify(next, null, 2)}\n`, "utf8");
60
+ }
61
+
62
+ function readEnvConfig() {
63
+ return {
64
+ provider: process.env.LOCAL_CODE_PROVIDER,
65
+ model: process.env.LOCAL_CODE_MODEL,
66
+ ollamaBaseUrl: process.env.OLLAMA_BASE_URL,
67
+ lmStudioBaseUrl: process.env.LM_STUDIO_BASE_URL,
68
+ allowCommands: parseBoolean(process.env.LOCAL_CODE_ALLOW_COMMANDS)
69
+ };
70
+ }
71
+
72
+ function parseBoolean(value) {
73
+ if (value == null || value === "") {
74
+ return undefined;
75
+ }
76
+
77
+ return ["1", "true", "yes", "on"].includes(String(value).toLowerCase());
78
+ }
79
+
80
+ function compactObject(value) {
81
+ return Object.fromEntries(
82
+ Object.entries(value).filter(([, entryValue]) => entryValue !== undefined)
83
+ );
84
+ }
85
+
86
+ async function readConfigFile(configPath) {
87
+ const parsed = await readJsonFile(configPath);
88
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
89
+ return parsed;
90
+ }
91
+
92
+ return {};
93
+ }
94
+
95
+ async function readJsonFile(filePath) {
96
+ try {
97
+ const raw = await fs.readFile(filePath, "utf8");
98
+ return JSON.parse(raw);
99
+ } catch (error) {
100
+ if (error && error.code !== "ENOENT") {
101
+ throw new Error(`Failed to read file: ${filePath}\n${error.message}`);
102
+ }
103
+ }
104
+
105
+ return {};
106
+ }
@@ -1,49 +1,49 @@
1
- export function createLmStudioProvider(config) {
2
- return {
3
- name: "lmstudio",
4
- async chat(messages) {
5
- ensureModel(config);
6
- const response = await fetch(joinUrl(config.lmStudioBaseUrl, "/v1/chat/completions"), {
7
- method: "POST",
8
- headers: { "content-type": "application/json" },
9
- body: JSON.stringify({
10
- model: config.model,
11
- messages,
12
- temperature: config.temperature
13
- })
14
- });
15
-
16
- if (!response.ok) {
17
- throw new Error(`LM Studio request failed: ${response.status} ${response.statusText}`);
18
- }
19
-
20
- const data = await response.json();
21
- return {
22
- content: data?.choices?.[0]?.message?.content ?? ""
23
- };
24
- },
25
- async listModels() {
26
- const response = await fetch(joinUrl(config.lmStudioBaseUrl, "/v1/models"));
27
- if (!response.ok) {
28
- throw new Error(`LM Studio list models failed: ${response.status} ${response.statusText}`);
29
- }
30
-
31
- const data = await response.json();
32
- return (data.data ?? []).map((item) => item.id);
33
- }
34
- };
35
- }
36
-
37
- function ensureModel(config) {
38
- if (!config.model) {
39
- throw new Error("A model is required. Set --model or LOCAL_CODE_MODEL.");
40
- }
41
- }
42
-
43
- function joinUrl(baseUrl, pathname) {
44
- return new URL(pathname, ensureTrailingSlash(baseUrl)).toString();
45
- }
46
-
47
- function ensureTrailingSlash(value) {
48
- return value.endsWith("/") ? value : `${value}/`;
49
- }
1
+ export function createLmStudioProvider(config) {
2
+ return {
3
+ name: "lmstudio",
4
+ async chat(messages) {
5
+ ensureModel(config);
6
+ const response = await fetch(joinUrl(config.lmStudioBaseUrl, "/v1/chat/completions"), {
7
+ method: "POST",
8
+ headers: { "content-type": "application/json" },
9
+ body: JSON.stringify({
10
+ model: config.model,
11
+ messages,
12
+ temperature: config.temperature
13
+ })
14
+ });
15
+
16
+ if (!response.ok) {
17
+ throw new Error(`LM Studio request failed: ${response.status} ${response.statusText}`);
18
+ }
19
+
20
+ const data = await response.json();
21
+ return {
22
+ content: data?.choices?.[0]?.message?.content ?? ""
23
+ };
24
+ },
25
+ async listModels() {
26
+ const response = await fetch(joinUrl(config.lmStudioBaseUrl, "/v1/models"));
27
+ if (!response.ok) {
28
+ throw new Error(`LM Studio list models failed: ${response.status} ${response.statusText}`);
29
+ }
30
+
31
+ const data = await response.json();
32
+ return (data.data ?? []).map((item) => item.id);
33
+ }
34
+ };
35
+ }
36
+
37
+ function ensureModel(config) {
38
+ if (!config.model) {
39
+ throw new Error("A model is required. Set --model or LOCAL_CODE_MODEL.");
40
+ }
41
+ }
42
+
43
+ function joinUrl(baseUrl, pathname) {
44
+ return new URL(pathname, ensureTrailingSlash(baseUrl)).toString();
45
+ }
46
+
47
+ function ensureTrailingSlash(value) {
48
+ return value.endsWith("/") ? value : `${value}/`;
49
+ }
@@ -1,52 +1,52 @@
1
- export function createOllamaProvider(config) {
2
- return {
3
- name: "ollama",
4
- async chat(messages) {
5
- ensureModel(config);
6
- const response = await fetch(joinUrl(config.ollamaBaseUrl, "/api/chat"), {
7
- method: "POST",
8
- headers: { "content-type": "application/json" },
9
- body: JSON.stringify({
10
- model: config.model,
11
- messages,
12
- stream: false,
13
- options: {
14
- temperature: config.temperature
15
- }
16
- })
17
- });
18
-
19
- if (!response.ok) {
20
- throw new Error(`Ollama request failed: ${response.status} ${response.statusText}`);
21
- }
22
-
23
- const data = await response.json();
24
- return {
25
- content: data?.message?.content ?? ""
26
- };
27
- },
28
- async listModels() {
29
- const response = await fetch(joinUrl(config.ollamaBaseUrl, "/api/tags"));
30
- if (!response.ok) {
31
- throw new Error(`Ollama list models failed: ${response.status} ${response.statusText}`);
32
- }
33
-
34
- const data = await response.json();
35
- return (data.models ?? []).map((item) => item.name);
36
- }
37
- };
38
- }
39
-
40
- function ensureModel(config) {
41
- if (!config.model) {
42
- throw new Error("A model is required. Set --model or LOCAL_CODE_MODEL.");
43
- }
44
- }
45
-
46
- function joinUrl(baseUrl, pathname) {
47
- return new URL(pathname, ensureTrailingSlash(baseUrl)).toString();
48
- }
49
-
50
- function ensureTrailingSlash(value) {
51
- return value.endsWith("/") ? value : `${value}/`;
52
- }
1
+ export function createOllamaProvider(config) {
2
+ return {
3
+ name: "ollama",
4
+ async chat(messages) {
5
+ ensureModel(config);
6
+ const response = await fetch(joinUrl(config.ollamaBaseUrl, "/api/chat"), {
7
+ method: "POST",
8
+ headers: { "content-type": "application/json" },
9
+ body: JSON.stringify({
10
+ model: config.model,
11
+ messages,
12
+ stream: false,
13
+ options: {
14
+ temperature: config.temperature
15
+ }
16
+ })
17
+ });
18
+
19
+ if (!response.ok) {
20
+ throw new Error(`Ollama request failed: ${response.status} ${response.statusText}`);
21
+ }
22
+
23
+ const data = await response.json();
24
+ return {
25
+ content: data?.message?.content ?? ""
26
+ };
27
+ },
28
+ async listModels() {
29
+ const response = await fetch(joinUrl(config.ollamaBaseUrl, "/api/tags"));
30
+ if (!response.ok) {
31
+ throw new Error(`Ollama list models failed: ${response.status} ${response.statusText}`);
32
+ }
33
+
34
+ const data = await response.json();
35
+ return (data.models ?? []).map((item) => item.name);
36
+ }
37
+ };
38
+ }
39
+
40
+ function ensureModel(config) {
41
+ if (!config.model) {
42
+ throw new Error("A model is required. Set --model or LOCAL_CODE_MODEL.");
43
+ }
44
+ }
45
+
46
+ function joinUrl(baseUrl, pathname) {
47
+ return new URL(pathname, ensureTrailingSlash(baseUrl)).toString();
48
+ }
49
+
50
+ function ensureTrailingSlash(value) {
51
+ return value.endsWith("/") ? value : `${value}/`;
52
+ }