@linzumi/cli 0.0.34-beta → 0.0.36-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -1
- package/dist/index.js +46 -32
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,10 +50,61 @@ real dotfiles, and your real branches. No "works in the sandbox VM,
|
|
|
50
50
|
breaks in your repo" surprises. The chat side runs in your browser;
|
|
51
51
|
the work side runs locally. This npm package is the local half.
|
|
52
52
|
|
|
53
|
+
## What you'll have in three minutes
|
|
54
|
+
|
|
55
|
+
- A Linzumi workspace in your browser.
|
|
56
|
+
- A local Commander connected to one trusted project folder.
|
|
57
|
+
- A live Coding agent thread your team can watch and steer.
|
|
58
|
+
- Optional browser editor and preview forwarding for the running app.
|
|
59
|
+
|
|
60
|
+
## Manual Runner Setup
|
|
61
|
+
|
|
62
|
+
Install the CLI or run it with `npx`:
|
|
63
|
+
|
|
53
64
|
```bash
|
|
65
|
+
npm install -g @linzumi/cli@latest
|
|
66
|
+
npx -y @linzumi/cli@0.0.36-beta --version
|
|
54
67
|
linzumi --version
|
|
55
68
|
```
|
|
56
69
|
|
|
70
|
+
Start a local runner from a trusted folder:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
linzumi paths add ~/code/my-app
|
|
74
|
+
linzumi start ~/code/my-app
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
For explicit runner roots, pass a comma-separated allowlist:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
linzumi start ~/code/my-app --allowed-cwd <paths>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Agent-first launch path
|
|
84
|
+
|
|
85
|
+
The fastest path is still the `codex` prompt above. It uses the npm CLI
|
|
86
|
+
to sign in, trust a demo project, connect the Commander, and start the
|
|
87
|
+
first visible Coding agent thread.
|
|
88
|
+
|
|
89
|
+
## What just happened
|
|
90
|
+
|
|
91
|
+
Linzumi keeps the browser/chat surface separate from the local work
|
|
92
|
+
surface. The CLI authenticates your local Commander, publishes runner
|
|
93
|
+
capabilities, and lets Kandan ask that Commander to start Codex inside
|
|
94
|
+
trusted folders only.
|
|
95
|
+
|
|
96
|
+
## Three things to try first
|
|
97
|
+
|
|
98
|
+
- Ask the Coding agent to make a small UI change and watch the thread.
|
|
99
|
+
- Open the browser editor from the thread controls.
|
|
100
|
+
- Share the preview URL with a teammate or your phone.
|
|
101
|
+
|
|
102
|
+
## Working as a team
|
|
103
|
+
|
|
104
|
+
Use the Linzumi thread as the shared source of truth. Humans can reply,
|
|
105
|
+
steer, interrupt, or inspect output while the actual commands still run
|
|
106
|
+
on the trusted local machine.
|
|
107
|
+
|
|
57
108
|
## Trusted folders
|
|
58
109
|
|
|
59
110
|
Linzumi only edits inside folders you've explicitly trusted.
|
|
@@ -63,7 +114,15 @@ linzumi paths add ~/code/my-app
|
|
|
63
114
|
```
|
|
64
115
|
|
|
65
116
|
The trust list lives at `~/.linzumi/config.json`. The bootstrap agent
|
|
66
|
-
adds `/tmp/hello_linzumi` for you on first run.
|
|
117
|
+
adds `/tmp/hello_linzumi` for you on first run. For `linzumi connect`, the
|
|
118
|
+
selected `--cwd` is also trusted for that runner process.
|
|
119
|
+
|
|
120
|
+
## When something looks wrong
|
|
121
|
+
|
|
122
|
+
Run `linzumi --help` or reconnect with `linzumi start ~/code/my-app`.
|
|
123
|
+
If the browser says no runner is connected, check that the terminal
|
|
124
|
+
running the Commander is still open and that the folder is listed in
|
|
125
|
+
`~/.linzumi/config.json`.
|
|
67
126
|
|
|
68
127
|
---
|
|
69
128
|
|
package/dist/index.js
CHANGED
|
@@ -5680,7 +5680,7 @@ function kandanHttpBaseUrl(kandanUrl) {
|
|
|
5680
5680
|
case "https:":
|
|
5681
5681
|
break;
|
|
5682
5682
|
default:
|
|
5683
|
-
throw new Error("--
|
|
5683
|
+
throw new Error("--linzumi-url must be ws://, wss://, http://, or https://");
|
|
5684
5684
|
}
|
|
5685
5685
|
parsed.pathname = "";
|
|
5686
5686
|
parsed.search = "";
|
|
@@ -9354,6 +9354,7 @@ async function waitForFileChangeOrTimeout(path, deadline, now, ready2 = () => fa
|
|
|
9354
9354
|
// src/index.ts
|
|
9355
9355
|
var flagDefinitions = new Map([
|
|
9356
9356
|
["version", { kind: "boolean" }],
|
|
9357
|
+
["linzumi-url", { kind: "value" }],
|
|
9357
9358
|
["kandan-url", { kind: "value" }],
|
|
9358
9359
|
["token", { kind: "value" }],
|
|
9359
9360
|
["runner-id", { kind: "value" }],
|
|
@@ -9363,6 +9364,7 @@ var flagDefinitions = new Map([
|
|
|
9363
9364
|
["launch-tui", { kind: "boolean" }],
|
|
9364
9365
|
["workspace", { kind: "value" }],
|
|
9365
9366
|
["channel", { kind: "value" }],
|
|
9367
|
+
["linzumi-thread-id", { kind: "value" }],
|
|
9366
9368
|
["kandan-thread-id", { kind: "value" }],
|
|
9367
9369
|
["listen-user", { kind: "value" }],
|
|
9368
9370
|
["model", { kind: "value" }],
|
|
@@ -9382,6 +9384,10 @@ var flagDefinitions = new Map([
|
|
|
9382
9384
|
["oauth-callback-host", { kind: "value" }],
|
|
9383
9385
|
["help", { kind: "boolean" }]
|
|
9384
9386
|
]);
|
|
9387
|
+
var flagAliases = new Map([
|
|
9388
|
+
["kandan-url", "linzumi-url"],
|
|
9389
|
+
["kandan-thread-id", "linzumi-thread-id"]
|
|
9390
|
+
]);
|
|
9385
9391
|
var helloFlagDefinitions = new Map([
|
|
9386
9392
|
["dir", { kind: "value" }],
|
|
9387
9393
|
["parent-dir", { kind: "value" }],
|
|
@@ -9415,7 +9421,7 @@ async function main(args) {
|
|
|
9415
9421
|
process.stdout.write(connectGuideText());
|
|
9416
9422
|
return;
|
|
9417
9423
|
case "version":
|
|
9418
|
-
process.stdout.write(`linzumi 0.0.
|
|
9424
|
+
process.stdout.write(`linzumi 0.0.36-beta
|
|
9419
9425
|
`);
|
|
9420
9426
|
return;
|
|
9421
9427
|
case "auth":
|
|
@@ -9661,7 +9667,7 @@ async function runAuthCommand(args) {
|
|
|
9661
9667
|
process.stdout.write(helpText());
|
|
9662
9668
|
return;
|
|
9663
9669
|
}
|
|
9664
|
-
const kandanUrl = required(values, "
|
|
9670
|
+
const kandanUrl = required(values, "linzumi-url");
|
|
9665
9671
|
const target = parseOptionalChannelTarget(values);
|
|
9666
9672
|
const token = await acquireLocalRunnerTokenDetails({
|
|
9667
9673
|
kandanUrl,
|
|
@@ -9675,7 +9681,7 @@ async function runAuthCommand(args) {
|
|
|
9675
9681
|
expiresInSeconds: token.expiresInSeconds,
|
|
9676
9682
|
authFilePath: stringValue3(values, "auth-file")
|
|
9677
9683
|
});
|
|
9678
|
-
process.stdout.write(`Saved
|
|
9684
|
+
process.stdout.write(`Saved Linzumi local runner auth for ${cached.kandanBaseUrl}
|
|
9679
9685
|
`);
|
|
9680
9686
|
}
|
|
9681
9687
|
async function parseStartRunnerArgs(args, deps = {
|
|
@@ -9692,7 +9698,7 @@ async function parseStartRunnerArgs(args, deps = {
|
|
|
9692
9698
|
process.exit(0);
|
|
9693
9699
|
}
|
|
9694
9700
|
rejectStartTargetingFlags(values);
|
|
9695
|
-
const kandanUrl = stringValue3(values, "
|
|
9701
|
+
const kandanUrl = stringValue3(values, "linzumi-url") ?? defaultLinzumiWebSocketUrl;
|
|
9696
9702
|
const requestedCwd = resolveUserPath(cwdArg ?? process.cwd());
|
|
9697
9703
|
const cwd = assertConfiguredAllowedCwds([requestedCwd])[0] ?? requestedCwd;
|
|
9698
9704
|
const explicitAllowedCwds = values.has("allowed-cwd") ? assertConfiguredAllowedCwds(parseAllowedCwdList(stringValue3(values, "allowed-cwd"))) : [];
|
|
@@ -9709,7 +9715,7 @@ async function parseStartRunnerArgs(args, deps = {
|
|
|
9709
9715
|
const authFilePath = stringValue3(values, "auth-file");
|
|
9710
9716
|
const callbackHost = stringValue3(values, "oauth-callback-host");
|
|
9711
9717
|
const reportRejectedCachedToken = () => {
|
|
9712
|
-
process.stderr.write(`Cached
|
|
9718
|
+
process.stderr.write(`Cached Linzumi local runner auth was rejected; starting OAuth.
|
|
9713
9719
|
`);
|
|
9714
9720
|
};
|
|
9715
9721
|
const token = await deps.resolveToken({
|
|
@@ -9768,7 +9774,7 @@ async function parseStartRunnerArgs(args, deps = {
|
|
|
9768
9774
|
channelSession: {
|
|
9769
9775
|
workspaceSlug: target.workspaceSlug,
|
|
9770
9776
|
channelSlug: target.channelSlug,
|
|
9771
|
-
kandanThreadId: stringValue3(values, "
|
|
9777
|
+
kandanThreadId: stringValue3(values, "linzumi-thread-id"),
|
|
9772
9778
|
listenUser: stringValue3(values, "listen-user") ?? defaultListenUserFromToken(targetToken),
|
|
9773
9779
|
model: stringValue3(values, "model"),
|
|
9774
9780
|
reasoningEffort: stringValue3(values, "reasoning-effort"),
|
|
@@ -9797,7 +9803,7 @@ async function parseAgentRunnerArgs(args, deps = {
|
|
|
9797
9803
|
const tokenFile = readStoredAgentTokenFile(tokenFilePath, deps.readTextFile);
|
|
9798
9804
|
const channelSlug = requiredStoredAgentChannel(tokenFile.channelId);
|
|
9799
9805
|
const listenUser = stringValue3(values, "listen-user") ?? requiredStoredOwnerUsername(tokenFile.ownerUsername);
|
|
9800
|
-
const kandanUrl = stringValue3(values, "
|
|
9806
|
+
const kandanUrl = stringValue3(values, "linzumi-url") ?? agentApiUrlToKandanUrl(tokenFile.apiUrl);
|
|
9801
9807
|
const requestedCwdValue = cwdArg ?? stringValue3(values, "cwd");
|
|
9802
9808
|
const requestedCwd = resolveUserPath(requestedCwdValue ?? process.cwd());
|
|
9803
9809
|
const allowedCwds = values.has("allowed-cwd") ? assertConfiguredAllowedCwds(parseAllowedCwdList(stringValue3(values, "allowed-cwd"))) : requestedCwdValue === undefined ? readConfiguredAllowedCwds() : assertConfiguredAllowedCwds([requestedCwd]);
|
|
@@ -9842,7 +9848,7 @@ async function parseAgentRunnerArgs(args, deps = {
|
|
|
9842
9848
|
channelSession: {
|
|
9843
9849
|
workspaceSlug: tokenFile.workspaceId,
|
|
9844
9850
|
channelSlug,
|
|
9845
|
-
kandanThreadId: stringValue3(values, "
|
|
9851
|
+
kandanThreadId: stringValue3(values, "linzumi-thread-id"),
|
|
9846
9852
|
listenUser,
|
|
9847
9853
|
model: stringValue3(values, "model"),
|
|
9848
9854
|
reasoningEffort: stringValue3(values, "reasoning-effort"),
|
|
@@ -9929,13 +9935,15 @@ async function parseRunnerArgs(args, deps = {
|
|
|
9929
9935
|
process.exit(0);
|
|
9930
9936
|
}
|
|
9931
9937
|
if (values.get("version") === true) {
|
|
9932
|
-
process.stdout.write(`linzumi 0.0.
|
|
9938
|
+
process.stdout.write(`linzumi 0.0.36-beta
|
|
9933
9939
|
`);
|
|
9934
9940
|
process.exit(0);
|
|
9935
9941
|
}
|
|
9936
9942
|
const channelTarget = parseChannelSessionTarget(values);
|
|
9937
|
-
const kandanUrl = required(values, "
|
|
9943
|
+
const kandanUrl = required(values, "linzumi-url");
|
|
9938
9944
|
const cwd = stringValue3(values, "cwd") ?? process.cwd();
|
|
9945
|
+
const cwdAllowedCwds = assertConfiguredAllowedCwds([cwd]);
|
|
9946
|
+
const configuredAllowedCwds = values.has("allowed-cwd") ? assertConfiguredAllowedCwds(parseAllowedCwdList(stringValue3(values, "allowed-cwd"))) : readConfiguredAllowedCwds();
|
|
9939
9947
|
const codexBin = stringValue3(values, "codex-bin") ?? "codex";
|
|
9940
9948
|
const customCodeServerBin = stringValue3(values, "code-server-bin");
|
|
9941
9949
|
const explicitToken = stringValue3(values, "token");
|
|
@@ -9947,7 +9955,7 @@ async function parseRunnerArgs(args, deps = {
|
|
|
9947
9955
|
authFilePath: stringValue3(values, "auth-file"),
|
|
9948
9956
|
callbackHost: stringValue3(values, "oauth-callback-host"),
|
|
9949
9957
|
reportRejectedCachedToken: () => {
|
|
9950
|
-
process.stderr.write(`Cached
|
|
9958
|
+
process.stderr.write(`Cached Linzumi local runner auth was rejected; starting OAuth.
|
|
9951
9959
|
`);
|
|
9952
9960
|
}
|
|
9953
9961
|
});
|
|
@@ -9975,7 +9983,7 @@ async function parseRunnerArgs(args, deps = {
|
|
|
9975
9983
|
launchTui: values.get("launch-tui") === true,
|
|
9976
9984
|
fast: values.get("fast") === true,
|
|
9977
9985
|
logFile: stringValue3(values, "log-file"),
|
|
9978
|
-
allowedCwds:
|
|
9986
|
+
allowedCwds: Array.from(new Set([...cwdAllowedCwds, ...configuredAllowedCwds])),
|
|
9979
9987
|
allowedForwardPorts: parseAllowedPortList(stringValue3(values, "forward-port")),
|
|
9980
9988
|
codeServerBin: editorRuntime.codeServerBin,
|
|
9981
9989
|
editorRuntime: editorRuntime.runtime,
|
|
@@ -9991,18 +9999,19 @@ function strictFlagValues(args, definitions = flagDefinitions) {
|
|
|
9991
9999
|
if (arg === undefined || !arg.startsWith("--")) {
|
|
9992
10000
|
throw new Error(`invalid argument: ${arg ?? ""}`);
|
|
9993
10001
|
}
|
|
9994
|
-
const
|
|
9995
|
-
const definition = definitions.get(
|
|
10002
|
+
const rawKey = arg.slice(2);
|
|
10003
|
+
const definition = definitions.get(rawKey);
|
|
9996
10004
|
if (definition === undefined) {
|
|
9997
|
-
throw new Error(`invalid flag: --${
|
|
10005
|
+
throw new Error(`invalid flag: --${rawKey}`);
|
|
9998
10006
|
}
|
|
10007
|
+
const key = flagAliases.get(rawKey) ?? rawKey;
|
|
9999
10008
|
if (definition.kind === "boolean") {
|
|
10000
10009
|
values.set(key, true);
|
|
10001
10010
|
continue;
|
|
10002
10011
|
}
|
|
10003
10012
|
const next = args[index + 1];
|
|
10004
10013
|
if (next === undefined || next.startsWith("--")) {
|
|
10005
|
-
throw new Error(`missing value for --${
|
|
10014
|
+
throw new Error(`missing value for --${rawKey}`);
|
|
10006
10015
|
}
|
|
10007
10016
|
values.set(key, next);
|
|
10008
10017
|
index += 1;
|
|
@@ -10089,7 +10098,7 @@ function parseChannelSession(values, token, target) {
|
|
|
10089
10098
|
return {
|
|
10090
10099
|
workspaceSlug: target.workspaceSlug,
|
|
10091
10100
|
channelSlug: target.channelSlug,
|
|
10092
|
-
kandanThreadId: stringValue3(values, "
|
|
10101
|
+
kandanThreadId: stringValue3(values, "linzumi-thread-id"),
|
|
10093
10102
|
listenUser,
|
|
10094
10103
|
model: stringValue3(values, "model"),
|
|
10095
10104
|
reasoningEffort: stringValue3(values, "reasoning-effort"),
|
|
@@ -10185,11 +10194,12 @@ Usage:
|
|
|
10185
10194
|
linzumi commander <folder> [options]
|
|
10186
10195
|
linzumi start <folder> [options]
|
|
10187
10196
|
linzumi paths list|add|remove [path]
|
|
10188
|
-
linzumi connect --
|
|
10189
|
-
linzumi auth --
|
|
10197
|
+
linzumi connect --linzumi-url <ws-url> --workspace <slug> --channel <slug> [options]
|
|
10198
|
+
linzumi auth --linzumi-url <ws-url> [--workspace <slug> --channel <slug>]
|
|
10190
10199
|
|
|
10191
10200
|
Required:
|
|
10192
|
-
--
|
|
10201
|
+
--linzumi-url <ws-url> Linzumi backend URL, default ${defaultLinzumiWebSocketUrl}
|
|
10202
|
+
(deprecated alias: --kandan-url)
|
|
10193
10203
|
--token <jwt> Optional override token. Otherwise ~/.linzumi/auth.json is validated or OAuth opens.
|
|
10194
10204
|
--auth-file <path> Auth cache path, default ~/.linzumi/auth.json
|
|
10195
10205
|
--oauth-callback-host <ip> Callback host reachable by your browser
|
|
@@ -10197,7 +10207,8 @@ Required:
|
|
|
10197
10207
|
Channel binding:
|
|
10198
10208
|
--workspace <slug> Workspace slug
|
|
10199
10209
|
--channel <slug|w/c> Channel slug, or workspace/channel
|
|
10200
|
-
--
|
|
10210
|
+
--linzumi-thread-id <uuid> Resume an existing Linzumi thread instead of announcing a new root
|
|
10211
|
+
(deprecated alias: --kandan-thread-id)
|
|
10201
10212
|
--listen-user <user|all> User whose replies are accepted, default authenticated user
|
|
10202
10213
|
|
|
10203
10214
|
Codex:
|
|
@@ -10212,7 +10223,7 @@ Codex:
|
|
|
10212
10223
|
--stream-flush-ms <ms> Batch live Codex deltas before Linzumi persistence, default 150
|
|
10213
10224
|
--fast Mark this runner as low-latency/fast in the availability message
|
|
10214
10225
|
--log-file <path> JSONL event log path, default <cwd>/.linzumi-runner.log
|
|
10215
|
-
--allowed-cwd <paths>
|
|
10226
|
+
--allowed-cwd <paths> Extra comma-separated roots where Linzumi may start local Codex sessions
|
|
10216
10227
|
--forward-port <ports> Comma-separated local TCP ports Linzumi may expose as authenticated previews
|
|
10217
10228
|
--code-server-bin <path> Custom development code-server executable. The default editor runtime is downloaded from Linzumi.
|
|
10218
10229
|
|
|
@@ -10309,8 +10320,9 @@ Usage:
|
|
|
10309
10320
|
linzumi paths add <path>
|
|
10310
10321
|
linzumi paths remove <path>
|
|
10311
10322
|
|
|
10312
|
-
Trusted paths are stored in ~/.linzumi/config.json. linzumi connect
|
|
10313
|
-
|
|
10323
|
+
Trusted paths are stored in ~/.linzumi/config.json. linzumi connect always
|
|
10324
|
+
trusts its selected cwd for that runner process and also uses configured paths
|
|
10325
|
+
unless --allowed-cwd is passed with explicit extra roots.
|
|
10314
10326
|
`;
|
|
10315
10327
|
}
|
|
10316
10328
|
function startHelpText() {
|
|
@@ -10326,7 +10338,8 @@ What it does:
|
|
|
10326
10338
|
previews, and the browser VS Code editor.
|
|
10327
10339
|
|
|
10328
10340
|
Options:
|
|
10329
|
-
--
|
|
10341
|
+
--linzumi-url <ws-url> Linzumi backend URL, default ${defaultLinzumiWebSocketUrl}
|
|
10342
|
+
(deprecated alias: --kandan-url)
|
|
10330
10343
|
--token <jwt> Optional scoped local-runner token override
|
|
10331
10344
|
--auth-file <path> Auth cache path, default ~/.linzumi/auth.json
|
|
10332
10345
|
--oauth-callback-host <ip> Callback host reachable by your browser
|
|
@@ -10366,23 +10379,24 @@ What it does:
|
|
|
10366
10379
|
|
|
10367
10380
|
Options:
|
|
10368
10381
|
--agent-token-file <path> Agent token cache, default ~/.linzumi/agent-token.json
|
|
10369
|
-
--
|
|
10382
|
+
--linzumi-url <ws-url> Linzumi websocket base URL. Defaults deterministically from the stored apiUrl.
|
|
10383
|
+
(deprecated alias: --kandan-url)
|
|
10370
10384
|
--runner-id <id> Stable Commander id
|
|
10371
10385
|
--codex-bin <path> Codex executable, default codex
|
|
10372
|
-
--code-server-bin <path> Custom development code-server executable. By default
|
|
10386
|
+
--code-server-bin <path> Custom development code-server executable. By default Linzumi installs the approved editor runtime.
|
|
10373
10387
|
--listen-user <user> Human whose replies Codex may accept, default owner from claim
|
|
10374
10388
|
--model <name> Model requested for Codex sessions
|
|
10375
10389
|
--reasoning-effort <value> Reasoning effort requested for Codex sessions
|
|
10376
|
-
--sandbox <value> Sandbox metadata shown in
|
|
10377
|
-
--approval-policy <value> Approval-policy metadata shown in
|
|
10378
|
-
--forward-port <ports> Comma-separated local TCP ports
|
|
10390
|
+
--sandbox <value> Sandbox metadata shown in Linzumi
|
|
10391
|
+
--approval-policy <value> Approval-policy metadata shown in Linzumi
|
|
10392
|
+
--forward-port <ports> Comma-separated local TCP ports Linzumi may expose as previews
|
|
10379
10393
|
--allowed-cwd <paths> Override ~/.linzumi/config.json or selected folder with comma-separated trusted roots
|
|
10380
10394
|
--fast Mark this Commander as low-latency/fast in Linzumi
|
|
10381
10395
|
|
|
10382
10396
|
Examples:
|
|
10383
10397
|
linzumi paths add "$PWD"
|
|
10384
10398
|
linzumi commander daemon --runner-id hello-world-commander
|
|
10385
|
-
linzumi commander ~/code/my-app --
|
|
10399
|
+
linzumi commander ~/code/my-app --linzumi-url ws://127.0.0.1:4162 --runner-id local-qa-commander
|
|
10386
10400
|
`;
|
|
10387
10401
|
}
|
|
10388
10402
|
function connectGuideText() {
|
package/package.json
CHANGED