@linzumi/cli 0.0.22-beta → 0.0.24-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 +31 -16
- package/dist/index.js +138 -42
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,8 +32,20 @@ starts that hot-reload app on your computer, creates the shared support
|
|
|
32
32
|
channel, starts a Linzumi Codex session in a work thread, and opens the
|
|
33
33
|
browser editor pointed at the demo app.
|
|
34
34
|
|
|
35
|
+
Terms:
|
|
36
|
+
|
|
37
|
+
- **Bootstrapper Codex**: the outer Codex started by the pasted command. It
|
|
38
|
+
sets up Linzumi and local processes, but does not edit the demo app.
|
|
39
|
+
- **Linzumi Commander**: the long-running local bridge started with
|
|
40
|
+
`linzumi commander`; it owns the secure tunnel, trusted folder, browser
|
|
41
|
+
editor, and inner Codex launch.
|
|
42
|
+
- **Linzumi Codex session**: the inner agent running inside the Linzumi thread;
|
|
43
|
+
it edits `/tmp/hello_linzumi` and posts progress.
|
|
44
|
+
- **Human**: the workspace owner who opens the one-time login link and watches
|
|
45
|
+
the work in `#general` and `#linzumi-support`.
|
|
46
|
+
|
|
35
47
|
The snippet uses automatic command approval and full local process access
|
|
36
|
-
because the bootstrapper must start a real
|
|
48
|
+
because the bootstrapper must start a real Linzumi Commander and browser editor on this
|
|
37
49
|
computer. It is intentionally not the dangerous sandbox-bypass mode.
|
|
38
50
|
|
|
39
51
|
Today, your AI coding agent has two homes, both bad.
|
|
@@ -104,7 +116,7 @@ stays available for compatibility. The bootstrap agent will confirm your
|
|
|
104
116
|
email and workspace choice up front, ask for the emailed code after signup
|
|
105
117
|
sends it, say hello to `@sean` in the shared support channel,
|
|
106
118
|
generate `/tmp/hello_linzumi`, start its hot-reload Node server, start the
|
|
107
|
-
|
|
119
|
+
Commander for that folder, start a Linzumi Codex session in a work thread, and
|
|
108
120
|
open the browser editor. The Linzumi Codex session then adds confetti to the
|
|
109
121
|
demo page while you watch. Workspace names are plain display names from 2 to
|
|
110
122
|
100 characters; Linzumi generates the URL-safe workspace slug.
|
|
@@ -117,25 +129,28 @@ Codex command.
|
|
|
117
129
|
npx -y @linzumi/cli@latest signup --email alice@example.com --workspace-name "Alice's Linzumi" --agent-name BuildBot
|
|
118
130
|
npx -y @linzumi/cli@latest claim --pending <pending_id> --code <XXXX-XXXX>
|
|
119
131
|
npx -y @linzumi/cli@latest channel post <support_channel_id> "Hello @sean, starting this launch run."
|
|
120
|
-
npx -y @linzumi/cli@latest
|
|
132
|
+
npx -y @linzumi/cli@latest thread new "Hello Linzumi confetti" --message "Preparing the Hello Linzumi demo. Next I will generate /tmp/hello_linzumi, start its hot-reload server bound to 0.0.0.0 on port 8787, and ask Linzumi Codex to add confetti when the page loads."
|
|
133
|
+
commander_id="hello-linzumi-commander-${thread_id%%-*}"
|
|
134
|
+
npx -y @linzumi/cli@latest init-hello-linzumi-demo-app --parent-dir /tmp --name hello_linzumi --host 0.0.0.0 --port 8787 --reset --json
|
|
121
135
|
(cd /tmp/hello_linzumi && npm run dev > /tmp/hello_linzumi/dev.log 2>&1 &)
|
|
122
|
-
npx -y @linzumi/cli@latest
|
|
123
|
-
|
|
124
|
-
--runner-id hello-linzumi-agent \
|
|
136
|
+
npx -y @linzumi/cli@latest commander /tmp/hello_linzumi \
|
|
137
|
+
--runner-id "$commander_id" \
|
|
125
138
|
--allowed-cwd /tmp/hello_linzumi \
|
|
126
139
|
--forward-port 8787 \
|
|
127
140
|
--sandbox danger-full-access \
|
|
128
141
|
--approval-policy never
|
|
129
142
|
```
|
|
130
143
|
|
|
131
|
-
The agent-owned
|
|
144
|
+
The agent-owned Commander reads `~/.linzumi/agent-token.json`, uses the
|
|
132
145
|
workspace/channel scope from the approval flow, trusts only the selected
|
|
133
146
|
folder, advertises the explicit preview port, and listens only to the
|
|
134
|
-
approving human unless `--listen-user` is explicitly passed.
|
|
135
|
-
|
|
147
|
+
approving human unless `--listen-user` is explicitly passed. Use a unique
|
|
148
|
+
Commander id per launch thread; Linzumi stores trusted-folder config per
|
|
149
|
+
Commander id, so reusing an old fixed id can pick up stale allowed-cwd config.
|
|
150
|
+
The bootstrap agent waits for `Runner connected:` before starting Codex in the Linzumi
|
|
136
151
|
thread.
|
|
137
152
|
|
|
138
|
-
By default, the
|
|
153
|
+
By default, the Commander downloads the Linzumi-approved `code-server`
|
|
139
154
|
runtime for your platform and verifies its checksum before enabling the
|
|
140
155
|
browser editor. Linux editor launches are wrapped with `bubblewrap`
|
|
141
156
|
(`bwrap`) for filesystem confinement.
|
|
@@ -146,20 +161,20 @@ workspace. The claim also provisions `#linzumi-support`, a shared channel
|
|
|
146
161
|
connected to Linzumi's workspace so our team can see setup issues from our
|
|
147
162
|
side; the bootstrap agent posts a hello there with the printed
|
|
148
163
|
`support_channel_id`.
|
|
149
|
-
Keep demo work in task threads; use the support channel when signup,
|
|
164
|
+
Keep demo work in task threads; use the support channel when signup, Commander,
|
|
150
165
|
preview, or browser-editor setup gets stuck.
|
|
151
166
|
|
|
152
|
-
Once the
|
|
167
|
+
Once the Commander is online, the bootstrap agent can ask Linzumi to start
|
|
153
168
|
Codex and open the browser editor for the same thread and folder:
|
|
154
169
|
|
|
155
170
|
```bash
|
|
156
171
|
npx -y @linzumi/cli@latest codex start <thread_id> \
|
|
157
|
-
--runner
|
|
172
|
+
--runner "$commander_id" \
|
|
158
173
|
--cwd /tmp/hello_linzumi \
|
|
159
174
|
--work-description "Work only in /tmp/hello_linzumi. Add tasteful confetti when the Hello Linzumi page loads, keep the hot-reload app working on port 8787, and post the exact files changed."
|
|
160
175
|
|
|
161
176
|
npx -y @linzumi/cli@latest editor open <thread_id> \
|
|
162
|
-
--runner
|
|
177
|
+
--runner "$commander_id" \
|
|
163
178
|
--cwd /tmp/hello_linzumi
|
|
164
179
|
```
|
|
165
180
|
|
|
@@ -261,7 +276,7 @@ intentionally. Every action is auditable from the thread.
|
|
|
261
276
|
## Pinning a version
|
|
262
277
|
|
|
263
278
|
```bash
|
|
264
|
-
npm install -g @linzumi/cli@0.0.
|
|
279
|
+
npm install -g @linzumi/cli@0.0.24-beta
|
|
265
280
|
linzumi --version
|
|
266
281
|
```
|
|
267
282
|
|
|
@@ -284,7 +299,7 @@ linzumi connect \
|
|
|
284
299
|
### All the flags
|
|
285
300
|
|
|
286
301
|
```text
|
|
287
|
-
--agent-token-file <path> Agent token cache for `linzumi
|
|
302
|
+
--agent-token-file <path> Agent token cache for `linzumi commander`
|
|
288
303
|
--oauth-callback-host <ip> Sign-in callback host your browser can reach
|
|
289
304
|
--codex-bin <path> Codex executable, default `codex`
|
|
290
305
|
--model <name> Model requested for Codex sessions and labelled in Linzumi
|
package/dist/index.js
CHANGED
|
@@ -7773,48 +7773,92 @@ Launch target:
|
|
|
7773
7773
|
}
|
|
7774
7774
|
|
|
7775
7775
|
// src/helloLinzumiProject.ts
|
|
7776
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "node:fs";
|
|
7776
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync7, readFileSync as readFileSync6, rmSync as rmSync2, writeFileSync as writeFileSync6 } from "node:fs";
|
|
7777
7777
|
import { dirname as dirname7, join as join7, resolve as resolve5 } from "node:path";
|
|
7778
7778
|
import { fileURLToPath } from "node:url";
|
|
7779
7779
|
var defaultHelloLinzumiProjectDir = "/tmp/hello_linzumi";
|
|
7780
|
+
var defaultHelloLinzumiProjectName = "hello_linzumi";
|
|
7781
|
+
var defaultHelloLinzumiParentDir = "/tmp";
|
|
7782
|
+
var defaultHelloLinzumiPort = 8787;
|
|
7783
|
+
var defaultHelloLinzumiHost = "0.0.0.0";
|
|
7780
7784
|
var markerFile = ".linzumi-demo-project";
|
|
7781
7785
|
var moduleDir = dirname7(fileURLToPath(import.meta.url));
|
|
7782
7786
|
var linzumiLogoSvg = readFileSync6(join7(moduleDir, "assets", "linzumi-logo.svg"), "utf8");
|
|
7783
|
-
function createHelloLinzumiProject(
|
|
7784
|
-
const
|
|
7785
|
-
|
|
7787
|
+
function createHelloLinzumiProject(input = {}) {
|
|
7788
|
+
const options = typeof input === "string" ? { rootPath: input } : input;
|
|
7789
|
+
const root = resolveHelloProjectRoot(options);
|
|
7790
|
+
const port = options.port ?? defaultHelloLinzumiPort;
|
|
7791
|
+
const host = normalizeHost(options.host);
|
|
7792
|
+
assertTcpPort(port);
|
|
7793
|
+
assertWritableDemoRoot(root, options.reset === true);
|
|
7786
7794
|
mkdirSync7(join7(root, "src"), { recursive: true });
|
|
7787
|
-
for (const file of demoFiles()) {
|
|
7795
|
+
for (const file of demoFiles({ root, port, host })) {
|
|
7788
7796
|
writeFileSync6(join7(root, file.path), file.content, "utf8");
|
|
7789
7797
|
}
|
|
7790
7798
|
return {
|
|
7791
7799
|
root,
|
|
7792
|
-
port
|
|
7800
|
+
port,
|
|
7801
|
+
host,
|
|
7793
7802
|
startCommand: "npm run dev",
|
|
7794
|
-
previewUrl:
|
|
7803
|
+
previewUrl: `http://${host}:${port}`
|
|
7795
7804
|
};
|
|
7796
7805
|
}
|
|
7797
|
-
function
|
|
7806
|
+
function resolveHelloProjectRoot(options) {
|
|
7807
|
+
if (options.rootPath !== undefined && (options.parentDir !== undefined || options.name !== undefined)) {
|
|
7808
|
+
throw new Error("linzumi init-hello-linzumi-demo-app accepts either --dir or --parent-dir/--name, not both");
|
|
7809
|
+
}
|
|
7810
|
+
if (options.rootPath !== undefined) {
|
|
7811
|
+
return resolve5(options.rootPath);
|
|
7812
|
+
}
|
|
7813
|
+
const name = normalizeProjectName(options.name ?? defaultHelloLinzumiProjectName);
|
|
7814
|
+
return resolve5(options.parentDir ?? defaultHelloLinzumiParentDir, name);
|
|
7815
|
+
}
|
|
7816
|
+
function normalizeProjectName(value) {
|
|
7817
|
+
const name = value.trim();
|
|
7818
|
+
if (name === "" || name === "." || name === ".." || name.includes("/") || name.includes("\\")) {
|
|
7819
|
+
throw new Error("--name must be a single directory name");
|
|
7820
|
+
}
|
|
7821
|
+
return name;
|
|
7822
|
+
}
|
|
7823
|
+
function normalizeHost(value) {
|
|
7824
|
+
const host = value?.trim() ?? defaultHelloLinzumiHost;
|
|
7825
|
+
if (host === "") {
|
|
7826
|
+
throw new Error("--host must not be empty");
|
|
7827
|
+
}
|
|
7828
|
+
return host;
|
|
7829
|
+
}
|
|
7830
|
+
function assertTcpPort(port) {
|
|
7831
|
+
if (Number.isInteger(port) && port > 0 && port <= 65535) {
|
|
7832
|
+
return;
|
|
7833
|
+
}
|
|
7834
|
+
throw new Error("--port must be a TCP port from 1 to 65535");
|
|
7835
|
+
}
|
|
7836
|
+
function assertWritableDemoRoot(root, reset) {
|
|
7798
7837
|
if (!existsSync7(root)) {
|
|
7799
7838
|
return;
|
|
7800
7839
|
}
|
|
7801
7840
|
const markerPath = join7(root, markerFile);
|
|
7802
|
-
|
|
7841
|
+
const isDemoRoot = existsSync7(markerPath) && readFileSync6(markerPath, "utf8").trim() === "hello-linzumi";
|
|
7842
|
+
if (isDemoRoot && reset) {
|
|
7843
|
+
rmSync2(root, { recursive: true, force: true });
|
|
7803
7844
|
return;
|
|
7804
7845
|
}
|
|
7805
|
-
|
|
7846
|
+
if (isDemoRoot) {
|
|
7847
|
+
return;
|
|
7848
|
+
}
|
|
7849
|
+
throw new Error(`${root} already exists and is not a Linzumi demo project; move it before rerunning linzumi init-hello-linzumi-demo-app`);
|
|
7806
7850
|
}
|
|
7807
|
-
function demoFiles() {
|
|
7851
|
+
function demoFiles(options) {
|
|
7808
7852
|
return [
|
|
7809
7853
|
{ path: markerFile, content: `hello-linzumi
|
|
7810
7854
|
` },
|
|
7811
7855
|
{ path: "package.json", content: packageJson },
|
|
7812
|
-
{ path: "server.mjs", content: serverSource },
|
|
7856
|
+
{ path: "server.mjs", content: serverSource(options) },
|
|
7813
7857
|
{ path: "index.html", content: htmlSource },
|
|
7814
|
-
{ path: "src/main.js", content: mainSource },
|
|
7858
|
+
{ path: "src/main.js", content: mainSource(options) },
|
|
7815
7859
|
{ path: "src/styles.css", content: cssSource },
|
|
7816
7860
|
{ path: "src/linzumi-logo.svg", content: linzumiLogoSvg },
|
|
7817
|
-
{ path: "README.md", content: readmeSource }
|
|
7861
|
+
{ path: "README.md", content: readmeSource(options) }
|
|
7818
7862
|
];
|
|
7819
7863
|
}
|
|
7820
7864
|
var packageJson = `${JSON.stringify({
|
|
@@ -7828,12 +7872,13 @@ var packageJson = `${JSON.stringify({
|
|
|
7828
7872
|
}
|
|
7829
7873
|
}, null, 2)}
|
|
7830
7874
|
`;
|
|
7831
|
-
var serverSource = `import { createReadStream, existsSync, statSync, watch } from "node:fs";
|
|
7875
|
+
var serverSource = ({ host, port }) => `import { createReadStream, existsSync, statSync, watch } from "node:fs";
|
|
7832
7876
|
import { extname, join, normalize } from "node:path";
|
|
7833
7877
|
import { createServer } from "node:http";
|
|
7834
7878
|
|
|
7835
7879
|
const root = process.cwd();
|
|
7836
|
-
const port = Number(process.env.PORT ?? "
|
|
7880
|
+
const port = Number(process.env.PORT ?? "${port}");
|
|
7881
|
+
const host = process.env.HOST ?? ${JSON.stringify(host)};
|
|
7837
7882
|
const clients = new Set();
|
|
7838
7883
|
|
|
7839
7884
|
const contentTypes = new Map([
|
|
@@ -7844,7 +7889,7 @@ const contentTypes = new Map([
|
|
|
7844
7889
|
]);
|
|
7845
7890
|
|
|
7846
7891
|
const server = createServer((request, response) => {
|
|
7847
|
-
const url = new URL(request.url ?? "/", "http://
|
|
7892
|
+
const url = new URL(request.url ?? "/", "http://0.0.0.0");
|
|
7848
7893
|
|
|
7849
7894
|
if (url.pathname === "/events") {
|
|
7850
7895
|
response.writeHead(200, {
|
|
@@ -7891,10 +7936,10 @@ for (const watchedPath of [join(root, "index.html"), join(root, "src")]) {
|
|
|
7891
7936
|
});
|
|
7892
7937
|
}
|
|
7893
7938
|
|
|
7894
|
-
server.listen(port,
|
|
7939
|
+
server.listen(port, host, () => {
|
|
7895
7940
|
const address = server.address();
|
|
7896
7941
|
const actualPort = typeof address === "object" && address !== null ? address.port : port;
|
|
7897
|
-
process.stdout.write(\`Hello Linzumi listening on http
|
|
7942
|
+
process.stdout.write(\`Hello Linzumi listening on http://\${host}:\${actualPort}\\n\`);
|
|
7898
7943
|
});
|
|
7899
7944
|
`;
|
|
7900
7945
|
var htmlSource = `<!doctype html>
|
|
@@ -8180,7 +8225,9 @@ h1 {
|
|
|
8180
8225
|
}
|
|
8181
8226
|
}
|
|
8182
8227
|
`;
|
|
8183
|
-
var mainSource = `const
|
|
8228
|
+
var mainSource = ({ root, host, port }) => `const projectLabel = ${JSON.stringify(`${root} · ${host}:${port}`)};
|
|
8229
|
+
|
|
8230
|
+
const prompts = [
|
|
8184
8231
|
"Add a soft confetti burst when I click the heading.",
|
|
8185
8232
|
"Make this a kanban board with three columns for my groceries.",
|
|
8186
8233
|
"Add a guestbook so my team can sign in.",
|
|
@@ -8236,7 +8283,7 @@ document.querySelector("#app").innerHTML = \`
|
|
|
8236
8283
|
</div>
|
|
8237
8284
|
|
|
8238
8285
|
<div class="footer-note">
|
|
8239
|
-
<code
|
|
8286
|
+
<code>\${escape(projectLabel)}</code>
|
|
8240
8287
|
<a href="https://linzumi.com" target="_blank" rel="noreferrer">linzumi.com →</a>
|
|
8241
8288
|
</div>
|
|
8242
8289
|
</div>
|
|
@@ -8261,10 +8308,10 @@ events.addEventListener("reload", () => {
|
|
|
8261
8308
|
window.location.reload();
|
|
8262
8309
|
});
|
|
8263
8310
|
`;
|
|
8264
|
-
var readmeSource = `# Linzumi launch demo
|
|
8311
|
+
var readmeSource = ({ host, port }) => `# Linzumi launch demo
|
|
8265
8312
|
|
|
8266
8313
|
A tiny Node-only HTTP server with browser live reload, generated by
|
|
8267
|
-
\`linzumi hello\`.
|
|
8314
|
+
\`linzumi init-hello-linzumi-demo-app\`.
|
|
8268
8315
|
|
|
8269
8316
|
Run it:
|
|
8270
8317
|
|
|
@@ -8272,7 +8319,8 @@ Run it:
|
|
|
8272
8319
|
npm run dev
|
|
8273
8320
|
\`\`\`
|
|
8274
8321
|
|
|
8275
|
-
|
|
8322
|
+
The app binds to \`${host}\` by default so Linzumi can reach it through the
|
|
8323
|
+
secure tunnel. Then open http://${host}:${port}. The page reloads when \`index.html\` or files
|
|
8276
8324
|
under \`src/\` change.
|
|
8277
8325
|
|
|
8278
8326
|
The bootstrap agent in your terminal has already opened the browser VS Code
|
|
@@ -8318,6 +8366,12 @@ var flagDefinitions = new Map([
|
|
|
8318
8366
|
]);
|
|
8319
8367
|
var helloFlagDefinitions = new Map([
|
|
8320
8368
|
["dir", { kind: "value" }],
|
|
8369
|
+
["parent-dir", { kind: "value" }],
|
|
8370
|
+
["name", { kind: "value" }],
|
|
8371
|
+
["port", { kind: "value" }],
|
|
8372
|
+
["host", { kind: "value" }],
|
|
8373
|
+
["reset", { kind: "boolean" }],
|
|
8374
|
+
["json", { kind: "boolean" }],
|
|
8321
8375
|
["help", { kind: "boolean" }]
|
|
8322
8376
|
]);
|
|
8323
8377
|
if (isMainModule()) {
|
|
@@ -8343,7 +8397,7 @@ async function main(args) {
|
|
|
8343
8397
|
process.stdout.write(connectGuideText());
|
|
8344
8398
|
return;
|
|
8345
8399
|
case "version":
|
|
8346
|
-
process.stdout.write(`linzumi 0.0.
|
|
8400
|
+
process.stdout.write(`linzumi 0.0.24-beta
|
|
8347
8401
|
`);
|
|
8348
8402
|
return;
|
|
8349
8403
|
case "auth":
|
|
@@ -8393,10 +8447,12 @@ function parseCommand(args) {
|
|
|
8393
8447
|
case "paths":
|
|
8394
8448
|
return { command: "paths", args: rest };
|
|
8395
8449
|
case "hello":
|
|
8450
|
+
case "init-hello-linzumi-demo-app":
|
|
8396
8451
|
return { command: "hello", args: rest };
|
|
8397
8452
|
case "agent":
|
|
8398
8453
|
return rest[0] === "runner" ? { command: "agentRunner", args: rest.slice(1) } : { command: "agent", args: rest };
|
|
8399
8454
|
case "agent-runner":
|
|
8455
|
+
case "commander":
|
|
8400
8456
|
return { command: "agentRunner", args: rest };
|
|
8401
8457
|
case "signup":
|
|
8402
8458
|
case "claim":
|
|
@@ -8422,12 +8478,32 @@ function runHelloCommand(args) {
|
|
|
8422
8478
|
process.stdout.write(helloHelpText());
|
|
8423
8479
|
return;
|
|
8424
8480
|
}
|
|
8425
|
-
const project = createHelloLinzumiProject(
|
|
8481
|
+
const project = createHelloLinzumiProject({
|
|
8482
|
+
rootPath: stringValue3(values, "dir"),
|
|
8483
|
+
parentDir: stringValue3(values, "parent-dir") === undefined ? undefined : resolveUserPath(required(values, "parent-dir")),
|
|
8484
|
+
name: stringValue3(values, "name"),
|
|
8485
|
+
port: tcpPortValue(values, "port"),
|
|
8486
|
+
host: stringValue3(values, "host"),
|
|
8487
|
+
reset: values.get("reset") === true
|
|
8488
|
+
});
|
|
8489
|
+
if (values.get("json") === true) {
|
|
8490
|
+
process.stdout.write(`${JSON.stringify({
|
|
8491
|
+
project_dir: project.root,
|
|
8492
|
+
dev_command: project.startCommand,
|
|
8493
|
+
preview_url: project.previewUrl,
|
|
8494
|
+
port: project.port,
|
|
8495
|
+
host: project.host
|
|
8496
|
+
})}
|
|
8497
|
+
`);
|
|
8498
|
+
return;
|
|
8499
|
+
}
|
|
8426
8500
|
process.stdout.write(`project_dir: ${project.root}
|
|
8427
8501
|
`);
|
|
8428
8502
|
process.stdout.write(`dev_command: ${project.startCommand}
|
|
8429
8503
|
`);
|
|
8430
8504
|
process.stdout.write(`preview_url: ${project.previewUrl}
|
|
8505
|
+
`);
|
|
8506
|
+
process.stdout.write(`bind_host: ${project.host}
|
|
8431
8507
|
`);
|
|
8432
8508
|
}
|
|
8433
8509
|
function runPathsCommand(args) {
|
|
@@ -8611,7 +8687,7 @@ async function parseAgentRunnerArgs(args, deps = {
|
|
|
8611
8687
|
}
|
|
8612
8688
|
rejectAgentRunnerTargetingFlags(values);
|
|
8613
8689
|
if (cwdArg !== undefined && values.has("cwd")) {
|
|
8614
|
-
throw new Error("linzumi
|
|
8690
|
+
throw new Error("linzumi commander accepts either <folder> or --cwd, not both");
|
|
8615
8691
|
}
|
|
8616
8692
|
const tokenFilePath = stringValue3(values, "agent-token-file") ?? defaultAgentTokenFilePath();
|
|
8617
8693
|
const tokenFile = readStoredAgentTokenFile(tokenFilePath, deps.readTextFile);
|
|
@@ -8677,14 +8753,14 @@ function readAgentTokenTextFile(path) {
|
|
|
8677
8753
|
function rejectAgentRunnerTargetingFlags(values) {
|
|
8678
8754
|
const unsupportedFlags = ["workspace", "channel", "token", "auth-file", "oauth-callback-host"].filter((flag) => values.has(flag));
|
|
8679
8755
|
if (unsupportedFlags.length > 0) {
|
|
8680
|
-
throw new Error(`linzumi
|
|
8756
|
+
throw new Error(`linzumi commander uses the claimed agent token scope; remove ${unsupportedFlags.map((flag) => `--${flag}`).join(", ")}.`);
|
|
8681
8757
|
}
|
|
8682
8758
|
}
|
|
8683
8759
|
function requiredStoredAgentChannel(channelId) {
|
|
8684
8760
|
if (channelId !== undefined) {
|
|
8685
8761
|
return channelId;
|
|
8686
8762
|
}
|
|
8687
|
-
throw new Error("agent token file is missing channelId; rerun linzumi claim before starting
|
|
8763
|
+
throw new Error("agent token file is missing channelId; rerun linzumi claim before starting a Commander");
|
|
8688
8764
|
}
|
|
8689
8765
|
function requiredStoredOwnerUsername(ownerUsername) {
|
|
8690
8766
|
if (ownerUsername !== undefined) {
|
|
@@ -8742,7 +8818,7 @@ async function parseRunnerArgs(args, deps = {
|
|
|
8742
8818
|
process.exit(0);
|
|
8743
8819
|
}
|
|
8744
8820
|
if (values.get("version") === true) {
|
|
8745
|
-
process.stdout.write(`linzumi 0.0.
|
|
8821
|
+
process.stdout.write(`linzumi 0.0.24-beta
|
|
8746
8822
|
`);
|
|
8747
8823
|
process.exit(0);
|
|
8748
8824
|
}
|
|
@@ -8941,6 +9017,17 @@ function positiveIntegerValue(values, key) {
|
|
|
8941
9017
|
}
|
|
8942
9018
|
throw new Error(`--${key} must be a positive integer`);
|
|
8943
9019
|
}
|
|
9020
|
+
function tcpPortValue(values, key) {
|
|
9021
|
+
const value = stringValue3(values, key);
|
|
9022
|
+
if (value === undefined) {
|
|
9023
|
+
return;
|
|
9024
|
+
}
|
|
9025
|
+
const parsed = Number(value);
|
|
9026
|
+
if (Number.isInteger(parsed) && parsed > 0 && parsed <= 65535) {
|
|
9027
|
+
return parsed;
|
|
9028
|
+
}
|
|
9029
|
+
throw new Error(`--${key} must be a TCP port from 1 to 65535`);
|
|
9030
|
+
}
|
|
8944
9031
|
function helpText() {
|
|
8945
9032
|
return `Linzumi local Codex runner
|
|
8946
9033
|
|
|
@@ -8952,8 +9039,8 @@ Usage:
|
|
|
8952
9039
|
linzumi post <thread_id> <message>
|
|
8953
9040
|
linzumi inbox <thread_id> --since-last
|
|
8954
9041
|
linzumi done <thread_id> --message <message>
|
|
8955
|
-
linzumi hello
|
|
8956
|
-
linzumi
|
|
9042
|
+
linzumi init-hello-linzumi-demo-app
|
|
9043
|
+
linzumi commander <folder> [options]
|
|
8957
9044
|
linzumi start <folder> [options]
|
|
8958
9045
|
linzumi paths list|add|remove [path]
|
|
8959
9046
|
linzumi connect --kandan-url <ws-url> --workspace <slug> --channel <slug> [options]
|
|
@@ -8994,8 +9081,8 @@ Examples:
|
|
|
8994
9081
|
linzumi thread new "Hello world" --message "Starting now. ETA 3m."
|
|
8995
9082
|
linzumi post thr_abc123 "PR is open"
|
|
8996
9083
|
linzumi done thr_abc123 --message "Done: https://github.com/example/repo/pull/1"
|
|
8997
|
-
linzumi hello
|
|
8998
|
-
linzumi
|
|
9084
|
+
linzumi init-hello-linzumi-demo-app
|
|
9085
|
+
linzumi commander ~/code/my-app --runner-id launch-commander
|
|
8999
9086
|
linzumi start ~/
|
|
9000
9087
|
linzumi start ~/code/my-app
|
|
9001
9088
|
linzumi connect --workspace <your-workspace> --channel <your-channel> --launch-tui
|
|
@@ -9019,19 +9106,27 @@ function helloHelpText() {
|
|
|
9019
9106
|
return `Linzumi Hello demo project
|
|
9020
9107
|
|
|
9021
9108
|
Usage:
|
|
9022
|
-
linzumi hello [--dir <path>]
|
|
9109
|
+
linzumi init-hello-linzumi-demo-app [--dir <path>]
|
|
9110
|
+
linzumi init-hello-linzumi-demo-app [--parent-dir <path> --name <dirname>]
|
|
9023
9111
|
|
|
9024
9112
|
Creates a tiny Node-only "Hello Linzumi" app with browser live reload.
|
|
9025
9113
|
|
|
9026
9114
|
Default:
|
|
9027
9115
|
${defaultHelloLinzumiProjectDir}
|
|
9116
|
+
host ${defaultHelloLinzumiHost}, port ${defaultHelloLinzumiPort}
|
|
9028
9117
|
|
|
9029
9118
|
After creation:
|
|
9030
9119
|
cd ${defaultHelloLinzumiProjectDir}
|
|
9031
9120
|
npm run dev
|
|
9032
9121
|
|
|
9033
9122
|
Options:
|
|
9034
|
-
--dir <path>
|
|
9123
|
+
--dir <path> Exact project directory.
|
|
9124
|
+
--parent-dir <path> Parent directory, default ${defaultHelloLinzumiParentDir}.
|
|
9125
|
+
--name <dirname> Project directory name with --parent-dir, default ${defaultHelloLinzumiProjectName}.
|
|
9126
|
+
--host <host> Bind host baked into the demo app, default ${defaultHelloLinzumiHost}.
|
|
9127
|
+
--port <port> Port baked into the demo app, default ${defaultHelloLinzumiPort}.
|
|
9128
|
+
--reset Recreate an existing marked Linzumi demo directory.
|
|
9129
|
+
--json Print machine-readable project details.
|
|
9035
9130
|
`;
|
|
9036
9131
|
}
|
|
9037
9132
|
function pathsHelpText() {
|
|
@@ -9079,13 +9174,14 @@ Examples:
|
|
|
9079
9174
|
`;
|
|
9080
9175
|
}
|
|
9081
9176
|
function agentRunnerHelpText() {
|
|
9082
|
-
return `Linzumi
|
|
9177
|
+
return `Linzumi Commander
|
|
9083
9178
|
|
|
9084
9179
|
Usage:
|
|
9180
|
+
linzumi commander <folder> [options]
|
|
9085
9181
|
linzumi agent runner <folder> [options]
|
|
9086
9182
|
|
|
9087
9183
|
What it does:
|
|
9088
|
-
Starts this computer as the claimed agent's scoped
|
|
9184
|
+
Starts this computer as the claimed agent's scoped Linzumi Commander. The command
|
|
9089
9185
|
reads ~/.linzumi/agent-token.json, uses its workspace/channel scope, trusts
|
|
9090
9186
|
only the selected folder by default, and listens only to the owning human
|
|
9091
9187
|
recorded during claim unless --listen-user is passed.
|
|
@@ -9093,7 +9189,7 @@ What it does:
|
|
|
9093
9189
|
Options:
|
|
9094
9190
|
--agent-token-file <path> Agent token cache, default ~/.linzumi/agent-token.json
|
|
9095
9191
|
--kandan-url <ws-url> Kandan websocket base URL. Defaults deterministically from the stored apiUrl.
|
|
9096
|
-
--runner-id <id> Stable
|
|
9192
|
+
--runner-id <id> Stable Commander id
|
|
9097
9193
|
--codex-bin <path> Codex executable, default codex
|
|
9098
9194
|
--code-server-bin <path> Custom development code-server executable. By default Kandan installs the approved editor runtime.
|
|
9099
9195
|
--listen-user <user> Human whose replies Codex may accept, default owner from claim
|
|
@@ -9103,11 +9199,11 @@ Options:
|
|
|
9103
9199
|
--approval-policy <value> Approval-policy metadata shown in Kandan
|
|
9104
9200
|
--forward-port <ports> Comma-separated local TCP ports Kandan may expose as previews
|
|
9105
9201
|
--allowed-cwd <paths> Override the selected folder with comma-separated trusted roots
|
|
9106
|
-
--fast Mark this
|
|
9202
|
+
--fast Mark this Commander as low-latency/fast in Linzumi
|
|
9107
9203
|
|
|
9108
9204
|
Examples:
|
|
9109
|
-
linzumi
|
|
9110
|
-
linzumi
|
|
9205
|
+
linzumi commander "$PWD" --runner-id hello-world-commander
|
|
9206
|
+
linzumi commander ~/code/my-app --kandan-url ws://127.0.0.1:4162 --runner-id local-qa-commander
|
|
9111
9207
|
`;
|
|
9112
9208
|
}
|
|
9113
9209
|
function connectGuideText() {
|
package/package.json
CHANGED