@nanhara/hara 0.125.1 → 0.126.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.
Files changed (46) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/README.md +22 -8
  3. package/SECURITY.md +6 -4
  4. package/dist/agent/limits.js +2 -2
  5. package/dist/agent/loop.js +413 -77
  6. package/dist/config.js +172 -4
  7. package/dist/gateway/flows-pending.js +14 -36
  8. package/dist/gateway/wecom.js +9 -1
  9. package/dist/index.js +439 -227
  10. package/dist/mcp/client.js +73 -6
  11. package/dist/providers/bounded-turn.js +6 -0
  12. package/dist/providers/factory.js +54 -0
  13. package/dist/providers/models.js +39 -6
  14. package/dist/providers/openai.js +6 -1
  15. package/dist/providers/reasoning.js +12 -0
  16. package/dist/providers/registry.js +1 -0
  17. package/dist/providers/target.js +98 -0
  18. package/dist/security/guardian.js +6 -1
  19. package/dist/security/private-state.js +1 -1
  20. package/dist/security/secrets.js +19 -0
  21. package/dist/serve/protocol.js +7 -2
  22. package/dist/serve/server.js +157 -40
  23. package/dist/serve/sessions.js +11 -2
  24. package/dist/session/operation-drain.js +45 -0
  25. package/dist/session/task.js +78 -0
  26. package/dist/statusbar.js +15 -2
  27. package/dist/tools/agent.js +1 -0
  28. package/dist/tools/all.js +1 -0
  29. package/dist/tools/ask_user.js +8 -3
  30. package/dist/tools/builtin.js +22 -1
  31. package/dist/tools/codebase.js +1 -0
  32. package/dist/tools/computer.js +1 -0
  33. package/dist/tools/cron.js +10 -0
  34. package/dist/tools/external_agent.js +1 -0
  35. package/dist/tools/memory.js +2 -0
  36. package/dist/tools/registry.js +95 -4
  37. package/dist/tools/result-limit.js +172 -2
  38. package/dist/tools/runtime.js +67 -0
  39. package/dist/tools/search.js +3 -0
  40. package/dist/tools/skill.js +1 -0
  41. package/dist/tools/task.js +5 -0
  42. package/dist/tools/todo.js +3 -2
  43. package/dist/tools/web.js +4 -0
  44. package/dist/tui/App.js +49 -17
  45. package/dist/tui/model-picker.js +11 -8
  46. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,82 @@ All notable changes to `@nanhara/hara`.
5
5
  > Versioning (pre-1.0, SemVer-style): the **minor** (middle) number bumps for a **new feature**; the
6
6
  > **patch** (last) number bumps for **optimizations/fixes of existing features**.
7
7
 
