@lobehub/cli 0.0.63 → 0.0.64
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/index.js +85 -21
- package/man/man1/lh.1 +1 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ import { finished, pipeline } from "node:stream/promises";
|
|
|
14
14
|
import { Duplex, PassThrough, Readable, Transform, Writable, getDefaultHighWaterMark, pipeline as pipeline$1 } from "node:stream";
|
|
15
15
|
import readline, { createInterface } from "node:readline";
|
|
16
16
|
import { EventEmitter, addAbortListener, on, once, setMaxListeners } from "node:events";
|
|
17
|
-
import fs$1, { access, chmod, copyFile, cp, lstat, mkdir, open, readFile, readdir, readlink, realpath, rename, rm, stat, unlink as unlink$1, writeFile } from "node:fs/promises";
|
|
17
|
+
import fs$1, { access, chmod, copyFile, cp, lstat, mkdir, mkdtemp, open, readFile, readdir, readlink, realpath, rename, rm, stat, unlink as unlink$1, writeFile } from "node:fs/promises";
|
|
18
18
|
import crypto$1, { X509Certificate, createHash, randomBytes, randomUUID, sign } from "node:crypto";
|
|
19
19
|
import { text } from "node:stream/consumers";
|
|
20
20
|
import { ReadableStream as ReadableStream$1 } from "node:stream/web";
|
|
@@ -23324,6 +23324,7 @@ const TRPC_NAMESPACE_API_KEY_RULES = {
|
|
|
23324
23324
|
user: rw("user:read", "user:write"),
|
|
23325
23325
|
userMemories: rw("user:read", "user:write"),
|
|
23326
23326
|
userMemory: rw("user:read", "user:write"),
|
|
23327
|
+
userSkill: rw("agent:read", "agent:write"),
|
|
23327
23328
|
verify: "blocked",
|
|
23328
23329
|
video: { any: "model:invoke" },
|
|
23329
23330
|
waitlist: "blocked",
|
|
@@ -292724,21 +292725,56 @@ var init_src = __esmMin((() => {
|
|
|
292724
292725
|
//#endregion
|
|
292725
292726
|
//#region ../../packages/local-file-shell/src/shell/runner.ts
|
|
292726
292727
|
/**
|
|
292727
|
-
*
|
|
292728
|
-
*
|
|
292729
|
-
*
|
|
292730
|
-
*
|
|
292728
|
+
* `true` = resolves to a directory; `false` = resolves to a non-directory
|
|
292729
|
+
* (a regular file); `undefined` = cannot be resolved at all (missing, an
|
|
292730
|
+
* unreadable parent, a symlink loop). Keeping the three cases apart lets the
|
|
292731
|
+
* report name what actually happened instead of guessing.
|
|
292731
292732
|
*/
|
|
292732
|
-
const
|
|
292733
|
+
const statIsDirectory = async (dir) => {
|
|
292733
292734
|
try {
|
|
292734
|
-
|
|
292735
|
-
|
|
292736
|
-
|
|
292737
|
-
if (error.code !== "ENOENT") return;
|
|
292738
|
-
return `Working directory does not exist on ${os.hostname()}: ${cwd}. The shell is fine — run the command from a directory that exists on this device.`;
|
|
292735
|
+
return (await stat(dir)).isDirectory();
|
|
292736
|
+
} catch {
|
|
292737
|
+
return;
|
|
292739
292738
|
}
|
|
292740
292739
|
};
|
|
292741
|
-
|
|
292740
|
+
/**
|
|
292741
|
+
* Resolve a requested cwd to a directory the shell can actually start in.
|
|
292742
|
+
*
|
|
292743
|
+
* A cwd pinned on another machine (a stale repo path, a moved worktree) would
|
|
292744
|
+
* otherwise kill every command in the run: the run cannot change its own pinned
|
|
292745
|
+
* cwd, callers strip a model-supplied cwd before dispatch, and re-running
|
|
292746
|
+
* `cd` inside the command does not help because the check happens before the
|
|
292747
|
+
* shell exists — so the same failure repeats forever. Un-sandboxed runs fall
|
|
292748
|
+
* back to a fresh isolated directory created under the OS temp root, and the
|
|
292749
|
+
* fallback is reported so nothing downstream mistakes it for the requested
|
|
292750
|
+
* directory.
|
|
292751
|
+
*
|
|
292752
|
+
* Sandboxed runs do NOT fall back: the sandbox fence (`createLocalSandboxPolicy`)
|
|
292753
|
+
* is built on the requested cwd, so silently spawning in another directory
|
|
292754
|
+
* would grant writes somewhere the user never approved. Those fail loudly.
|
|
292755
|
+
*/
|
|
292756
|
+
const resolveWorkingDirectory = async (requestedCwd, sandboxRequested, fallbackRoot) => {
|
|
292757
|
+
const usable = await statIsDirectory(requestedCwd);
|
|
292758
|
+
if (usable) return { cwd: requestedCwd };
|
|
292759
|
+
const reason = usable === false ? `Working directory is not a directory on ${os.hostname()}: ${requestedCwd}` : `Working directory does not exist on ${os.hostname()}: ${requestedCwd}`;
|
|
292760
|
+
if (sandboxRequested) return { error: `${reason}. A sandboxed run must start in its requested directory — the sandbox fence is built on it — so the command was not run.` };
|
|
292761
|
+
try {
|
|
292762
|
+
const fallback = await mkdtemp(path.join(fallbackRoot ?? os.tmpdir(), "lobehub-cwd-fallback-"));
|
|
292763
|
+
return {
|
|
292764
|
+
cwd: fallback,
|
|
292765
|
+
notice: `${reason}. Falling back to ${fallback}.`,
|
|
292766
|
+
remove: async () => {
|
|
292767
|
+
await rm(fallback, {
|
|
292768
|
+
force: true,
|
|
292769
|
+
recursive: true
|
|
292770
|
+
});
|
|
292771
|
+
}
|
|
292772
|
+
};
|
|
292773
|
+
} catch {
|
|
292774
|
+
return { error: `${reason}. The shell is fine — run the command from a directory that exists on this device.` };
|
|
292775
|
+
}
|
|
292776
|
+
};
|
|
292777
|
+
async function runCommand$1({ command, cwd, description, env: extraEnv, run_in_background, timeout = DEFAULT_OBSERVATION_TIMEOUT_MS }, { backend: backendOverride, processManager, logger, onSandboxUnavailable, sandboxPolicy, spawnProcess, tmpdirOverride }) {
|
|
292742
292778
|
if (!command) return {
|
|
292743
292779
|
error: "command is required",
|
|
292744
292780
|
success: false
|
|
@@ -292750,12 +292786,18 @@ async function runCommand$1({ command, cwd, description, env: extraEnv, run_in_b
|
|
|
292750
292786
|
cwd,
|
|
292751
292787
|
timeout
|
|
292752
292788
|
});
|
|
292789
|
+
let effectiveCwd = cwd;
|
|
292790
|
+
let cwdNotice;
|
|
292791
|
+
let removeCwdFallback;
|
|
292753
292792
|
if (cwd) {
|
|
292754
|
-
const
|
|
292755
|
-
if (
|
|
292756
|
-
error:
|
|
292793
|
+
const resolution = await resolveWorkingDirectory(cwd, !!sandboxPolicy, tmpdirOverride);
|
|
292794
|
+
if (resolution.error) return {
|
|
292795
|
+
error: resolution.error,
|
|
292757
292796
|
success: false
|
|
292758
292797
|
};
|
|
292798
|
+
effectiveCwd = resolution.cwd;
|
|
292799
|
+
cwdNotice = resolution.notice;
|
|
292800
|
+
removeCwdFallback = resolution.remove;
|
|
292759
292801
|
}
|
|
292760
292802
|
const requestedEnv = extraEnv ? {
|
|
292761
292803
|
...process.env,
|
|
@@ -292763,6 +292805,7 @@ async function runCommand$1({ command, cwd, description, env: extraEnv, run_in_b
|
|
|
292763
292805
|
} : process.env;
|
|
292764
292806
|
const shellConfig = await getShellConfig(process.platform === "win32" ? normalizeEnvVarRefs(command, requestedEnv, (await detectWindowsShell()).type) : command);
|
|
292765
292807
|
let outputFiles;
|
|
292808
|
+
let registered = false;
|
|
292766
292809
|
let releaseSandbox;
|
|
292767
292810
|
let sandboxed;
|
|
292768
292811
|
try {
|
|
@@ -292774,7 +292817,7 @@ async function runCommand$1({ command, cwd, description, env: extraEnv, run_in_b
|
|
|
292774
292817
|
try {
|
|
292775
292818
|
launchPlan = await createSandboxLaunchPlan({
|
|
292776
292819
|
command: shellConfig,
|
|
292777
|
-
cwd,
|
|
292820
|
+
cwd: effectiveCwd,
|
|
292778
292821
|
env: requestedEnv,
|
|
292779
292822
|
policy: sandboxPolicy
|
|
292780
292823
|
});
|
|
@@ -292794,7 +292837,7 @@ async function runCommand$1({ command, cwd, description, env: extraEnv, run_in_b
|
|
|
292794
292837
|
args: launchCommand.args,
|
|
292795
292838
|
cmd: launchCommand.cmd
|
|
292796
292839
|
}, {
|
|
292797
|
-
cwd,
|
|
292840
|
+
cwd: effectiveCwd,
|
|
292798
292841
|
env: launchEnv,
|
|
292799
292842
|
outputFiles: shellOutputFiles,
|
|
292800
292843
|
shellId
|
|
@@ -292818,21 +292861,27 @@ async function runCommand$1({ command, cwd, description, env: extraEnv, run_in_b
|
|
|
292818
292861
|
shellProcess.spawnError = new Error(`Failed to start command${cwdContext}: ${error.message}`, { cause: error });
|
|
292819
292862
|
shellProcess.exitCode = 1;
|
|
292820
292863
|
});
|
|
292821
|
-
handle.once("close", () =>
|
|
292864
|
+
handle.once("close", () => {
|
|
292865
|
+
releaseSandbox?.();
|
|
292866
|
+
if (removeCwdFallback) removeCwdFallback().catch((error) => {
|
|
292867
|
+
logger?.debug(`${logPrefix} Fallback directory cleanup failed`, { error });
|
|
292868
|
+
});
|
|
292869
|
+
});
|
|
292822
292870
|
processManager.register(shellId, shellProcess);
|
|
292871
|
+
registered = true;
|
|
292823
292872
|
processManager.closeOutputFiles(shellOutputFiles);
|
|
292824
292873
|
logger?.info?.(`${logPrefix} Started session`, {
|
|
292825
292874
|
background: run_in_background,
|
|
292826
292875
|
shellId
|
|
292827
292876
|
});
|
|
292828
292877
|
if (run_in_background) return {
|
|
292829
|
-
output: "",
|
|
292878
|
+
output: cwdNotice ?? "",
|
|
292830
292879
|
output_files: processManager.getOutputFilesInfo(shellOutputFiles),
|
|
292831
292880
|
sandboxed,
|
|
292832
292881
|
shell_id: shellId,
|
|
292833
292882
|
success: true
|
|
292834
292883
|
};
|
|
292835
|
-
|
|
292884
|
+
const result = {
|
|
292836
292885
|
...await processManager.getRunCommandOutput({
|
|
292837
292886
|
shell_id: shellId,
|
|
292838
292887
|
timeout
|
|
@@ -292840,9 +292889,17 @@ async function runCommand$1({ command, cwd, description, env: extraEnv, run_in_b
|
|
|
292840
292889
|
sandboxed,
|
|
292841
292890
|
shell_id: shellId
|
|
292842
292891
|
};
|
|
292892
|
+
if (!cwdNotice) return result;
|
|
292893
|
+
const prefix = `${cwdNotice}\n\n`;
|
|
292894
|
+
return {
|
|
292895
|
+
...result,
|
|
292896
|
+
output: `${prefix}${result.output ?? ""}`,
|
|
292897
|
+
stdout: `${prefix}${result.stdout ?? ""}`
|
|
292898
|
+
};
|
|
292843
292899
|
} catch (error) {
|
|
292844
292900
|
releaseSandbox?.();
|
|
292845
292901
|
if (outputFiles) processManager.closeOutputFiles(outputFiles);
|
|
292902
|
+
if (removeCwdFallback && !registered) await removeCwdFallback().catch(() => {});
|
|
292846
292903
|
return {
|
|
292847
292904
|
error: error.message,
|
|
292848
292905
|
success: false
|
|
@@ -512440,6 +512497,7 @@ const admissionHint = {
|
|
|
512440
512497
|
pending_decision: "a decision gate is still waiting on an answer",
|
|
512441
512498
|
review_changed: "task review feedback changed after this turn started",
|
|
512442
512499
|
stale_input: "the graph moved after this turn started, so the plan would apply to stale input",
|
|
512500
|
+
started_from_draft: "the Goal was started from its draft, which settled this turn; the next turn plans further work",
|
|
512443
512501
|
turn_owner: "this Goal has no matching planning turn",
|
|
512444
512502
|
turn_settled: "this turn's run is no longer running",
|
|
512445
512503
|
wait_unsettled: "unfinished work must be settled before waiting",
|
|
@@ -512695,10 +512753,12 @@ function registerGoalCommand$1(program) {
|
|
|
512695
512753
|
};
|
|
512696
512754
|
const result = fromTopic ? hasOperationToken() ? await client.goal.createConversationGoal.mutate({
|
|
512697
512755
|
...goalInput,
|
|
512756
|
+
draft: true,
|
|
512698
512757
|
operationId
|
|
512699
512758
|
}) : await client.goal.create.mutate({
|
|
512700
512759
|
...goalInput,
|
|
512701
512760
|
agentId: process.env.LOBEHUB_AGENT_ID,
|
|
512761
|
+
draft: true,
|
|
512702
512762
|
conversationOperationId: operationId,
|
|
512703
512763
|
conversationTopicId: process.env.LOBEHUB_TOPIC_ID
|
|
512704
512764
|
}) : await client.goal.create.mutate({
|
|
@@ -512726,7 +512786,11 @@ function registerGoalCommand$1(program) {
|
|
|
512726
512786
|
"first; every other seed task (or only --units) leaves the graph as a roster unit, its description",
|
|
512727
512787
|
"kept as that unit's note, and is released wave by wave once the probes ran through without a person.",
|
|
512728
512788
|
"A rejection revises the recipe and re-probes. Tasks that differ only in names, files or details are",
|
|
512729
|
-
"one recipe; tasks whose steps differ are not, so start those without --rollout."
|
|
512789
|
+
"one recipe; tasks whose steps differ are not, so start those without --rollout.",
|
|
512790
|
+
"Inside a batch a seed may depend only on a probe, and folded seeds need distinct titles.",
|
|
512791
|
+
"",
|
|
512792
|
+
"Starting a draft that holds tasks settles the planning turn that created it: submit any plan with",
|
|
512793
|
+
"lh goal plan before starting, not after."
|
|
512730
512794
|
].join("\n")).option("--rollout <mode>", "Fold the seed tasks into a batch: canary or full").option("--probes <nodeIds...>", "Seed task node ids that run first (2-5 for canary)").option("--units <nodeIds...>", "Seed task node ids that become batch units (default: every other seed)").option("--recipe <text>", "The procedure every unit follows").option("--recipe-file <path>", "Read the recipe from a markdown file").option("--variant <axis=values...>", "An axis the units differ along, e.g. mechanism=replica,swr (repeatable); the gate holds until the probes cover each value").option("--operation <id>", "Defaults to LOBEHUB_OPERATION_ID").option("--json", "Output JSON").action(async (id, options) => {
|
|
512731
512795
|
let rollout;
|
|
512732
512796
|
if (options.rollout) {
|
package/man/man1/lh.1
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
.\" Code generated by `npm run man:generate`; DO NOT EDIT.
|
|
2
2
|
.\" Manual command details come from the Commander command tree.
|
|
3
|
-
.TH LH 1 "" "@lobehub/cli 0.0.
|
|
3
|
+
.TH LH 1 "" "@lobehub/cli 0.0.64" "User Commands"
|
|
4
4
|
.SH NAME
|
|
5
5
|
lh \- LobeHub CLI \- manage and connect to LobeHub services
|
|
6
6
|
.SH SYNOPSIS
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.64",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"lh": "dist/index.js",
|
|
@@ -41,18 +41,18 @@
|
|
|
41
41
|
"url-join": "^5.0.0",
|
|
42
42
|
"vitest": "5.0.0",
|
|
43
43
|
"@lobechat/const": "1.0.0",
|
|
44
|
-
"@lobechat/device-control": "1.0.0",
|
|
45
44
|
"@lobechat/agent-gateway-client": "1.0.0",
|
|
46
45
|
"@lobechat/agent-tracing": "1.0.0",
|
|
47
|
-
"@lobechat/eval-rubric": "1.0.0",
|
|
48
46
|
"@lobechat/device-gateway-client": "1.0.0",
|
|
49
47
|
"@lobechat/device-identity": "1.0.0",
|
|
48
|
+
"@lobechat/eval-rubric": "1.0.0",
|
|
49
|
+
"@lobechat/device-control": "1.0.0",
|
|
50
|
+
"@lobechat/heterogeneous-agents": "1.0.0",
|
|
50
51
|
"@lobechat/html-artifact": "1.0.0",
|
|
51
52
|
"@lobechat/local-file-shell": "1.0.0",
|
|
52
|
-
"@lobechat/heterogeneous-agents": "1.0.0",
|
|
53
53
|
"@lobechat/tool-runtime": "1.0.0",
|
|
54
|
-
"@lobechat/
|
|
55
|
-
"@lobechat/
|
|
54
|
+
"@lobechat/utils": "1.0.0",
|
|
55
|
+
"@lobechat/types": "1.0.0"
|
|
56
56
|
},
|
|
57
57
|
"engines": {
|
|
58
58
|
"node": ">=22.15"
|