itermbot 1.0.2 → 1.0.4

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.
Files changed (128) hide show
  1. package/.github/workflows/ci.yml +15 -20
  2. package/.github/workflows/release.yml +32 -20
  3. package/README.md +11 -20
  4. package/cleanup-unused.patch +108 -0
  5. package/config/app.yaml +32 -13
  6. package/config/memory.yaml +38 -31
  7. package/config/model.yaml +33 -0
  8. package/config/skill.yaml +8 -0
  9. package/config/tool.yaml +50 -17
  10. package/config/tsconfig.json +4 -1
  11. package/dist/chat/builtin-commands.d.ts +8 -0
  12. package/dist/chat/builtin-commands.d.ts.map +1 -0
  13. package/dist/chat/builtin-commands.js +53 -0
  14. package/dist/chat/builtin-commands.js.map +1 -0
  15. package/dist/chat/progress.d.ts +3 -0
  16. package/dist/chat/progress.d.ts.map +1 -0
  17. package/dist/chat/progress.js +23 -0
  18. package/dist/chat/progress.js.map +1 -0
  19. package/dist/chat/response-safety.d.ts +8 -0
  20. package/dist/chat/response-safety.d.ts.map +1 -0
  21. package/dist/chat/response-safety.js +126 -0
  22. package/dist/chat/response-safety.js.map +1 -0
  23. package/dist/chat/step-display.d.ts +2 -0
  24. package/dist/chat/step-display.d.ts.map +1 -0
  25. package/dist/chat/step-display.js +50 -0
  26. package/dist/chat/step-display.js.map +1 -0
  27. package/dist/chat/tool-result.d.ts +4 -0
  28. package/dist/chat/tool-result.d.ts.map +1 -0
  29. package/dist/chat/tool-result.js +24 -0
  30. package/dist/chat/tool-result.js.map +1 -0
  31. package/dist/config.d.ts +11 -6
  32. package/dist/config.d.ts.map +1 -1
  33. package/dist/config.js +26 -12
  34. package/dist/config.js.map +1 -1
  35. package/dist/index.js +308 -151
  36. package/dist/index.js.map +1 -1
  37. package/dist/iterm/direct-command-router.d.ts +24 -0
  38. package/dist/iterm/direct-command-router.d.ts.map +1 -0
  39. package/dist/iterm/direct-command-router.js +213 -0
  40. package/dist/iterm/direct-command-router.js.map +1 -0
  41. package/dist/iterm/session-hint.d.ts +10 -0
  42. package/dist/iterm/session-hint.d.ts.map +1 -0
  43. package/dist/iterm/session-hint.js +43 -0
  44. package/dist/iterm/session-hint.js.map +1 -0
  45. package/dist/iterm/target-panel-policy.d.ts +12 -0
  46. package/dist/iterm/target-panel-policy.d.ts.map +1 -0
  47. package/dist/iterm/target-panel-policy.js +287 -0
  48. package/dist/iterm/target-panel-policy.js.map +1 -0
  49. package/dist/runtime/text-tool-call-recovery.d.ts +23 -0
  50. package/dist/runtime/text-tool-call-recovery.d.ts.map +1 -0
  51. package/dist/runtime/text-tool-call-recovery.js +211 -0
  52. package/dist/runtime/text-tool-call-recovery.js.map +1 -0
  53. package/dist/startup/colors.d.ts +37 -0
  54. package/dist/startup/colors.d.ts.map +1 -0
  55. package/dist/{startup-colors.js → startup/colors.js} +30 -15
  56. package/dist/startup/colors.js.map +1 -0
  57. package/dist/startup/diagnostics.d.ts +8 -0
  58. package/dist/startup/diagnostics.d.ts.map +1 -0
  59. package/dist/startup/diagnostics.js +18 -0
  60. package/dist/startup/diagnostics.js.map +1 -0
  61. package/dist/startup/os.d.ts +10 -0
  62. package/dist/startup/os.d.ts.map +1 -0
  63. package/dist/startup/os.js +67 -0
  64. package/dist/startup/os.js.map +1 -0
  65. package/dist/startup/ui.d.ts +11 -0
  66. package/dist/startup/ui.d.ts.map +1 -0
  67. package/dist/startup/ui.js +49 -0
  68. package/dist/startup/ui.js.map +1 -0
  69. package/package.json +23 -13
  70. package/scripts/internal-package-refs.mjs +158 -0
  71. package/scripts/patch-buildin-cache.sh +1 -4
  72. package/scripts/resolve-deps.js +5 -0
  73. package/scripts/test-llm.mjs +11 -5
  74. package/skills/gpu-ssh-monitor/SKILL.md +22 -3
  75. package/src/chat/builtin-commands.ts +70 -0
  76. package/src/chat/progress.ts +26 -0
  77. package/src/chat/response-safety.ts +134 -0
  78. package/src/chat/step-display.ts +54 -0
  79. package/src/chat/tool-result.ts +22 -0
  80. package/src/config.ts +48 -21
  81. package/src/index.ts +377 -167
  82. package/src/iterm/direct-command-router.ts +274 -0
  83. package/src/iterm/session-hint.ts +49 -0
  84. package/src/iterm/target-panel-policy.ts +341 -0
  85. package/src/runtime/text-tool-call-recovery.ts +257 -0
  86. package/src/{startup-colors.ts → startup/colors.ts} +42 -27
  87. package/src/startup/diagnostics.ts +25 -0
  88. package/src/startup/os.ts +63 -0
  89. package/src/startup/ui.ts +56 -0
  90. package/src/types/marked-terminal.d.ts +3 -0
  91. package/test/builtin-commands.test.mjs +50 -0
  92. package/test/chat-flow.integration.test.mjs +235 -0
  93. package/test/chat-progress.test.mjs +83 -0
  94. package/test/config.test.mjs +22 -0
  95. package/test/diagnostics.test.mjs +45 -0
  96. package/test/direct-command-router.test.mjs +149 -0
  97. package/test/live-iterm-llm.integration.test.mjs +153 -0
  98. package/test/response-safety.test.mjs +44 -0
  99. package/test/session-hint.test.mjs +78 -0
  100. package/test/startup-colors.test.mjs +145 -0
  101. package/test/target-panel-policy.test.mjs +180 -0
  102. package/test/tool-call-recovery.test.mjs +199 -0
  103. package/config/agent.yaml +0 -121
  104. package/config/models.yaml +0 -36
  105. package/config/skills.yaml +0 -4
  106. package/dist/agent.d.ts +0 -14
  107. package/dist/agent.d.ts.map +0 -1
  108. package/dist/agent.js +0 -16
  109. package/dist/agent.js.map +0 -1
  110. package/dist/context.d.ts +0 -12
  111. package/dist/context.d.ts.map +0 -1
  112. package/dist/context.js +0 -20
  113. package/dist/context.js.map +0 -1
  114. package/dist/session-hint.d.ts +0 -4
  115. package/dist/session-hint.d.ts.map +0 -1
  116. package/dist/session-hint.js +0 -25
  117. package/dist/session-hint.js.map +0 -1
  118. package/dist/startup-colors.d.ts +0 -26
  119. package/dist/startup-colors.d.ts.map +0 -1
  120. package/dist/startup-colors.js.map +0 -1
  121. package/dist/target-routing.d.ts +0 -15
  122. package/dist/target-routing.d.ts.map +0 -1
  123. package/dist/target-routing.js +0 -355
  124. package/dist/target-routing.js.map +0 -1
  125. package/src/agent.ts +0 -35
  126. package/src/context.ts +0 -35
  127. package/src/session-hint.ts +0 -28
  128. package/src/target-routing.ts +0 -419
