@linghun/cli 0.1.1 → 0.1.2

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.js CHANGED
@@ -5,6 +5,7 @@ import { randomUUID } from "crypto";
5
5
  import { readFile } from "fs/promises";
6
6
  import { createRequire } from "module";
7
7
  import { dirname, join } from "path";
8
+ import { Writable } from "stream";
8
9
  import { fileURLToPath } from "url";
9
10
  import { resolveProviderRuntimeContract } from "@linghun/providers";
10
11
  import { LINGHUN_CLI_NAME, LINGHUN_NAME, LINGHUN_VERSION } from "@linghun/shared";
@@ -14,6 +15,7 @@ var helpText = `${LINGHUN_NAME} ${LINGHUN_VERSION}
14
15
  ${LINGHUN_CLI_NAME} \u8FDB\u5165\u4EA4\u4E92\u5F0F\u7EC8\u7AEF
15
16
  ${LINGHUN_CLI_NAME} --version \u663E\u793A\u7248\u672C\u53F7
16
17
  ${LINGHUN_CLI_NAME} --help \u663E\u793A\u5E2E\u52A9\u4FE1\u606F
18
+ ${LINGHUN_CLI_NAME} run --prompt \u6587\u672C \u975E\u4EA4\u4E92\u6267\u884C\u4E00\u6B21\u4EFB\u52A1
17
19
  ${LINGHUN_CLI_NAME} sessions list [--json] \u5217\u51FA\u5F53\u524D\u9879\u76EE\u4F1A\u8BDD
18
20
  ${LINGHUN_CLI_NAME} sessions create [--message \u6587\u672C] \u65B0\u5EFA\u4F1A\u8BDD\uFF0C\u53EF\u5199\u5165\u4E00\u6761\u7528\u6237\u6D88\u606F
19
21
  ${LINGHUN_CLI_NAME} sessions append <id> --message \u6587\u672C \u8FFD\u52A0\u4E00\u6761\u7528\u6237\u6D88\u606F
@@ -71,6 +73,9 @@ async function runCli(argv) {
71
73
  `, stderr: "", exitCode: 0 };
72
74
  }
73
75
  const normalized = normalizeSlashCommand(argv);
76
+ if (normalized[0] === "run") {
77
+ return runHeadlessCommand(normalized.slice(1));
78
+ }
74
79
  if (normalized[0] === "sessions") {
75
80
  return runSessionsCommand(normalized.slice(1));
76
81
  }
@@ -104,7 +109,11 @@ function configurePlatformBundledRoot(kind, envName) {
104
109
  const packageName = `@linghun/${kind}-${process.platform}-${process.arch}`;
105
110
  try {
106
111
  const require2 = createRequire(import.meta.url);
107
- process.env[envName] = join(dirname(require2.resolve(`${packageName}/package.json`)), "bundled", kind);
112
+ process.env[envName] = join(
113
+ dirname(require2.resolve(`${packageName}/package.json`)),
114
+ "bundled",
115
+ kind
116
+ );
108
117
  } catch {
109
118
  }
110
119
  }
@@ -312,6 +321,57 @@ function maskSecret(secret) {
312
321
  if (secret.length <= 8) return "****";
313
322
  return `${secret.slice(0, 3)}\u2026${secret.slice(-4)}`;
314
323
  }