8
+ ## 0.126.0 — 2026-07-19 — provider control plane, bounded tools, and honest execution time
9
+
10
+ - **Desktop can configure providers through an authenticated, redacted Serve control plane.** The shared
11
+ catalog distinguishes cloud, local, OAuth, and managed routes; settings can list, test, and save a Personal
12
+ route without returning credentials to the UI. Switching provider or endpoint requires a matching new key
13
+ instead of replaying another vendor's credential, named/managed profiles remain explicit, and launch-time
14
+ environment overrides stay immutable from Desktop.
15
+ - **Ollama and LM Studio are first-class local providers.** They require no fake API key, accept only
16
+ loopback HTTP endpoints, omit the Authorization header on the wire, and can discover installed models
17
+ through the same bounded connection-test path. Cloud custom endpoints continue to require HTTPS except
18
+ for an explicit loopback target.
19
+ - **Tool execution has conservative runtime traits.** Tools without a complete declaration default to
20
+ side-effect-capable and serial; input-level classification can narrow a real read but cannot turn a
21
+ mutating call into an inherited read approval. Parallel calls share an aggregate result budget so one
22
+ round cannot flood the next model request.
23
+ - **Long-tail tool schemas and large results are demand-loaded.** `tool_search` activates only matched,
24
+ role-allowed capabilities for the next model round. Oversized, redacted tool output is kept in a
25
+ quota/TTL-bounded private store and exposed only through opaque `tool_result_read` continuation IDs, never
26
+ arbitrary filesystem paths.
27
+
28
+ - Human clarification and approval waits no longer consume `runTimeoutMs`. The non-renewable budget now
29
+ measures active model/tool execution, resumes with the exact remaining time after an answer, and still
30
+ stops genuinely stuck providers, tools, and loops. Esc, shutdown, and explicit cancellation continue to
31
+ dismiss a waiting prompt immediately.
32
+ - The TUI distinguishes this state as `waiting for your answer · task timer paused`; five-minute and 80%
33
+ lifecycle notices no longer fire while Hara is waiting for a person.
34
+ - `hara serve` now exposes authenticated `server.shutdown` so Desktop can gracefully release sessions and
35
+ locks before relaunching after an update.
36
+ - Timed-out or interrupted provider/tool calls retain their Serve session lease until the underlying
37
+ operation physically settles. A second turn, session deletion, or updater shutdown receives `BUSY`
38
+ instead of overlapping a non-cooperative request or releasing its lock early.
39
+ - Headless resumed sessions use the same physical-lifetime rule for dynamically nested sub-agents and
40
+ automatic compaction, so a late child request cannot escape a cleanup snapshot and release the
41
+ cross-process lock early.
42
+ - The WeCom gateway now uses the bundled `ws` transport because Node 22's native WebSocket handshake is
43
+ rejected by WeCom's production endpoint before authentication. A late authentication frame can no longer
44
+ revive an already-aborted connection or install a heartbeat after cleanup.
45
+ - Upgrade with `npm i -g @nanhara/hara@0.126.0`.
46
+
47
+ ## 0.125.3 — 2026-07-18 — conversation/task boundary and deliberate execution
48
+
49
+ - **Chat delivery is now separate from task execution.** Slash controls such as `/model` no longer create a
50
+ fake steer target; input typed while a picker or other local control is busy is visibly queued as the next
51
+ turn. If a real turn ends between enqueue and delivery, Hara promotes the raced steer to a normal turn
52
+ instead of rejecting it with `there is no task to steer` or dropping the input. Queued controls execute
53
+ alone rather than absorbing the following task as command arguments, and paused/completed tasks are never
54
+ implicit steer targets—only explicit `/continue` may reopen one. User-invocable slash Skills remain real
55
+ Agent turns, so refinements typed while `/design`, `/video`, or another Skill is running steer that Skill
56
+ instead of becoming an unrelated task.
57
+ - **Main tasks now establish an explicit understanding checkpoint before side effects.** The engine-owned
58
+ `task_intake` records intent, interpreted goal, constraints, acceptance checks, and short steps in the
59
+ durable task state. Reads and diagnosis may happen first, but edits, non-read-only commands, computer
60
+ actions, external agents, and MCP connections are blocked until the brief is accepted in a completed tool
61
+ round. Starting or stopping a background process is also treated as a state change even when its command or
62
+ job tool is otherwise read-only; malformed string-valued `background` flags are rejected. Read-only actions
63
+ inside mixed tools (`task list`, `cronjob list`) stay available for evidence gathering. Brief revisions
64
+ replace the old prompt copy and cannot share a round with a side effect. A later steer cannot be overwritten
65
+ by a concurrent or revised checkpoint.
66
+ - **Alibaba Coding Plan discovery follows the current exact model contract.** `/model` prefers the endpoint's
67
+ live response and uses the documented ten-model list only for official Coding Plan hosts. Context guards now
68
+ use each model's published window, and `qwen3-coder-next` / `qwen3-coder-plus` no longer expose an unsupported
69
+ thinking control. Desktop/serve derives the reasoning dial from each session's pinned model rather than the
70
+ current global default.
71
+ - **Configured MCP servers no longer execute or ask for permission when Hara starts.** Hara exposes a
72
+ zero-side-effect `mcp_connect` capability; the agent calls it only when the current task materially needs
73
+ one named server, receives the existing external-boundary approval, and discovers that server's tools for
74
+ the next model round. Other configured servers remain stopped.
75
+ - Interactive calls to connected MCP tools still require confirmation every time, protected-file-shaped
76
+ inputs remain blocked, read-only roles cannot receive the launcher, and headless runs remain fail-closed
77
+ unless `HARA_ALLOW_TRUSTED_EXTENSIONS=1` was set before launch.
78
+ - MCP stderr now drops only npm 11's repeated `Unknown user config "always-auth"` and `"home"` deprecation
79
+ lines. Other npm warnings and all actual server errors remain visible and redacted. Hara does not read,
80
+ rewrite, or weaken the user's `.npmrc`. Esc, interruption, and the active-execution deadline now also cancel a
81
+ lazy MCP startup/tool call and close an unresponsive child instead of leaving it behind.
82
+ - Upgrade with `npm i -g @nanhara/hara@0.125.3`.
83
+
8
84
  ## 0.125.1 — 2026-07-18 — installed plugin commands inside agent tasks