@@ -36,30 +36,25 @@ jobs:
36
36
  grep -q '@easynet:registry=' .npmrc || echo "@easynet:registry=https://registry.npmjs.org/" >> .npmrc
37
37
  grep -q '@wallee:registry=' .npmrc || echo "@wallee:registry=https://registry.npmjs.org/" >> .npmrc
38
38
 
39
- - name: Use @easynet deps from npm (CI has no file:../../)
40
- run: |
41
- node -e "
42
- const fs = require('fs');
43
- const pkgPath = 'package.json';
44
- const p = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
45
- const deps = { ...p.dependencies, ...p.devDependencies };
46
- let changed = false;
47
- for (const [name, v] of Object.entries(deps)) {
48
- if (name.startsWith('@easynet/') && typeof v === 'string' && v.startsWith('file:')) {
49
- if (p.dependencies[name]) { p.dependencies[name] = 'latest'; changed = true; }
50
- if (p.devDependencies[name]) { p.devDependencies[name] = 'latest'; changed = true; }
51
- }
52
- }
53
- if (changed) fs.writeFileSync(pkgPath, JSON.stringify(p, null, 2) + '\n');
54
- "
55
-
56
- - name: Remove lockfile to avoid stale local/git refs
57
- run: rm -f package-lock.json
39
+ - name: Rewrite file deps to npm/git refs for CI
40
+ env:
41
+ AGENT_SKILL_READ_TOKEN: ${{ secrets.AGENT_SKILL_READ_TOKEN }}
42
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
43
+ run: node scripts/resolve-deps.js
58
44
 
59
45
  - name: Install dependencies
60
46
  env:
61
47
  NPM_CONFIG_REGISTRY: "https://registry.npmjs.org/"
