itermbot 1.0.18 → 1.0.19
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
CHANGED
|
@@ -1,38 +1,10 @@
|
|
|
1
1
|
# iTermBot
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 介绍
|
|
4
4
|
|
|
5
|
-
`
|
|
5
|
+
`itermbot` 是一个运行在 iTerm2 环境中的终端智能体应用,基于 `@botbotgo/agent` 及相关框架包构建。
|
|
6
6
|
|
|
7
|
-
##
|
|
8
|
-
|
|
9
|
-
This repo is an app, not a reusable library. Its public interface is the executable entry:
|
|
10
|
-
|
|
11
|
-
| Interface | Type | Purpose |
|
|
12
|
-
| --- | --- | --- |
|
|
13
|
-
| `itermbot` | CLI | Start the app from `dist/index.js`. |
|
|
14
|
-
|
|
15
|
-
## Configuration
|
|
16
|
-
|
|
17
|
-
Main config files:
|
|
18
|
-
|
|
19
|
-
- `config/app.yaml`
|
|
20
|
-
- `config/agent.yaml`
|
|
21
|
-
- `config/model.yaml`
|
|
22
|
-
- `config/toolkit.yaml`
|
|
23
|
-
- `config/memory.yaml`
|
|
24
|
-
- `config/task-manager.yaml`
|
|
25
|
-
|
|
26
|
-
`config/app.yaml` holds app-level behavior such as prompt templates and local startup settings. The model, memory, tool, and runtime files are delegated to the corresponding framework repos.
|
|
27
|
-
`config/task-manager.yaml` defines the application task manager behavior and persistence file.
|
|
28
|
-
|
|
29
|
-
Task manager commands in CLI:
|
|
30
|
-
|
|
31
|
-
- `task list`
|
|
32
|
-
- `task add <description>`
|
|
33
|
-
- `task run [task-id]`
|
|
34
|
-
|
|
35
|
-
## Usage
|
|
7
|
+
## 如何使用
|
|
36
8
|
|
|
37
9
|
```bash
|
|
38
10
|
cd apps/itermbot
|
|
@@ -41,10 +13,27 @@ npm run build
|
|
|
41
13
|
npm start
|
|
42
14
|
```
|
|
43
15
|
|
|
44
|
-
|
|
16
|
+
其他模式:
|
|
45
17
|
|
|
46
18
|
```bash
|
|
47
19
|
npm run react
|
|
48
20
|
npm run deep
|
|
49
|
-
npm run test:llm
|
|
50
21
|
```
|
|
22
|
+
|
|
23
|
+
## 如何设置
|
|
24
|
+
|
|
25
|
+
- Node.js >= 22
|
|
26
|
+
- 需在 iTerm2 内运行(依赖 `TERM_PROGRAM=iTerm.app` 或 `ITERM_SESSION_ID`)
|
|
27
|
+
- 主要配置文件:
|
|
28
|
+
- `config/app.yaml`
|
|
29
|
+
- `config/agent.yaml`
|
|
30
|
+
- `config/model.yaml`
|
|
31
|
+
- `config/memory.yaml`
|
|
32
|
+
- `config/toolkit.yaml`
|
|
33
|
+
- `config/task-manager.yaml`
|
|
34
|
+
|
|
35
|
+
## 暴露 API
|
|
36
|
+
|
|
37
|
+
- 可执行命令:`itermbot`
|
|
38
|
+
- CLI 入口:`node dist/index.js [react|deep] [prompt]`
|
|
39
|
+
- npm 脚本接口:`npm run start`、`npm run react`、`npm run deep`、`npm run test:llm`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "itermbot",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.19",
|
|
4
4
|
"description": "iTermBot: ReAct agent (LangChain) + DeepAgent (DeepAgents) using BotBotGo packages",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"iTermbot": "dist/index.js"
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
|
-
"preinstall": "node scripts/resolve-deps.
|
|
14
|
-
"prebuild": "node scripts/build-internal-deps.mjs",
|
|
13
|
+
"preinstall": "node -e \"const fs=require('fs'); const {execSync}=require('child_process'); if (fs.existsSync('../../scripts/run-resolve-deps.sh')) { execSync('bash ../../scripts/run-resolve-deps.sh .', { stdio: 'inherit' }); } else { console.log('Skipping workspace resolve-deps helper'); }\"",
|
|
14
|
+
"prebuild": "node ./scripts/run-iterm-build-internal-deps.mjs .",
|
|
15
15
|
"build": "tsc -p config/tsconfig.json",
|
|
16
16
|
"dev": "tsc -p config/tsconfig.json --watch",
|
|
17
17
|
"start": "node dist/index.js",
|
|
@@ -22,16 +22,16 @@
|
|
|
22
22
|
"test": "npm run typecheck && npm run build && npm run test:policy",
|
|
23
23
|
"test:policy": "npm run build && node --test --test-concurrency=1 test/unit/*.test.mjs test/unit/**/*.test.mjs test/integration/*.test.mjs",
|
|
24
24
|
"test:live": "npm run build && node --test --test-concurrency=1 test/integration/live-iterm-llm.integration.test.mjs",
|
|
25
|
-
"test:llm": "node scripts/test-llm.mjs",
|
|
25
|
+
"test:llm": "node ../../scripts/run-iterm-test-llm.mjs .",
|
|
26
26
|
"release": "semantic-release"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@botbotgo/common": "
|
|
30
|
-
"@botbotgo/memory": "
|
|
31
|
-
"@botbotgo/model": "
|
|
32
|
-
"@botbotgo/agent": "
|
|
33
|
-
"@botbotgo/toolkit": "
|
|
34
|
-
"@botbotgo/toolkit-builtin": "
|
|
29
|
+
"@botbotgo/common": "1.0.15",
|
|
30
|
+
"@botbotgo/memory": "1.0.64",
|
|
31
|
+
"@botbotgo/model": "1.0.9",
|
|
32
|
+
"@botbotgo/agent": "1.1.20",
|
|
33
|
+
"@botbotgo/toolkit": "1.0.122",
|
|
34
|
+
"@botbotgo/toolkit-builtin": "0.0.114",
|
|
35
35
|
"@langchain/core": "1.1.31",
|
|
36
36
|
"@langchain/langgraph": "1.2.0",
|
|
37
37
|
"@langchain/langgraph-checkpoint": "1.0.0",
|
package/scripts/resolve-deps.js
CHANGED
|
@@ -1,49 +1,91 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
|
-
import { dirname, resolve } from "node:path";
|
|
5
|
-
import {
|
|
3
|
+
import { existsSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { dirname, join, resolve } from "node:path";
|
|
5
|
+
import { execSync } from "node:child_process";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
6
7
|
|
|
7
8
|
const DEP_SECTIONS = ["dependencies", "devDependencies", "optionalDependencies"];
|
|
9
|
+
const SCOPES = ["@botbotgo/", "@wallee/"];
|
|
10
|
+
const SKIP_DIRS = new Set(["node_modules", ".git", "dist", "coverage"]);
|
|
8
11
|
|
|
9
|
-
function
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
function readJson(path) { return JSON.parse(readFileSync(path, "utf8")); }
|
|
13
|
+
function writeJson(path, value) { writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`); }
|
|
14
|
+
function isInternalPackage(name) { return SCOPES.some((scope) => name.startsWith(scope)); }
|
|
15
|
+
|
|
16
|
+
function tryResolveLocalVersion(pkgDir, spec) {
|
|
17
|
+
if (!spec.startsWith("file:")) return null;
|
|
18
|
+
const pkgPath = resolve(pkgDir, spec.slice(5), "package.json");
|
|
19
|
+
if (!existsSync(pkgPath)) return null;
|
|
20
|
+
const parsed = readJson(pkgPath);
|
|
21
|
+
return typeof parsed.version === "string" && parsed.version.length > 0 ? parsed.version : null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function fetchPublishedVersion(name) {
|
|
25
|
+
try {
|
|
26
|
+
const raw = execSync(`npm view ${name} version --json`, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
27
|
+
const parsed = JSON.parse(raw);
|
|
28
|
+
return typeof parsed === "string" && parsed.length > 0 ? parsed : null;
|
|
29
|
+
} catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function collectPackageJsonPaths(rootDir) {
|
|
35
|
+
const out = [];
|
|
36
|
+
function walk(currentDir) {
|
|
37
|
+
for (const entry of readdirSync(currentDir)) {
|
|
38
|
+
if (SKIP_DIRS.has(entry)) continue;
|
|
39
|
+
const abs = join(currentDir, entry);
|
|
40
|
+
const st = statSync(abs);
|
|
41
|
+
if (st.isDirectory()) {
|
|
42
|
+
walk(abs);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (entry === "package.json") out.push(abs);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
walk(rootDir);
|
|
49
|
+
return out.sort();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function rewritePackageJson(pkgPath) {
|
|
53
|
+
const pkg = readJson(pkgPath);
|
|
54
|
+
const pkgDir = dirname(pkgPath);
|
|
14
55
|
let changed = false;
|
|
15
56
|
|
|
16
57
|
for (const section of DEP_SECTIONS) {
|
|
17
58
|
const deps = pkg[section];
|
|
18
59
|
if (!deps || typeof deps !== "object") continue;
|
|
19
|
-
for (const [name,
|
|
20
|
-
if (!name.startsWith("
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
60
|
+
for (const [name, current] of Object.entries(deps)) {
|
|
61
|
+
if (typeof current !== "string" || !isInternalPackage(name) || !current.startsWith("file:")) continue;
|
|
62
|
+
const next = tryResolveLocalVersion(pkgDir, current) ?? fetchPublishedVersion(name);
|
|
63
|
+
if (!next) {
|
|
64
|
+
console.warn(`[resolve-deps] warn: could not resolve ${name} for ${pkgPath}`);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (next !== current) {
|
|
68
|
+
deps[name] = next;
|
|
69
|
+
changed = true;
|
|
70
|
+
console.log(`[resolve-deps] ${pkg.name ?? pkgPath} ${section}.${name}: ${current} -> ${next}`);
|
|
71
|
+
}
|
|
27
72
|
}
|
|
28
73
|
}
|
|
29
74
|
|
|
30
|
-
if (changed)
|
|
31
|
-
|
|
32
|
-
}
|
|
75
|
+
if (changed) writeJson(pkgPath, pkg);
|
|
76
|
+
return changed;
|
|
33
77
|
}
|
|
34
78
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (existsSync(workspaceRunner)) {
|
|
40
|
-
const { runResolveDeps } = await import(pathToFileURL(workspaceRunner).href);
|
|
41
|
-
await runResolveDeps(import.meta.url, "../../../scripts/internal-package-refs.mjs");
|
|
79
|
+
function main() {
|
|
80
|
+
if (!process.env.CI) {
|
|
81
|
+
console.log("[resolve-deps] skipping because CI is not set");
|
|
42
82
|
return;
|
|
43
83
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
84
|
+
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
85
|
+
const packageJsonPaths = collectPackageJsonPaths(repoRoot);
|
|
86
|
+
let changed = false;
|
|
87
|
+
for (const pkgPath of packageJsonPaths) changed = rewritePackageJson(pkgPath) || changed;
|
|
88
|
+
if (!changed) console.log("[resolve-deps] no file-based internal deps to rewrite");
|
|
47
89
|
}
|
|
48
90
|
|
|
49
|
-
|
|
91
|
+
main();
|
|
@@ -3,16 +3,10 @@
|
|
|
3
3
|
import { execSync } from "node:child_process";
|
|
4
4
|
import { existsSync, lstatSync, mkdirSync, readFileSync, rmSync, symlinkSync } from "node:fs";
|
|
5
5
|
import { dirname, resolve } from "node:path";
|
|
6
|
-
import { fileURLToPath } from "node:url";
|
|
7
6
|
|
|
8
|
-
const
|
|
9
|
-
const appDir = resolve(scriptDir, "..");
|
|
7
|
+
const appDir = process.argv[2] ? resolve(process.argv[2]) : process.cwd();
|
|
10
8
|
const packageJson = JSON.parse(readFileSync(resolve(appDir, "package.json"), "utf8"));
|
|
11
|
-
const dependencySections = [
|
|
12
|
-
packageJson.dependencies ?? {},
|
|
13
|
-
packageJson.devDependencies ?? {},
|
|
14
|
-
packageJson.optionalDependencies ?? {},
|
|
15
|
-
];
|
|
9
|
+
const dependencySections = [packageJson.dependencies ?? {}, packageJson.devDependencies ?? {}, packageJson.optionalDependencies ?? {}];
|
|
16
10
|
|
|
17
11
|
const WORKSPACE_PACKAGE_DIRS = {
|
|
18
12
|
"@botbotgo/common": "framework/common",
|
|
@@ -45,9 +39,7 @@ function resolveWorkspacePackageDir(packageName) {
|
|
|
45
39
|
|
|
46
40
|
function syncWorkspacePackage(packageName, packageDir) {
|
|
47
41
|
const [, scope, shortName] = packageName.match(/^@([^/]+)\/(.+)$/) ?? [];
|
|
48
|
-
if (!scope || !shortName) {
|
|
49
|
-
throw new Error(`Unsupported scoped package name: ${packageName}`);
|
|
50
|
-
}
|
|
42
|
+
if (!scope || !shortName) throw new Error(`Unsupported scoped package name: ${packageName}`);
|
|
51
43
|
const scopeDir = resolve(appDir, "node_modules", `@${scope}`);
|
|
52
44
|
const targetDir = resolve(scopeDir, shortName);
|
|
53
45
|
mkdirSync(scopeDir, { recursive: true });
|
|
@@ -81,7 +73,7 @@ function syncPeerDependenciesFromApp(packageDir) {
|
|
|
81
73
|
}
|
|
82
74
|
}
|
|
83
75
|
|
|
84
|
-
function ensureInstalledDependencies(
|
|
76
|
+
function ensureInstalledDependencies(packageDir) {
|
|
85
77
|
if (hasInstalledDependencies(packageDir)) return;
|
|
86
78
|
console.log(`[build-internal-deps] npm install --prefix ${packageDir}`);
|
|
87
79
|
execSync(`npm install --prefix ${JSON.stringify(packageDir)} --legacy-peer-deps --ignore-scripts`, {
|
|
@@ -91,33 +83,16 @@ function ensureInstalledDependencies(packageName, packageDir) {
|
|
|
91
83
|
syncPeerDependenciesFromApp(packageDir);
|
|
92
84
|
}
|
|
93
85
|
|
|
94
|
-
const packageNames = [
|
|
95
|
-
"@botbotgo/common",
|
|
96
|
-
"@botbotgo/model",
|
|
97
|
-
"@botbotgo/memory",
|
|
98
|
-
"@botbotgo/toolkit",
|
|
99
|
-
"@botbotgo/agent",
|
|
100
|
-
"@botbotgo/toolkit-builtin",
|
|
101
|
-
];
|
|
86
|
+
const packageNames = ["@botbotgo/common", "@botbotgo/model", "@botbotgo/memory", "@botbotgo/toolkit", "@botbotgo/agent", "@botbotgo/toolkit-builtin"];
|
|
102
87
|
|
|
103
88
|
for (const packageName of packageNames) {
|
|
104
89
|
const spec = getDependencySpec(packageName);
|
|
105
|
-
const packageDir = spec?.startsWith("file:")
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if (!packageDir || !existsSync(resolve(packageDir, "package.json"))) {
|
|
109
|
-
if (spec?.startsWith("file:")) {
|
|
110
|
-
console.warn(`[build-internal-deps] skipping missing workspace package for ${packageName}: ${packageDir}`);
|
|
111
|
-
}
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
ensureInstalledDependencies(packageName, packageDir);
|
|
90
|
+
const packageDir = spec?.startsWith("file:") ? resolve(appDir, spec.slice("file:".length)) : resolveWorkspacePackageDir(packageName);
|
|
91
|
+
if (!packageDir || !existsSync(resolve(packageDir, "package.json"))) continue;
|
|
92
|
+
ensureInstalledDependencies(packageDir);
|
|
115
93
|
console.log(`[build-internal-deps] npm run build --prefix ${packageDir}`);
|
|
116
94
|
try {
|
|
117
|
-
execSync(`npm run build --prefix ${JSON.stringify(packageDir)}`, {
|
|
118
|
-
cwd: appDir,
|
|
119
|
-
stdio: "inherit",
|
|
120
|
-
});
|
|
95
|
+
execSync(`npm run build --prefix ${JSON.stringify(packageDir)}`, { cwd: appDir, stdio: "inherit" });
|
|
121
96
|
} catch (error) {
|
|
122
97
|
if (!hasBuiltOutput(packageDir)) throw error;
|
|
123
98
|
console.warn(`[build-internal-deps] build failed for ${packageName}, using existing dist at ${packageDir}`);
|
package/scripts/test-llm.mjs
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Quick LLM config test. Run from app root: npm run test:llm
|
|
3
|
-
*/
|
|
4
|
-
import { AgentContextTokens, getDefaultAgentContext } from "@botbotgo/common/context";
|
|
5
|
-
import { createAgentModel } from "@botbotgo/model";
|
|
6
|
-
import { loadAppConfig, getModelsConfigPath } from "../dist/config.js";
|
|
7
|
-
|
|
8
|
-
async function main() {
|
|
9
|
-
try {
|
|
10
|
-
const appConfig = await loadAppConfig("config/app.yaml");
|
|
11
|
-
const agentNames = Object.keys(appConfig?.app?.agent ?? {});
|
|
12
|
-
const agentName = appConfig?.app?.defaultAgent ?? agentNames[0];
|
|
13
|
-
const modelPath = getModelsConfigPath(appConfig, agentName);
|
|
14
|
-
console.log(`[test-llm] Loading LLM from ${modelPath} ...`);
|
|
15
|
-
await createAgentModel({
|
|
16
|
-
configPath: modelPath,
|
|
17
|
-
});
|
|
18
|
-
const llm = getDefaultAgentContext().get(AgentContextTokens.ChatModel);
|
|
19
|
-
|
|
20
|
-
console.log("[test-llm] Invoking LLM ...");
|
|
21
|
-
const res = await llm.invoke(
|
|
22
|
-
"In one sentence, introduce yourself and say you are being used to test iTermBot's LLM config."
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
console.log("[test-llm] Raw response:");
|
|
26
|
-
console.log(JSON.stringify(res, null, 2));
|
|
27
|
-
} catch (err) {
|
|
28
|
-
console.error("[test-llm] Error:", err);
|
|
29
|
-
process.exit(1);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
main();
|