9
85
 
10
86
  - **Commands contributed by an installed Hara plugin are now available to Hara's own tool subprocesses.**
package/README.md CHANGED
@@ -109,8 +109,11 @@ hara config set model qwen-plus # or qwen-max, qwen3-coder-plus, …
109
109
  # coding-plan keys (sk-sp-…) use the coding endpoint instead:
110
110
  # hara config set baseURL https://coding.dashscope.aliyuncs.com/v1
111
111
  # hara config set model qwen3.7-plus
112
- # plan models: qwen3.7-plus, qwen3.6-plus, qwen3-coder-plus, qwen3-coder-next,
113
- # qwen3-max-2026-01-23, glm-5, glm-4.7 (switch with -m or /model)
112
+ # supported exact ids (2026-07-18):
113
+ # qwen3.7-plus, qwen3.6-plus, qwen3.5-plus, qwen3-max-2026-01-23,
114
+ # qwen3-coder-next, qwen3-coder-plus, kimi-k2.5, glm-5, glm-4.7,
115
+ # MiniMax-M2.5
116
+ # /model uses the endpoint's live list first and this official list only as a fallback.
114
117
  ```
115
118
 
116
119
  > Plan keys (Coding Plan / Token Plan) are licensed **only** for use inside AI coding agents /
@@ -266,7 +269,7 @@ Type-ahead Enter steers the exact live turn; `/next <message>` queues a separate
266
269
  clients use `session.steer` with `expectedTurnId` (durable before ACK) and may pass `newTask: true` to force a
267
270
  new execution. The `hara resume` launcher preserves terminal input in both npm/Node and standalone-binary
268
271
  installs.
269
- **MCP**: add an `mcpServers` map to global config (a reviewed project config additionally needs `HARA_TRUST_PROJECT_CONFIG=1` at launch); their tools appear to the agent as `mcp__<server>__<tool>`. Configured MCP servers, like `external_agent`, are trusted host extensions outside Hara's protected-file boundary. Every interactive tool call requires confirmation (even in `full-auto`), and non-interactive runs disable them by default; reviewed automation can explicitly opt in before launch with `HARA_ALLOW_TRUSTED_EXTENSIONS=1`. hara can also **be** an MCP server — `hara mcp` exposes its read/search tools (esp. **`codebase_search`**) over stdio so other clients (Claude Desktop, Cursor, another hara) can use them; read-only by default (`HARA_MCP_TOOLS` to override).
272
+ **MCP**: add an `mcpServers` map to global config (a reviewed project config additionally needs `HARA_TRUST_PROJECT_CONFIG=1` at launch). Hara starts with every configured server stopped and exposes only `mcp_connect`; when the current task first needs one server, the agent requests permission to connect that server and its tools appear on the next round as `mcp__<server>__<tool>`. Unrelated servers remain stopped. Configured MCP servers, like `external_agent`, are trusted host extensions outside Hara's protected-file boundary. Every interactive external-tool call requires confirmation (even in `full-auto`), and non-interactive runs disable them by default; reviewed automation can explicitly opt in before launch with `HARA_ALLOW_TRUSTED_EXTENSIONS=1`. hara can also **be** an MCP server — `hara mcp` exposes its read/search tools (esp. **`codebase_search`**) over stdio so other clients (Claude Desktop, Cursor, another hara) can use them; read-only by default (`HARA_MCP_TOOLS` to override).
270
273
  **Vim mode**: `hara config set vimMode true` makes the prompt modal — Esc → normal, `i/a/A/I` insert, `h l 0 $ w b e` motions, `x D C dd cw p` edits. Off by default.
271
274
  **Scheduled tasks**: `hara cron add "0 9 * * 1-5" "<task>"` (or `"every 30m"`, `"in 2h"`) runs a task on a schedule — each run is a fresh hara session. `hara cron install` wires a per-minute tick into launchd/crontab (no daemon); `--org` routes through the role org. Manage with `hara cron list/run/enable/disable/remove/logs`. Every job has a 30-minute deadline and the whole sequential tick has a non-renewable 60-minute watchdog: a job timeout kills its process tree, records `timed out` + duration/error, then continues with the next due job; a tick timeout stops the remainder and releases the global lock. Add `--deliver feishu:<chatId>` (or Telegram/webhook) for outcomes and `--alert-after N` for the consecutive-failure 🚨 threshold (default 3). Delivery intent is durable before transport, uses a stable idempotency key, and retries with bounded backoff on later ticks until confirmed. A failed channel cannot grow `jobs.json` forever: each job keeps at most 64 pending effects, reserves outcome/alert room before launch, and disables itself with a visible backlog error when full; restore delivery, let the queue drain, then re-enable it. Tune milliseconds with `HARA_CRON_JOB_TIMEOUT_MS` (hard max 24h) and `HARA_CRON_TICK_TIMEOUT_MS` (hard max 5h); scheduled jobs are also capped by the tick. After upgrading from a version whose tick is already stuck, terminate that specific legacy `hara cron tick` process tree once (or reboot); the next scheduler minute marks over-age state interrupted/disabled and recovers the lock without replaying a possibly orphaned task.
272
275
  **Work coordination**: `todo_write` is the agent's short, session-scoped checklist; it persists with that
@@ -274,10 +277,21 @@ session and is isolated between simultaneous sub-agents and serve sessions. `tas
274
277
  for work that outlives a conversation: add/update/list/remove items with `pending|in_progress|done`, an optional