62
- run: npm install --legacy-peer-deps
48
+ run: |
49
+ rm -rf node_modules
50
+ rm -f package-lock.json
51
+ unset NPM_CONFIG_USERCONFIG NODE_AUTH_TOKEN
52
+ for i in 1 2 3; do
53
+ if npm install --legacy-peer-deps --ignore-scripts; then exit 0; fi
54
+ echo "Attempt $i failed, retrying in 10s..."
55
+ sleep 10
56
+ done
57
+ exit 1
63
58
 
64
59
  - name: Build
65
60
  run: npm run build --if-present
@@ -42,30 +42,25 @@ jobs:
42
42
  grep -q '@easynet:registry=' .npmrc || echo "@easynet:registry=https://registry.npmjs.org/" >> .npmrc
43
43
  grep -q '@wallee:registry=' .npmrc || echo "@wallee:registry=https://registry.npmjs.org/" >> .npmrc
44
44
 
45
- - name: Use @easynet deps from npm (CI has no file:../../)
46
- run: |
47
- node -e "
48
- const fs = require('fs');
49
- const pkgPath = 'package.json';
50
- const p = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
51
- const deps = { ...p.dependencies, ...p.devDependencies };
52
- let changed = false;
53
- for (const [name, v] of Object.entries(deps)) {
54
- if (name.startsWith('@easynet/') && typeof v === 'string' && v.startsWith('file:')) {
55
- if (p.dependencies[name]) { p.dependencies[name] = 'latest'; changed = true; }
56
- if (p.devDependencies[name]) { p.devDependencies[name] = 'latest'; changed = true; }
57
- }
58
- }
59
- if (changed) fs.writeFileSync(pkgPath, JSON.stringify(p, null, 2) + '\n');
60
- "
61
-
62
- - name: Remove lockfile to avoid stale local/git refs
63
- run: rm -f package-lock.json
45
+ - name: Rewrite file deps to npm/git refs for CI
46
+ env:
47
+ AGENT_SKILL_READ_TOKEN: ${{ secrets.AGENT_SKILL_READ_TOKEN }}
48
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
49
+ run: node scripts/resolve-deps.js
64
50
 
65
51
  - name: Install dependencies
66
52
  env:
67
53
  NPM_CONFIG_REGISTRY: "https://registry.npmjs.org/"
68
- run: npm install --legacy-peer-deps
54
+ run: |
55
+ rm -rf node_modules
56
+ rm -f package-lock.json
57
+ unset NPM_CONFIG_USERCONFIG NODE_AUTH_TOKEN
58
+ for i in 1 2 3; do
59
+ if npm install --legacy-peer-deps --ignore-scripts; then exit 0; fi
60
+ echo "Attempt $i failed, retrying in 10s..."
61
+ sleep 10
62
+ done
63
+ exit 1
69
64
 
70
65
  - name: Build
71
66
  run: npm run build --if-present
@@ -76,8 +71,25 @@ jobs:
76
71
  - name: Test
77
72
  run: npm test --if-present
78
73
 
74
+ - name: Detect npm token
75
+ id: release_gate
76
+ env:
77
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
78
+ run: |
79
+ if [ -n "${NPM_TOKEN}" ]; then
80
+ echo "has_npm_token=true" >> "$GITHUB_OUTPUT"
81
+ else
82
+ echo "has_npm_token=false" >> "$GITHUB_OUTPUT"
83
+ fi
84
+
85
+ - name: Skip release (missing NPM_TOKEN)
86
+ if: ${{ steps.release_gate.outputs.has_npm_token == 'false' }}
87
+ run: echo "NPM_TOKEN is not configured. Skipping semantic-release."
88
+
79
89
  - name: Release
90
+ if: ${{ steps.release_gate.outputs.has_npm_token == 'true' }}
80
91
  env:
81
92
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
93
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
82
94
  NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
83
95
  run: npx semantic-release
package/README.md CHANGED
@@ -8,7 +8,7 @@ iTermBot is an application built on the **@easynet** agent framework. It runs tw
8
8
  Both agents share:
9
9
 
10
10
  - **@easynet/agent-common** — YAML config (app, paths).
11
- - **@easynet/agent-model** — LLM and embedding models from `models.yaml`.
11
+ - **@easynet/agent-model** — LLM and embedding models (falls back to module default config).
12
12
  - **@easynet/agent-memory** — Agent memory (recall/inject for ReAct; store adapter for Deep).
13
13
  - **@easynet/agent-tool** + **@easynet/agent-tool-buildin** — Tools (FS, HTTP, util, exec, etc.).
14
14
 
@@ -19,7 +19,7 @@ Both agents share:
19
19
 
20
20
  ## Setup
21
21
 
22
- The app uses **npm packages** only (no file: links), so it builds from a clean install:
22
+ Build from source workspace:
23
23
 
24
24
  ```bash
25
25
  cd apps/itermbot
@@ -33,23 +33,12 @@ Tool support uses agent-tool’s `@easynet/agent-tool` and `@easynet/agent-tool-
33
33
 
34
34
  | File | Purpose |