324
+ async function runHeadlessCommand(argv) {
325
+ if (argv.includes("--help") || argv.includes("-h")) {
326
+ return {
327
+ stdout: [
328
+ "\u7528\u6CD5\uFF1Alinghun run --prompt <\u6587\u672C> [--mode full-access] [--auto-approve]",
329
+ "",
330
+ "\u9009\u9879\uFF1A",
331
+ " --prompt, -p <\u6587\u672C> \u672C\u6B21\u4EFB\u52A1\u8BF4\u660E",
332
+ " --prompt-file <\u8DEF\u5F84> \u4ECE\u6587\u4EF6\u8BFB\u53D6\u4EFB\u52A1\u8BF4\u660E",
333
+ " --mode <\u6A21\u5F0F> default / auto-review / plan / full-access\uFF0C\u9ED8\u8BA4 full-access",
334
+ " --auto-approve \u81EA\u52A8\u6279\u51C6\u672C\u6B21 headless \u8FD0\u884C\u4E2D\u7684\u672C\u5730\u5DE5\u5177\u786E\u8BA4\uFF08\u9ED8\u8BA4\uFF09",
335
+ " --no-auto-approve \u9047\u5230\u672C\u5730\u5DE5\u5177\u786E\u8BA4\u65F6\u505C\u6B62",
336
+ " --max-approvals <\u6570\u91CF> \u81EA\u52A8\u6279\u51C6\u4E0A\u9650\uFF0C\u9ED8\u8BA4 32",
337
+ "",
338
+ "\u672A\u63D0\u4F9B --prompt \u6216 --prompt-file \u65F6\uFF0C\u4F1A\u4ECE stdin \u8BFB\u53D6\u4EFB\u52A1\u8BF4\u660E\u3002"
339
+ ].join("\n") + "\n",
340
+ stderr: "",
341
+ exitCode: 0
342
+ };
343
+ }
344
+ const mode = readOption(argv, "--mode") ?? "full-access";
345
+ if (!["default", "auto-review", "plan", "full-access"].includes(mode)) {
346
+ return usageError("\u7528\u6CD5\uFF1Alinghun run --mode default|auto-review|plan|full-access");
347
+ }
348
+ const prompt = readOption(argv, "--prompt") ?? readOption(argv, "-p") ?? await readPromptFile(argv) ?? readPositionalPrompt(argv) ?? await readStdinPrompt();
349
+ if (!prompt?.trim()) {
350
+ return usageError("\u7528\u6CD5\uFF1Alinghun run --prompt <\u6587\u672C>\uFF0C\u6216\u901A\u8FC7 stdin \u8F93\u5165\u4EFB\u52A1\u8BF4\u660E\u3002");
351
+ }
352
+ const maxApprovalsRaw = readOption(argv, "--max-approvals");
353
+ let maxApprovals;
354
+ if (maxApprovalsRaw !== void 0) {
355
+ const parsed = Number.parseInt(maxApprovalsRaw, 10);
356
+ if (!Number.isFinite(parsed) || parsed < 0) {
357
+ return usageError("\u7528\u6CD5\uFF1Alinghun run --max-approvals <\u975E\u8D1F\u6574\u6570>");
358
+ }
359
+ maxApprovals = parsed;
360
+ }
361
+ configureCliBundledRoot();
362
+ const stdout = new StringWritable();
363
+ const stderr = new StringWritable();
364
+ const { runHeadlessTask } = await import("@linghun/tui");
365
+ const exitCode = await runHeadlessTask({
366
+ prompt,
367
+ mode,
368
+ autoApprove: !argv.includes("--no-auto-approve"),
369
+ ...maxApprovals !== void 0 ? { maxApprovals } : {},
370
+ stdout,
371
+ stderr
372
+ });
373
+ return { stdout: stdout.toString(), stderr: stderr.toString(), exitCode };
374
+ }
315
375
  async function runSessionsCommand(argv) {
316
376
  const [subcommand = "list", ...rest] = argv;
317
377
  const [{ loadConfig, resolveStoragePaths }, { SessionStore }] = await Promise.all([
@@ -414,6 +474,35 @@ function normalizeSlashCommand(argv) {
414
474
  }
415
475
  return argv;
416
476
  }
477
+ async function readPromptFile(argv) {
478
+ const path = readOption(argv, "--prompt-file");
479
+ if (!path) return void 0;
480
+ return readFile(path, "utf8");
481
+ }
482
+ function readPositionalPrompt(argv) {
483
+ const values = [];
484
+ for (let i = 0; i < argv.length; i += 1) {
485
+ const value = argv[i];
486
+ if (!value) continue;
487
+ if (value.startsWith("-")) {
488
+ if (optionTakesValue(value)) i += 1;
489
+ continue;
490
+ }
491
+ values.push(value);
492
+ }
493
+ return values.length > 0 ? values.join(" ") : void 0;
494
+ }
495
+ async function readStdinPrompt() {
496
+ if (process.stdin.isTTY) return void 0;
497
+ let text = "";
498
+ for await (const chunk of process.stdin) {
499
+ text += typeof chunk === "string" ? chunk : chunk.toString("utf8");
500
+ }
501
+ return text;
502
+ }
503
+ function optionTakesValue(option) {
504
+ return ["--prompt", "-p", "--prompt-file", "--mode", "--max-approvals"].includes(option);
505
+ }
417
506
  function isSlashCommand(command, name) {
418
507
  if (!command) {
419
508
  return false;
@@ -451,6 +540,16 @@ function formatDiagnostics(diagnostics) {
451
540
  return `${diagnostics.map((diagnostic) => `JSONL \u7B2C ${diagnostic.line} \u884C\u5DF2\u8DF3\u8FC7\uFF1A${diagnostic.message}`).join("\n")}
452
541
  `;
453
542
  }
543
+ var StringWritable = class extends Writable {
544
+ chunks = [];
545
+ _write(chunk, _encoding, callback) {
546
+ this.chunks.push(typeof chunk === "string" ? chunk : chunk.toString("utf8"));
547
+ callback();
548
+ }
549
+ toString() {
550
+ return this.chunks.join("");
551
+ }
552
+ };
454
553
 
455
554
  // src/main.ts
456
555
  var result = await runCli(process.argv.slice(2));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linghun/cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "bin": {
@@ -23,10 +23,10 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "@linghun/config": "0.1.0",
26
+ "@linghun/shared": "0.1.2",
27
+ "@linghun/providers": "0.1.1",
26
28
  "@linghun/core": "0.1.0",
27
- "@linghun/providers": "0.1.0",
28
- "@linghun/shared": "0.1.0",
29
- "@linghun/tui": "0.1.0"
29
+ "@linghun/tui": "0.1.1"
30
30
  },
31
31
  "scripts": {
32
32
  "build": "tsup src/main.ts --format esm --clean",
@@ -32,8 +32,20 @@ for (const packageName of [
32
32
  const packageRoot = join(requireFromCli.resolve(`${packageName}/package.json`), "..");
33
33
  const executable =
34
34
  packageName.includes("codebase-memory")
35
- ? join(packageRoot, "bundled", "codebase-memory", packageName.replace("@linghun/codebase-memory-", ""), "codebase-memory-mcp")
36
- : join(packageRoot, "bundled", "native-runner", packageName.replace("@linghun/native-runner-", ""), "linghun-native-runner");
35
+ ? join(
36
+ packageRoot,
37
+ "bundled",
38
+ "codebase-memory",
39
+ packageName.replace("@linghun/codebase-memory-", ""),
40
+ "codebase-memory-mcp",
41
+ )
42
+ : join(
43
+ packageRoot,
44
+ "bundled",
45
+ "native-runner",
46
+ packageName.replace("@linghun/native-runner-", ""),
47
+ "linghun-native-runner",
48
+ );
37
49
  if (existsSync(executable)) {
38
50
  chmodSync(executable, 0o755);
39
51
  }