275
278
  owner, and `blockedBy` dependencies. The private, atomic store is shared by concurrent hara processes for the
276
279
  same project and rejects missing/self/cyclic dependencies.
280
+ **Conversation and execution**: the composer first routes an input as a local control, a new task, a steer of
281
+ the exact live task, or an explicit next task. User-invocable slash Skills are executable turns and accept
282
+ live steering; local controls such as `/model` are serialized without pretending to own a task. A main task keeps the raw user request and a separate accepted
283
+ brief (intent, interpreted goal, constraints, acceptance checks, and steps). Hara permits read-only
284
+ investigation before that brief, but its engine blocks side effects until the understanding has been
285
+ checkpointed in its own model/tool round. Mixed tools are classified by action (`task list` is a read), and
286
+ a brief revision cannot share its round with a side effect. `/task` shows the current execution identity and brief. See
287
+ [`docs/conversation-task-execution.md`](docs/conversation-task-execution.md).
277
288
  **Notifications**: `hara config set notify bell` (terminal bell) or `notify system` (OS notification) pings you when a turn finishes — handy for long runs you've stepped away from. Gated on elapsed time so quick turns stay quiet; off by default.
278
- **Run limits and loop alarms**: every agent turn has a non-renewable 30-minute total deadline and a 64-round
279
- model/tool cap. Hara warns after five minutes or at 75% of the round budget, stops the third identical failing
280
- tool call, and surfaces the final reason in CLI, Desktop, or gateway output. Tune intentional long work with
289
+ **Run limits and loop alarms**: every agent turn has a non-renewable 30-minute active-execution budget and a
290
+ 64-round model/tool cap. Time spent waiting for an engine-owned question or approval does not consume that
291
+ budget; the status row says the task timer is paused, while Esc, shutdown, and explicit cancellation still
292
+ take effect immediately. Answering resumes the remaining budget rather than resetting it. Hara warns after
293
+ five active minutes or at 75% of the round budget, stops the third identical failing tool call, and surfaces
294
+ the final reason in CLI, Desktop, or gateway output. Tune intentional long work with
281
295
  `hara config set runTimeoutMs 45m` (1s..2h) and `hara config set maxAgentRounds 96` (1..256), or
282
296
  `HARA_RUN_TIMEOUT_MS` / `HARA_MAX_AGENT_ROUNDS`; neither boundary can be disabled. Sub-agents are capped at