35
35
  |------|--------|
36
- | `config/app.yaml` | App name and paths (loaded via agent-common). |
37
- | `config/models.yaml` | LLM + embedding instances (agent-model). |
38
- | `config/memory.yaml` | Memory backend config (agent-memory). |
39
- | `config/tool.yaml` | Tool list used by all environments. |
36
+ | `config/app.yaml` | App-level settings (`agent`, `printSteps`, prompt templates). |
40
37
 
41
- Paths in `config/app.yaml` are relative to the app root (current working directory when you run the app).
38
+ Agent profile defaults (model/memory/tool/skills) are resolved by `@easynet/agent-runtime`.
39
+ Top-level app config only overrides runtime defaults.
42
40
 
43
- ### Tool source by environment
44
-
45
- - `APP_ENV=development` and `APP_ENV=production` both use `config/tool.yaml`
46
-
47
- Example:
48
-
49
- ```bash
50
- APP_ENV=development npm run react
51
- APP_ENV=production npm run react
52
- ```
41
+ Tool config now falls back to `@easynet/agent-tool` module defaults when app-level tool config is not provided.
53
42
 
54
43
  ## Usage
55
44
 
@@ -84,8 +73,10 @@ APP_ENV=production npm run react
84
73
 
85
74
  ## Architecture
86
75
 
