@dimi-agent/cli 0.6.5 → 0.6.7
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/dist/main.mjs +105 -3
- package/package.json +4 -4
package/dist/main.mjs
CHANGED
|
@@ -104346,7 +104346,7 @@ var init_abort = __esmMin((() => {
|
|
|
104346
104346
|
//#region ../../packages/agent-core-v2/src/agent/tools/os/bash/bash.md?raw
|
|
104347
104347
|
var bash_default;
|
|
104348
104348
|
var init_bash = __esmMin((() => {
|
|
104349
|
-
bash_default = "Execute a `${SHELL_NAME}` command. Use this for shell semantics — pipes, env, processes, git, package managers, build/test runners, anything genuinely interactive or multi-step.\n\n**Translate these to a dedicated tool instead:**\n- `cat` / `head` / `tail` (known path) → `Read`\n- `sed` / `awk` (in-place edit) → `Edit`\n- `echo > file` / `cat <<EOF` → `Write`\n- `find` / recursive `ls` to locate files by name pattern → `Glob` (plain `ls <known-directory>` is fine for listing a directory)\n- `grep` / `rg` (search file contents) → `Grep`\n- `echo` / `printf` (talk to the user) → just output text directly\n\nThe dedicated tools render in the per-tool permission UI and keep raw stdout out of the conversation; that is why they are worth reaching for whenever one fits.\n\n**Output:**\nThe stdout and stderr will be combined and returned as a string. The output may be truncated if it is too long. If the command exits non-zero, the output ends with a `Command failed with exit code: N` line; a command killed by its timeout or interrupted by the user ends with its own message instead.\n\nIf `run_in_background=true`, the command will be started as a background task and this tool will return a task ID instead of waiting for command completion. When doing that, you must provide a short `description`. Background commands default to a ${DEFAULT_BACKGROUND_TIMEOUT_S}s timeout and `timeout` is capped at ${MAX_BACKGROUND_TIMEOUT_S}s; set `disable_timeout=true` only when the task should run without a timeout. You will be automatically notified when the task completes. After starting one, default to returning control to the user instead of immediately waiting on it. Use `TaskOutput` only for a non-blocking status/output snapshot — do not wait on a task you just launched, since its completion arrives automatically. Use `TaskStop` only if the task must be cancelled. If a human user wants to inspect background tasks themselves, point them to the `/tasks` command, which opens an interactive panel; it has no subcommands.\n\n**Guidelines for safety and security:**\n- Each shell tool call will be executed in a fresh shell environment. The shell variables, current working directory changes, and the shell history is not preserved between calls. To run a command in a particular directory, pass the `cwd` argument (or use absolute paths) rather than relying on a `cd` from an earlier call.\n- The tool call will return after the command is finished. You shall not use this tool to execute an interactive command or a command that may run forever. For possibly long-running foreground commands, set the `timeout` argument in seconds. Foreground commands default to ${DEFAULT_TIMEOUT_S}s and allow up to ${MAX_TIMEOUT_S}s. When a foreground command hits its timeout it is moved to the background instead of being killed, and you will be automatically notified when it completes.\n- Avoid using `..` to access files or directories outside of the working directory.\n- Avoid modifying files outside of the working directory unless explicitly instructed to do so.\n- Never run commands that require superuser privileges unless explicitly instructed to do so.\n\n**Guidelines for efficiency:**\n- Use `&&` to chain commands that genuinely depend on each other, e.g. `npm install && npm test`. Independent read-only commands (separate `git show`, `ls`, or status checks) should be issued as separate parallel Bash calls in one response, not chained into a single call — chaining serializes their execution and mixes their output. Do not stitch outputs together with `echo` separators.\n- Use `;` to run commands sequentially regardless of success/failure\n- Use `||` for conditional execution (run second command only if first fails)\n- Use pipe operations (`|`) and redirections (`>`, `>>`) to chain input and output between commands\n- Always quote file paths containing spaces with double quotes (e.g., cd \"/path with spaces/\")\n- Compose multi-step logic in a single call with `if` / `case` / `for` / `while` control flows.\n- Prefer `run_in_background=true` for long-running builds, tests, watchers, or servers when you need the conversation to continue before the command finishes.\n\n**Commands available:**\nThe following common command categories are usually available. Availability still depends on the host, so when in doubt run `which <command>` first to confirm a command exists before relying on it.\n- Navigation and inspection: `ls`, `pwd`, `cd`, `stat`, `file`, `du`, `df`, `tree`\n- File and directory management: `cp`, `mv`, `rm`, `mkdir`, `touch`, `ln`, `chmod`, `chown`\n- Text and data processing: `wc`, `sort`, `uniq`, `cut`, `tr`, `diff`, `xargs`\n- Archives and compression: `tar`, `gzip`, `gunzip`, `zip`, `unzip`\n- Networking and transfer: `curl`, `wget`, `ping`, `ssh`, `scp`\n- Version control: `git`; for GitHub-hosted work (PRs, issues, CI runs, API queries) prefer the `gh` CLI when installed — it carries the user's GitHub auth and can return structured JSON\n- Process and system: `ps`, `kill`, `top`, `env`, `date`, `uname`, `whoami`\n- Language and package toolchains: `node`, `npm`, `pnpm`, `yarn`, `python`, `pip` (use whichever the project actually relies on)\n";
|
|
104349
|
+
bash_default = "Execute a `${SHELL_NAME}` command. Use this for shell semantics — pipes, env, processes, git, package managers, build/test runners, anything genuinely interactive or multi-step.\n\n**Translate these to a dedicated tool instead:**\n- `cat` / `head` / `tail` (known path) → `Read`\n- `sed` / `awk` (in-place edit) → `Edit`\n- `echo > file` / `cat <<EOF` → `Write`\n- `find` / recursive `ls` to locate files by name pattern → `Glob` (plain `ls <known-directory>` is fine for listing a directory)\n- `grep` / `rg` (search file contents) → `Grep`\n- `echo` / `printf` (talk to the user) → just output text directly\n\nThe dedicated tools render in the per-tool permission UI and keep raw stdout out of the conversation; that is why they are worth reaching for whenever one fits.\n\n**Output:**\nThe stdout and stderr will be combined and returned as a string. The output may be truncated if it is too long. If the command exits non-zero, the output ends with a `Command failed with exit code: N` line; a command killed by its timeout or interrupted by the user ends with its own message instead.\n\nIf `run_in_background=true`, the command will be started as a background task and this tool will return a task ID instead of waiting for command completion. When doing that, you must provide a short `description`. Background commands default to a ${DEFAULT_BACKGROUND_TIMEOUT_S}s timeout and `timeout` is capped at ${MAX_BACKGROUND_TIMEOUT_S}s; set `disable_timeout=true` only when the task should run without a timeout. You will be automatically notified when the task completes. After starting one, default to returning control to the user instead of immediately waiting on it. Use `TaskOutput` only for a non-blocking status/output snapshot — do not wait on a task you just launched, since its completion arrives automatically. Use `TaskStop` only if the task must be cancelled. If a human user wants to inspect background tasks themselves, point them to the `/tasks` command, which opens an interactive panel; it has no subcommands.\n\n**Detached processes:** If a command leaves processes running in its process group after the shell exits (e.g. `nohup … &`, `… &`, `disown`), the result includes a notice listing them. Those processes are not tracked by dimi: you will not be notified when they finish, `TaskStop` cannot stop them, and a `WaitFor` only wakes on timeout. If the detach was intentional (e.g. starting a daemon), you may ignore the notice; otherwise prefer `run_in_background=true` so dimi manages the process and notifies you. Note this detection covers processes that stayed in the command's process group; a process that deliberately escapes to its own session (e.g. daemonizers, `setsid`) is not detectable after the command exits and is typically intentional.\n\n**Guidelines for safety and security:**\n- Each shell tool call will be executed in a fresh shell environment. The shell variables, current working directory changes, and the shell history is not preserved between calls. To run a command in a particular directory, pass the `cwd` argument (or use absolute paths) rather than relying on a `cd` from an earlier call.\n- The tool call will return after the command is finished. You shall not use this tool to execute an interactive command or a command that may run forever. For possibly long-running foreground commands, set the `timeout` argument in seconds. Foreground commands default to ${DEFAULT_TIMEOUT_S}s and allow up to ${MAX_TIMEOUT_S}s. When a foreground command hits its timeout it is moved to the background instead of being killed, and you will be automatically notified when it completes.\n- Avoid using `..` to access files or directories outside of the working directory.\n- Avoid modifying files outside of the working directory unless explicitly instructed to do so.\n- Never run commands that require superuser privileges unless explicitly instructed to do so.\n\n**Guidelines for efficiency:**\n- Use `&&` to chain commands that genuinely depend on each other, e.g. `npm install && npm test`. Independent read-only commands (separate `git show`, `ls`, or status checks) should be issued as separate parallel Bash calls in one response, not chained into a single call — chaining serializes their execution and mixes their output. Do not stitch outputs together with `echo` separators.\n- Use `;` to run commands sequentially regardless of success/failure\n- Use `||` for conditional execution (run second command only if first fails)\n- Use pipe operations (`|`) and redirections (`>`, `>>`) to chain input and output between commands\n- Always quote file paths containing spaces with double quotes (e.g., cd \"/path with spaces/\")\n- Compose multi-step logic in a single call with `if` / `case` / `for` / `while` control flows.\n- Prefer `run_in_background=true` for long-running builds, tests, watchers, or servers when you need the conversation to continue before the command finishes.\n\n**Commands available:**\nThe following common command categories are usually available. Availability still depends on the host, so when in doubt run `which <command>` first to confirm a command exists before relying on it.\n- Navigation and inspection: `ls`, `pwd`, `cd`, `stat`, `file`, `du`, `df`, `tree`\n- File and directory management: `cp`, `mv`, `rm`, `mkdir`, `touch`, `ln`, `chmod`, `chown`\n- Text and data processing: `wc`, `sort`, `uniq`, `cut`, `tr`, `diff`, `xargs`\n- Archives and compression: `tar`, `gzip`, `gunzip`, `zip`, `unzip`\n- Networking and transfer: `curl`, `wget`, `ping`, `ssh`, `scp`\n- Version control: `git`; for GitHub-hosted work (PRs, issues, CI runs, API queries) prefer the `gh` CLI when installed — it carries the user's GitHub auth and can return structured JSON\n- Process and system: `ps`, `kill`, `top`, `env`, `date`, `uname`, `whoami`\n- Language and package toolchains: `node`, `npm`, `pnpm`, `yarn`, `python`, `pip` (use whichever the project actually relies on)\n";
|
|
104350
104350
|
}));
|
|
104351
104351
|
//#endregion
|
|
104352
104352
|
//#region ../../packages/agent-core-v2/src/agent/tools/os/bash/process-task.ts
|
|
@@ -104571,6 +104571,75 @@ function foregroundDescription(args) {
|
|
|
104571
104571
|
if (explicit !== void 0 && explicit.length > 0) return explicit;
|
|
104572
104572
|
return `Bash: ${args.command.length > 60 ? `${args.command.slice(0, 60)}…` : args.command}`;
|
|
104573
104573
|
}
|
|
104574
|
+
/**
|
|
104575
|
+
* Detect processes that outlived the command's process group on Unix.
|
|
104576
|
+
*
|
|
104577
|
+
* dimi spawns every shell in its own session/process group (`setsid`, pid ==
|
|
104578
|
+
* sid == pgid), so `nohup`/`&`/`disown` children that survive the shell stay
|
|
104579
|
+
* in that same process group. Probing `kill(-pid, 0)` (process-group kill)
|
|
104580
|
+
* tells us whether any process is still there after the command finished;
|
|
104581
|
+
* `ps -g <pid>` then lists who.
|
|
104582
|
+
*
|
|
104583
|
+
* Scope: this covers processes that stayed in the command's process group
|
|
104584
|
+
* (the common accidental detach: `nohup … &`, `… &`, `disown`). A process
|
|
104585
|
+
* that actively escapes (calls `setsid`, or moves to its own group with
|
|
104586
|
+
* `setpgid`/`setpgrp`, e.g. daemonizers, `start_new_session=True`, node
|
|
104587
|
+
* `{detached:true}`) leaves the group entirely and cannot be attributed back
|
|
104588
|
+
* after the shell exits — such escapes are typically intentional and are out
|
|
104589
|
+
* of scope here. Windows has no session/process-group kill, so detection is
|
|
104590
|
+
* skipped there (returns []).
|
|
104591
|
+
*/
|
|
104592
|
+
async function detectDetachedProcesses(pid) {
|
|
104593
|
+
if (process.platform === "win32" || !Number.isInteger(pid) || pid <= 0) return [];
|
|
104594
|
+
let alive = false;
|
|
104595
|
+
try {
|
|
104596
|
+
process.kill(-pid, 0);
|
|
104597
|
+
alive = true;
|
|
104598
|
+
} catch (error) {
|
|
104599
|
+
alive = error.code === "EPERM";
|
|
104600
|
+
}
|
|
104601
|
+
if (!alive) return [];
|
|
104602
|
+
return listProcessGroupProcesses(pid);
|
|
104603
|
+
}
|
|
104604
|
+
async function listProcessGroupProcesses(pid) {
|
|
104605
|
+
const { execFile } = await import("node:child_process");
|
|
104606
|
+
const ps = await new Promise((resolve) => {
|
|
104607
|
+
execFile("ps", [
|
|
104608
|
+
"-o",
|
|
104609
|
+
"pid=,ppid=,command=",
|
|
104610
|
+
"-g",
|
|
104611
|
+
String(pid)
|
|
104612
|
+
], (error, stdout) => {
|
|
104613
|
+
resolve(error === null ? stdout : "");
|
|
104614
|
+
});
|
|
104615
|
+
});
|
|
104616
|
+
const infos = [];
|
|
104617
|
+
for (const line of ps.split("\n")) {
|
|
104618
|
+
const trimmed = line.trim();
|
|
104619
|
+
if (trimmed.length === 0) continue;
|
|
104620
|
+
const match = /^(\d+)\s+(\d+)\s+(.*)$/.exec(trimmed);
|
|
104621
|
+
if (match === null) continue;
|
|
104622
|
+
const childPid = Number(match[1]);
|
|
104623
|
+
if (childPid === pid) continue;
|
|
104624
|
+
infos.push({
|
|
104625
|
+
pid: childPid,
|
|
104626
|
+
ppid: Number(match[2]),
|
|
104627
|
+
command: match[3] ?? ""
|
|
104628
|
+
});
|
|
104629
|
+
}
|
|
104630
|
+
return infos;
|
|
104631
|
+
}
|
|
104632
|
+
/**
|
|
104633
|
+
* Rendered guidance appended to a Bash result when the finished command left
|
|
104634
|
+
* detached processes behind. Informational only — the command result itself
|
|
104635
|
+
* is unchanged; the agent decides whether the detach was intended.
|
|
104636
|
+
*/
|
|
104637
|
+
function formatDetachedProcessNotice(infos) {
|
|
104638
|
+
return `
|
|
104639
|
+
|
|
104640
|
+
⚠ Command left processes running outside dimi control:
|
|
104641
|
+
${infos.map((info) => ` - pid ${String(info.pid)} (ppid ${String(info.ppid)}): ${info.command}`).join("\n")}\nThese processes are NOT tracked by dimi: dimi cannot notify you when they finish, cannot stop them with TaskStop, and a WaitFor will only wake on timeout. If this was intentional (e.g. starting a daemon), ignore this notice. Otherwise, prefer running the command with run_in_background=true so dimi manages it.`;
|
|
104642
|
+
}
|
|
104574
104643
|
async function killSpawnedProcess(proc) {
|
|
104575
104644
|
try {
|
|
104576
104645
|
await proc.kill("SIGTERM");
|
|
@@ -104581,6 +104650,15 @@ async function killSpawnedProcess(proc) {
|
|
|
104581
104650
|
function shellQuote(s) {
|
|
104582
104651
|
return `'${s.replaceAll("'", "'\\''")}'`;
|
|
104583
104652
|
}
|
|
104653
|
+
function partToResultText(part) {
|
|
104654
|
+
switch (part.type) {
|
|
104655
|
+
case "text": return part.text;
|
|
104656
|
+
case "think": return part.think;
|
|
104657
|
+
case "image_url": return "[image]";
|
|
104658
|
+
case "audio_url": return "[audio]";
|
|
104659
|
+
case "video_url": return "[video]";
|
|
104660
|
+
}
|
|
104661
|
+
}
|
|
104584
104662
|
function windowsPathToPosixPath(path) {
|
|
104585
104663
|
if (path.startsWith("\\\\")) return path.replaceAll("\\", "/");
|
|
104586
104664
|
const driveMatch = /^([A-Za-z]):(?:[\\/]|$)/.exec(path);
|
|
@@ -104819,7 +104897,31 @@ var init_bashTool = __esmMin((() => {
|
|
|
104819
104897
|
if (builder.nChars === 0) builder.write(`Process exited with code ${String(exitCode)}`);
|
|
104820
104898
|
result = builder.error(`Command failed with exit code: ${String(exitCode)}.`, { brief: `Failed with exit code: ${String(exitCode)}` });
|
|
104821
104899
|
}
|
|
104822
|
-
|
|
104900
|
+
const withReference = await this.addForegroundOutputReference(taskId, result);
|
|
104901
|
+
return this.addDetachedProcessNotice(proc, withReference);
|
|
104902
|
+
}
|
|
104903
|
+
/**
|
|
104904
|
+
* After a foreground command finishes, check whether it left processes
|
|
104905
|
+
* running in the command's process group (e.g. `nohup … &`) that dimi can
|
|
104906
|
+
* no longer track. When it did, append an informational notice to the
|
|
104907
|
+
* result — the exit code / error status is untouched, and the agent
|
|
104908
|
+
* decides whether the detach was intended. Processes that actively escape
|
|
104909
|
+
* to their own session/group (setsid, daemonizers) cannot be detected
|
|
104910
|
+
* after the shell exits and are out of scope.
|
|
104911
|
+
*/
|
|
104912
|
+
async addDetachedProcessNotice(proc, result) {
|
|
104913
|
+
const infos = await this.detectDetached(proc.pid);
|
|
104914
|
+
if (infos.length === 0) return result;
|
|
104915
|
+
const output = result.output;
|
|
104916
|
+
const text = typeof output === "string" ? output : output.map(partToResultText).join("");
|
|
104917
|
+
return {
|
|
104918
|
+
...result,
|
|
104919
|
+
output: `${text}${formatDetachedProcessNotice(infos)}`
|
|
104920
|
+
};
|
|
104921
|
+
}
|
|
104922
|
+
/** Overridable seam for tests: probe for processes that escaped the session. */
|
|
104923
|
+
detectDetached(pid) {
|
|
104924
|
+
return detectDetachedProcesses(pid);
|
|
104823
104925
|
}
|
|
104824
104926
|
async addForegroundOutputReference(taskId, result) {
|
|
104825
104927
|
if (!result.truncated) return result;
|
|
@@ -123100,7 +123202,7 @@ var init_waitService = __esmMin((() => {
|
|
|
123100
123202
|
//#region ../../packages/agent-core-v2/src/agent/tools/wait-for/wait-for.md?raw
|
|
123101
123203
|
var wait_for_default;
|
|
123102
123204
|
var init_wait_for = __esmMin((() => {
|
|
123103
|
-
wait_for_default = "Wait for a future notification when no independent work remains. Provide a concise reason and an optional timeout in seconds. The default is 60 seconds; use longer waits only for clearly long-running work, up to 1800 seconds.\n\nCall WaitFor by itself. It waits on the current agent, not a specific task. Any later notification wakes the agent. A timeout wakes the agent with an explicit `wait_expired` message and never cancels background work.\n\nWhen you are waiting on an external state that can change on its own (a file being written, a service coming up, a process finishing, a remote resource becoming ready, …), do not just park on a timeout and re-check later. Start a background Bash task that polls exactly the part of that state you care about and exits as soon as it changes — for example a loop that checks every few seconds and breaks on the expected condition, printing what changed. Because a finished background task notifies the agent, the wait then wakes you the moment the state flips instead of on a blind timeout, and you can act immediately. Keep the polling script narrowly scoped to the monitored condition and make sure it terminates on its own (or after the wait timeout); do not leave a watcher running forever.\n\nSurface errors from the watcher loudly instead of hiding them. If a check fails, a command errors, or the target becomes unreachable, print the error and exit with a non-zero code so the failed background task wakes you with the real reason — then you can diagnose and retry immediately. Do not swallow failures with `|| true`, `2>/dev/null`, or a `continue` that keeps polling forever; a watcher that silently runs to timeout hides the very condition you are waiting on.\n\n";
|
|
123205
|
+
wait_for_default = "Wait for a future notification when no independent work remains. Provide a concise reason and an optional timeout in seconds. The default is 60 seconds; use longer waits only for clearly long-running work, up to 1800 seconds.\n\nCall WaitFor by itself. It waits on the current agent, not a specific task. Any later notification wakes the agent. A timeout wakes the agent with an explicit `wait_expired` message and never cancels background work.\n\nWhen you are waiting on an external state that can change on its own (a file being written, a service coming up, a process finishing, a remote resource becoming ready, …), do not just park on a timeout and re-check later. Start a background Bash task that polls exactly the part of that state you care about and exits as soon as it changes — for example a loop that checks every few seconds and breaks on the expected condition, printing what changed. Because a finished background task notifies the agent, the wait then wakes you the moment the state flips instead of on a blind timeout, and you can act immediately. Keep the polling script narrowly scoped to the monitored condition and make sure it terminates on its own (or after the wait timeout); do not leave a watcher running forever.\n\nStart the watcher as a dimi background task with `run_in_background=true` on the Bash tool — never launch it detached from the session (no `nohup`, no `&` outside the tool, no cron or external scheduler). Only a dimi background task is tracked by the agent runtime, so only its completion (success or failure) can wake the wait; a detached process is invisible to dimi, gives no notification, and leaves you sleeping until the timeout. The watcher must exit on its own when the state flips or the wait deadline passes.\n\nSurface errors from the watcher loudly instead of hiding them. If a check fails, a command errors, or the target becomes unreachable, print the error and exit with a non-zero code so the failed background task wakes you with the real reason — then you can diagnose and retry immediately. Do not swallow failures with `|| true`, `2>/dev/null`, or a `continue` that keeps polling forever; a watcher that silently runs to timeout hides the very condition you are waiting on.\n\n\n";
|
|
123104
123206
|
}));
|
|
123105
123207
|
//#endregion
|
|
123106
123208
|
//#region ../../packages/agent-core-v2/src/agent/tools/wait-for/waitForTool.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dimi-agent/cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.7",
|
|
4
4
|
"description": "The Starting Point for Next-Gen Agents",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -61,13 +61,13 @@
|
|
|
61
61
|
"yazl": "^3.3.1",
|
|
62
62
|
"zod": "^4.3.6",
|
|
63
63
|
"@dimi-agent/agent-core-v2": "^0.1.0",
|
|
64
|
-
"@dimi-agent/dimi-oauth": "^0.1.0",
|
|
65
64
|
"@dimi-agent/dimi-sdk": "^0.2.0",
|
|
65
|
+
"@dimi-agent/dimi-oauth": "^0.1.0",
|
|
66
66
|
"@dimi-agent/dimi-telemetry": "^0.1.0",
|
|
67
67
|
"@dimi-agent/dimi-web": "^0.1.0",
|
|
68
|
-
"@dimi-agent/kap-server": "^0.1.0",
|
|
69
68
|
"@dimi-agent/pi-tui": "^0.1.0",
|
|
70
|
-
"@dimi-agent/remote": "^0.1.0"
|
|
69
|
+
"@dimi-agent/remote": "^0.1.0",
|
|
70
|
+
"@dimi-agent/kap-server": "^0.1.0"
|
|
71
71
|
},
|
|
72
72
|
"optionalDependencies": {
|
|
73
73
|
"@dimi-agent/dimi-native-darwin-arm64": ">=0.5.3 <1",
|