283
297
  8 minutes/24 rounds and inherit the parent's cancellation. Auxiliary model work (planning, verification,
@@ -286,8 +300,8 @@ provider that ignores cancellation cannot strand the CLI outside the main loop.
286
300
  **Hooks**: run your own shell commands around tool calls via a `"hooks"` map in global config; hooks from a reviewed project config require the launch-time `HARA_TRUST_PROJECT_CONFIG=1` opt-in. A **`PreToolUse`** hook can **veto** a call (non-zero exit blocks it; its output becomes the reason the model sees) — gate `bash`, forbid edits outside a path, require a clean tree. A **`PostToolUse`** hook observes (format/lint a file the agent just wrote, log, notify). Each has a `matcher` (regex/literal on the tool name, `*` = all) and gets `{tool, payload}` on stdin + `HARA_TOOL_NAME` in env. Plugins can contribute hooks too.
287
301
  Reviewer/read-only/plan runs and parallel read-only sub-agents suppress both hook phases: PreToolUse and
288
302
  PostToolUse commands are arbitrary shell, so either could otherwise bypass their read-only contract indirectly.
289
- They also skip configured and plugin-provided MCP server processes, so starting an external tool server cannot
290
- bypass the same contract before the first model turn.
303
+ They also omit the lazy connector for configured and plugin-provided MCP servers, so a read-only role cannot
304
+ start an external tool server.
291
305
  **Profiles and live config**: select an identity with `--profile <name>`; use `overlays` in
292
306
  `~/.hara/config.json` for named config overlays. Project `.hara/config.json` files get the safe preference
293
307
  allowlist above; project-specific routing requires `HARA_TRUST_PROJECT_CONFIG=1` before launch.
package/SECURITY.md CHANGED
@@ -70,11 +70,13 @@ local user (who already has your shell).
70
70
  - **MCP/external agents are trusted extensions.** They execute outside Hara's protected-file boundary. Every
71
71
  interactive tool call requires confirmation, including in `full-auto`; non-interactive runs disable them by
72
72
  default. Reviewed automation can explicitly enable them before launch with
73
- `HARA_ALLOW_TRUSTED_EXTENSIONS=1`. Their inherited environment is still scrubbed, but the extension may use
74
- its own credentials or access anything its host process permits.
73
+ `HARA_ALLOW_TRUSTED_EXTENSIONS=1`. Merely configuring an MCP server does not start it: `mcp_connect` requests
74
+ permission and starts one named server only when a task needs it. Their inherited environment is still
75
+ scrubbed, but the extension may use its own credentials or access anything its host process permits.
75
76
  - **Plugins are code you trust.** Installing a plugin (`hara plugin add`) grants its author code execution:
76
- its MCP servers and hooks run shell commands on launch. `hara plugin add` **prints the exact commands** a
77
- plugin will run so you can review them; disable with `hara plugin disable <name>`.
77
+ its MCP servers may run on first relevant use and its hooks may run around matching tool calls. `hara plugin
78
+ add` **prints the exact commands** a plugin can run so you can review them; disable with
79
+ `hara plugin disable <name>`.
78
80
  - **Coding-plan keys.** Provider keys you configure are used only to call the model endpoint you set.
79
81
 
80
82
  ## What is *not* a security boundary
@@ -19,8 +19,8 @@ export function parseAgentRunTimeoutMs(value) {
19
19
  const parsed = amount * multiplier;
20
20
  return Number.isFinite(parsed) ? parsed : undefined;
21
21
  }
22
- /** Parse a total run deadline. Invalid/zero values cannot disable the safety boundary. Human values such
23
- * as `30m`, `90s`, and `1h` are accepted in config; HARA_RUN_TIMEOUT_MS also accepts plain milliseconds. */
22
+ /** Parse the active execution deadline. Invalid/zero values cannot disable the safety boundary. Human values
23
+ * such as `30m`, `90s`, and `1h` are accepted in config; HARA_RUN_TIMEOUT_MS also accepts plain milliseconds. */
24
24
  export function agentRunTimeoutMs(value = process.env.HARA_RUN_TIMEOUT_MS) {
25
25
  const parsed = parseAgentRunTimeoutMs(value);
26
26
  if (parsed === undefined || parsed <= 0)