87
- - **context.ts** — Builds shared `BotContext`: LLM (`createAgentLlm`), memory (`createAgentMemory`), tools (`createAgentTools` with env-selected tool config and `coreTools`).
88
- - **agents/react-agent.ts** — LangChain `createAgent`; before each run, injects memory via `memory.recall`; optional `remember()` with `memory.memorize`.
89
- - **agents/deep-agent.ts** — DeepAgents `createDeepAgent` with state backend (no extra memory store adapter wiring).
76
+ - **src/index.ts** — CLI startup and orchestration.
77
+ - **src/context.ts** — Shared `BotContext` builders (LLM/memory/tools/skills).
78
+ - **src/config.ts** — App-level override adapter on top of runtime config.
79
+ - **src/startup/** — startup UI, diagnostics, and panel color bootstrapping.
80
+ - **src/iterm/** — iTerm session routing and target session prompt injection.
90
81
 
91
82
  Both agents use the same LLM, memory backend, and tool set; only the orchestration (ReAct vs Deep) differs.
@@ -0,0 +1,108 @@
1
+ *** Begin Patch
2
+ *** Update File: src/iterm/session-hint.ts
3
+ @@
4
+ /**
5
+ * Build the full system prompt by prepending iTerm policy and session info
6
+ * to an optional base prompt. Called before createReactAgentRuntime().
7
+ */
8
+ export function buildSystemPrompt(
9
+ templates: PromptTemplates | undefined,
10
+ startup: StartupResult,
11
+ basePrompt = "",
12
+ ): string {
13
+ @@
14
+ if (basePrompt.trim()) parts.push(basePrompt.trim());
15
+ return parts.join("\n\n");
16
+ }
17
+ -
18
+ -/**
19
+ - * Update just the target session section in an existing system prompt.
20
+ - * Used when target routing changes at runtime.
21
+ - */
22
+ -export function updateTargetSessionInPrompt(
23
+ - currentPrompt: string,
24
+ - templates: PromptTemplates | undefined,
25
+ - startup: StartupResult,
26
+ -): string {
27
+ - const targetTemplate = templates?.targetSession?.trim() ?? "";
28
+ - if (!targetTemplate) return currentPrompt;
29
+ - const rendered = startup.targetSessionId
30
+ - ? formatTargetSessionHint(targetTemplate, startup)
31
+ - : "";
32
+ - if (!rendered) return currentPrompt;
33
+ - // Replace existing target session block or append
34
+ - const headerLine = "## Target Panel Session";
35
+ - const idx = currentPrompt.indexOf(headerLine);
36
+ - if (idx !== -1) {
37
+ - // Find end of block (next ## heading or end of string)
38
+ - const afterHeader = currentPrompt.indexOf("\n##", idx + 1);
39
+ - const before = currentPrompt.slice(0, idx).trimEnd();
40
+ - const after = afterHeader !== -1 ? "\n\n" + currentPrompt.slice(afterHeader).trimStart() : "";
41
+ - return (before + "\n\n" + rendered + after).trim();
42
+ - }
43
+ - return currentPrompt + "\n\n" + rendered;
44
+ -}
45
+ *** End Patch
46
+
47
+ *** Begin Patch
48
+ *** Update File: src/startup/colors.ts
49
+ @@
50
+ function captureSessionColorsSync(args: {
51
+ windowId: number;
52
+ tabIndex: number;
53
+ sessionId: string;
54
+ }): SessionColorSnapshot | null {
55
+ @@
56
+ }
57
+ }
58
+ -
59
+ -export function captureSessionColorsByIdSync(args: {
60
+ - windowId: number;
61
+ - tabIndex: number;
62
+ - sessionId: string;
63
+ -}): SessionColorSnapshot | null {
64
+ - return captureSessionColorsSync(args);
65
+ -}
66
+
67
+ export function restoreSessionColorsSync(snapshots: SessionColorSnapshot[]): void {
68
+ *** End Patch
69
+
70
+ *** Begin Patch
71
+ *** Update File: src/startup/diagnostics.ts
72
+ @@
73
+ -import { loadYamlFile, AgentContextTokens } from "@easynet/agent-common";
74
+ +import { AgentContextTokens } from "@easynet/agent-common";
75
+ @@
76
+ type AgentRuntimeLike = {
77
+ context: {
78
+ get<T>(token: unknown): T;
79
+ };
80
+ };
81
+ -
82
+ -export async function getLlmSelectionLabel(modelsPath: string): Promise<string> {
83
+ - try {
84
+ - const raw = await loadYamlFile<Record<string, unknown>>(modelsPath);
85
+ - const spec = raw?.spec && typeof raw.spec === "object" && !Array.isArray(raw.spec)
86
+ - ? (raw.spec as Record<string, unknown>)
87
+ - : undefined;
88
+ - const llm = ((spec?.llm ?? raw?.llm) ?? null) as Record<string, unknown> | null;
89
+ - if (!llm) return "name=unknown, model=unknown";
90
+ - const selectedName =
91
+ - typeof llm.default === "string" && llm.default.trim().length > 0
92
+ - ? llm.default.trim()
93
+ - : "unknown";
94
+ - const selected = llm[selectedName];
95
+ - const selectedRec =
96
+ - typeof selected === "object" && selected !== null
97
+ - ? (selected as Record<string, unknown>)
98
+ - : null;
99
+ - const model =
100
+ - selectedRec && typeof selectedRec.model === "string" && selectedRec.model.trim().length > 0
101
+ - ? selectedRec.model.trim()
102
+ - : "unknown";
103
+ - return `name=${selectedName}, model=${model}`;
104
+ - } catch {
105
+ - return "name=unknown, model=unknown";
106
+ - }
107
+ -}
108
+ *** End Patch
package/config/app.yaml CHANGED
@@ -1,9 +1,26 @@
1
- # iTermBot app-level config
1
+ apiVersion: easynet.world/v1
2
+ kind: AppConfig
3
+ metadata:
4
+ name: itermbot
5
+ spec:
6
+ agent: react
7
+
8
+ printSteps: true
9
+ maxSteps: 100
10
+ responseSafetyMode: balanced
11
+
12
+ promptTemplates:
13
+ systemPrompt: |
14
+ ## Role
15
+ You are a senior systems engineer and terminal operations expert.
16
+ You are highly experienced with Linux/macOS shells, filesystems, networking, process diagnostics, and incident triage.
17
+ You think step-by-step, prioritize verifiable evidence, and avoid guesses.
18
+ You communicate in clear, well-structured Markdown suitable for terminal display.
19
+ 你是一位资深系统工程师与终端运维专家,熟悉 Linux/macOS 系统排障与性能分析,结论必须基于可验证证据。
2
20
 
3
- app:
4
- prompt_templates:
5
- iterm_policy: |
6
21
  ## iTerm Operating Policy
22
+ - The chat panel receives user messages; understand intent, select a matching skill when available, then plan, execute on target panel, analyze, and reply.
23
+ - Skills are preferred over ad-hoc planning when a skill matches the request.
7
24
  - Target panel output is the remote source of truth.
8
25
  - Never use local machine commands for system/project data collection.
9
26
  - For remote operations/investigation, use `itermRunCommandInSession` in target panel.
@@ -14,13 +31,15 @@ app:
14
31
  - Host may auto-update target panel when focus moves to a non-chat panel.
15
32
  - Final response must be valid Markdown with stable formatting.
16
33
  - Host may auto-recover target routing (reuse non-chat pane or auto-split); if still failing, ask user.
17
- target_session: |
18
- ## Target Panel Session
19
- Routed target panel (may change at runtime):
20
- - sessionId: "{{sessionId}}"
21
- - windowId: {{windowId}}
22
- - tabIndex: {{tabIndex}}
23
- Never use `windowId: 0` and never guess IDs.
24
34
 
25
- agent:
26
- path: ./config/agent.yaml
35
+ {{targetSessionSection}}
36
+
37
+ {{targetOsSection}}
38
+
39
+ Response safety policy:
40
+ - Ground all conclusions in tool output evidence only.
41
+ - If tool output contains requestedPath/resolvedPath/pathFallbackUsed, treat those fields as source of truth.
42
+ - Never claim a missing path exists when fallback was used.
43
+ - If user request omits path/scope for inspection tasks, run one non-destructive check against current target-panel working directory first, and state this assumption explicitly.
44
+ - Do not suggest destructive commands (for example rm -rf, sudo rm, mkfs, dd, disk erase) unless the user explicitly asks to execute them.
45
+ - Prefer non-destructive and reversible recommendations before irreversible actions.
@@ -1,33 +1,40 @@
1
- # iTermBot agent memory (@easynet/agent-memory)
2
- memory:
3
- thread:
4
- store:
5
- type: sqlite
6
- config:
7
- dbPath: ../data/thread.db
8
- sessionCompaction:
9
- enabled: true
10
- maxTokens: 3000
11
- keepRecentTurns: 12
12
- summaryKey: "__session_summary__"
13
- checkEveryTurns: 3
14
- cross_thread:
15
- store:
16
- type: sqlite
17
- config:
18
- dbPath: ../data/cross-thread.db
19
- knowledge:
20
- store:
21
- type: sqlite
22
- config:
23
- dbPath: ../data/knowledge.db
1
+ apiVersion: easynet.world/v1
2
+ kind: MemoryConfig
3
+ metadata:
4
+ name: itermbot-memory
5
+ spec:
6
+ memory:
7
+ thread:
8
+ store:
9
+ type: in_memory
10
+ allowWrite: true
11
+ maxItems: 20
12
+ sessionCompaction:
13
+ enabled: true
14
+ maxTokens: 3000
15
+ keepRecentTurns: 12
16
+ summaryKey: __session_summary__
17
+ checkEveryTurns: 3
24
18
 
25
- observability:
26
- trace: false
19
+ cross_thread:
20
+ store:
21
+ type: in_memory
22
+ allowWrite: true
23
+ maxItems: 20
24
+
25
+ knowledge:
26
+ store:
27
+ type: in_memory
28
+ allowWrite: true
29
+ maxItems: 20
30
+
31
+ observability:
32
+ trace: false
33
+
34
+ privacy:
35
+ forbiddenMetadataKeys:
36
+ - password
37
+ - api_key
38
+ - secret
39
+ - token
27
40
 
28
- privacy:
29
- forbiddenMetadataKeys:
30
- - password
31
- - api_key
32
- - secret
33
- - token
@@ -0,0 +1,33 @@
1
+ apiVersion: easynet.world/v1
2
+ kind: ModelConfig
3
+ metadata:
4
+ name: itermbot-models
5
+ spec:
6
+ llm:
7
+ default: lfm2
8
+ small:
9
+ provider: openai
10
+ base_url: http://localhost:11434/v1
11
+ model: qwen3:0.6b
12
+ lfm2:
13
+ provider: openai
14
+ base_url: https://ollama-rtx-4070.easynet.world/v1
15
+ model: lfm2:latest
16
+
17
+ embed:
18
+ default: local
19
+ local:
20
+ provider: openai
21
+ base_url: http://localhost:11434/v1
22
+ model: qwen3-embedding:0.6b
23
+ apiKey: not-needed
24
+
25
+ vlm:
26
+ default: glm_ocr
27
+ glm_ocr:
28
+ type: image
29
+ provider: openai
30
+ base_url: http://localhost:11434/v1
31
+ model: glm-ocr:q8_0
32
+ apiKey: not-needed
33
+
@@ -0,0 +1,8 @@
1
+ apiVersion: easynet.world/v1
2
+ kind: SkillConfig
3
+ metadata:
4
+ name: itermbot-skills
5
+ spec:
6
+ path: ../skills
7
+ mode: prompt
8
+ inject_metadata: true
package/config/tool.yaml CHANGED
@@ -1,17 +1,50 @@
1
- # iTermBot tools (shared across development and production)
2
- # Only load the iterm tools needed — no fs/http/util tools that would
3
- # distract the LLM from using itermRunCommandInSession.
4
- tools:
5
- list:
6
- - "npm:@easynet/agent-tool-buildin@latest#itermRunCommandInSession"
7
- - "npm:@easynet/agent-tool-buildin@latest#itermSendText"
8
- - "npm:@easynet/agent-tool-buildin@latest#itermListCurrentWindowSessions"
9
- - "npm:@easynet/agent-tool-buildin@latest#itermListWindows"
10
- - "npm:@easynet/agent-tool-buildin@latest#itermSetSessionColors"
11
- - "npm:@easynet/agent-tool-buildin@latest#itermSplitPane"
12
- - "npm:@easynet/agent-tool-buildin@latest#itermGetSessionInfo"
13
- sandboxedPath: .
14
- allowedHosts:
15
- - api.github.com
16
- - duckduckgo.com
17
- - www.duckduckgo.com
1
+ apiVersion: easynet.world/v1
2
+ kind: ToolConfig
3
+ metadata:
4
+ name: itermbot-local-tool-config
5
+ spec:
6
+ tools:
7
+ defaults:
8
+ itermRunCommandInSession:
9
+ allowedCommandPrefixes:
10
+ - cat
11
+ - cd
12
+ - date
13
+ - df
14
+ - du
15
+ - env
16
+ - file
17
+ - find
18
+ - grep
19
+ - head
20
+ - hostname
21
+ - id
22
+ - ls
23
+ - md5sum
24
+ - pwd
25
+ - readlink
26
+ - rg
27
+ - sha1sum
28
+ - sha256sum
29
+ - stat
30
+ - tail
31
+ - uname -s
32
+ - uname
33
+ - wc
34
+ - whoami
35
+ # Add only explicit command prefixes here. Example:
36
+ # - hdfs dfs -ls
37
+ list:
38
+ - file:../../../agent-tool-buildin#listDir
39
+ - file:../../../agent-tool-buildin#itermCreateWindow
40
+ - file:../../../agent-tool-buildin#itermCreateTab
41
+ - file:../../../agent-tool-buildin#itermSplitPane
42
+ - file:../../../agent-tool-buildin#itermResizeWindow
43
+ - file:../../../agent-tool-buildin#itermRename
44
+ - file:../../../agent-tool-buildin#itermSetBackgroundColor
45
+ - file:../../../agent-tool-buildin#itermSetSessionColors
46
+ - file:../../../agent-tool-buildin#itermSendText
47
+ - file:../../../agent-tool-buildin#itermRunCommandInSession
48
+ - file:../../../agent-tool-buildin#itermListCurrentWindowSessions
49
+ - file:../../../agent-tool-buildin#itermGetSessionInfo
50
+ - file:../../../agent-tool-buildin#itermListWindows
@@ -3,15 +3,18 @@
3
3
  "target": "ES2022",
4
4
  "module": "NodeNext",
5
5
  "moduleResolution": "NodeNext",
6
+ "lib": ["ES2022"],
6
7
  "outDir": "../dist",
7
8
  "rootDir": "../src",
8
9
  "strict": true,
9
10
  "esModuleInterop": true,
11
+ "allowSyntheticDefaultImports": true,
12
+ "resolveJsonModule": true,
10
13
  "skipLibCheck": true,
11
14
  "declaration": true,
12
15
  "declarationMap": true,
13
16
  "sourceMap": true,
14
- "resolveJsonModule": true
17
+ "types": ["node"]
15
18
  },
16
19
  "include": ["../src/**/*"],
17
20
  "exclude": ["../node_modules", "../dist"]
@@ -0,0 +1,8 @@
1
+ type RuntimeLike = {
2
+ context: {
3
+ get<T>(token: unknown): T;
4
+ };
5
+ };
6
+ export declare function tryHandleBuiltinReadCommand(input: string, runtime: RuntimeLike): string | null;
7
+ export {};
8
+ //# sourceMappingURL=builtin-commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builtin-commands.d.ts","sourceRoot":"","sources":["../../src/chat/builtin-commands.ts"],"names":[],"mappings":"AAGA,KAAK,WAAW,GAAG;IACjB,OAAO,EAAE;QACP,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,GAAG,CAAC,CAAC;KAC3B,CAAC;CACH,CAAC;AAyDF,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAK9F"}
@@ -0,0 +1,53 @@
1
+ import { AgentContextTokens } from "@easynet/agent-common/context";
2
+ import { normalizeToolList, shortToolName } from "@easynet/agent-common/utils";
3
+ function isToolLike(tool) {
4
+ return Boolean(tool
5
+ && typeof tool === "object"
6
+ && typeof tool.name === "string");
7
+ }
8
+ function safeGet(runtime, token) {
9
+ try {
10
+ return runtime.context.get(token);
11
+ }
12
+ catch {
13
+ return null;
14
+ }
15
+ }
16
+ function formatTools(runtime) {
17
+ const raw = safeGet(runtime, AgentContextTokens.Tools);
18
+ const tools = normalizeToolList(raw, isToolLike);
19
+ if (tools.length === 0)
20
+ return "No tools are registered.";
21
+ const lines = [`Available tools (${tools.length}):`];
22
+ for (const tool of tools) {
23
+ const short = shortToolName(tool.name);
24
+ if (tool.description?.trim())
25
+ lines.push(`- ${short}: ${tool.description.trim()}`);
26
+ else
27
+ lines.push(`- ${short}`);
28
+ }
29
+ return lines.join("\n");
30
+ }
31
+ function formatSkills(runtime) {
32
+ const skillSet = safeGet(runtime, AgentContextTokens.SkillSet);
33
+ const skills = skillSet?.list?.() ?? [];
34
+ if (skills.length === 0)
35
+ return "No skills are configured.";
36
+ const lines = [`Available skills (${skills.length}):`];
37
+ for (const skill of skills) {
38
+ if (skill.description?.trim())
39
+ lines.push(`- ${skill.name}: ${skill.description.trim()}`);
40
+ else
41
+ lines.push(`- ${skill.name}`);
42
+ }
43
+ return lines.join("\n");
44
+ }
45
+ export function tryHandleBuiltinReadCommand(input, runtime) {
46
+ const normalized = input.trim().toLowerCase().replace(/\s+/g, " ");
47
+ if (normalized === "list tools")
48
+ return formatTools(runtime);
49
+ if (normalized === "list skills")
50
+ return formatSkills(runtime);
51
+ return null;
52
+ }
53
+ //# sourceMappingURL=builtin-commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builtin-commands.js","sourceRoot":"","sources":["../../src/chat/builtin-commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAsB/E,SAAS,UAAU,CAAC,IAAa;IAC/B,OAAO,OAAO,CACZ,IAAI;WACD,OAAO,IAAI,KAAK,QAAQ;WACxB,OAAQ,IAA2B,CAAC,IAAI,KAAK,QAAQ,CACzD,CAAC;AACJ,CAAC;AAED,SAAS,OAAO,CAAI,OAAoB,EAAE,KAAc;IACtD,IAAI,CAAC;QACH,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAI,KAAK,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,OAAoB;IACvC,MAAM,GAAG,GAAG,OAAO,CAAU,OAAO,EAAE,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAChE,MAAM,KAAK,GAAG,iBAAiB,CAAW,GAAG,EAAE,UAAU,CAAC,CAAC;IAC3D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,0BAA0B,CAAC;IAC1D,MAAM,KAAK,GAAG,CAAC,oBAAoB,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;IACrD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,IAAI,CAAC,WAAW,EAAE,IAAI,EAAE;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,KAAK,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;;YAC9E,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,YAAY,CAAC,OAAoB;IACxC,MAAM,QAAQ,GAAG,OAAO,CAA2B,OAAO,EAAE,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACzF,MAAM,MAAM,GAAG,QAAQ,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC;IACxC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,2BAA2B,CAAC;IAC5D,MAAM,KAAK,GAAG,CAAC,qBAAqB,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;IACvD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,WAAW,EAAE,IAAI,EAAE;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;;YACrF,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,KAAa,EAAE,OAAoB;IAC7E,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACnE,IAAI,UAAU,KAAK,YAAY;QAAE,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC;IAC7D,IAAI,UAAU,KAAK,aAAa;QAAE,OAAO,YAAY,CAAC,OAAO,CAAC,CAAC;IAC/D,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { type AgentEventListener } from "@easynet/agent-common/events";
2
+ export declare function createChatProgressEventListener(writer?: (line: string) => void): AgentEventListener;
3
+ //# sourceMappingURL=progress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../../src/chat/progress.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAgBzG,wBAAgB,+BAA+B,CAC7C,MAAM,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAkB,GAC3C,kBAAkB,CAOpB"}
@@ -0,0 +1,23 @@
1
+ import { createProgressAgentEventListener } from "@easynet/agent-common/events";
2
+ import { renderStepLine } from "./step-display.js";
3
+ function reasonForAction(action) {
4
+ if (action.startsWith("run command:")) {
5
+ return "Because we need verifiable terminal evidence, execute this command first.";
6
+ }
7
+ if (action.startsWith("list directory")) {
8
+ return "Because we need to confirm directory structure and contents, list the directory first.";
9
+ }
10
+ if (action.startsWith("read file:") || action === "read file" || action.startsWith("read path:")) {
11
+ return "Because conclusions depend on file content, read the file first.";
12
+ }
13
+ return null;
14
+ }
15
+ export function createChatProgressEventListener(writer = console.log) {
16
+ return createProgressAgentEventListener({
17
+ writer: (line) => writer(renderStepLine(line)),
18
+ runLabelReact: "analysis",
19
+ runLabelDeep: "deep analysis",
20
+ reasonForAction,
21
+ });
22
+ }
23
+ //# sourceMappingURL=progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.js","sourceRoot":"","sources":["../../src/chat/progress.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gCAAgC,EAA2B,MAAM,8BAA8B,CAAC;AACzG,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,SAAS,eAAe,CAAC,MAAc;IACrC,IAAI,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QACtC,OAAO,2EAA2E,CAAC;IACrF,CAAC;IACD,IAAI,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACxC,OAAO,wFAAwF,CAAC;IAClG,CAAC;IACD,IAAI,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,MAAM,KAAK,WAAW,IAAI,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACjG,OAAO,kEAAkE,CAAC;IAC5E,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,+BAA+B,CAC7C,SAAiC,OAAO,CAAC,GAAG;IAE5C,OAAO,gCAAgC,CAAC;QACtC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QACtD,aAAa,EAAE,UAAU;QACzB,YAAY,EAAE,eAAe;QAC7B,eAAe;KAChB,CAAC,CAAC;AACL,CAAC"}