@stalfh233/omc-cli 0.4.10 → 0.4.12

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 CHANGED
@@ -246,12 +246,12 @@ src/ args/support/plan/read/write/package/context(治理管道)
246
246
 
247
247
  ## npm 分发
248
248
 
249
- 本包(`@stalfh233/omc-cli`,可执行命令仍是 `omc`)通过公共 npm registry 分发。`omc-core` 是 `omc-cli` 的内部依赖,发布时先发 `omc-core`,再发 `omc-cli`;两者版本保持一致。当前版本为 `0.4.10`,尚未宣称 `1.0.0` 稳定契约。
249
+ 本包(`@stalfh233/omc-cli`,可执行命令仍是 `omc`)通过公共 npm registry 分发。`omc-core` 是 `omc-cli` 的内部依赖,发布时先发 `omc-core`,再发 `omc-cli`;两者版本保持一致。当前版本为 `0.4.12`,尚未宣称 `1.0.0` 稳定契约。
250
250
 
251
251
  ### 使用已发布包
252
252
 
253
253
  ```bash
254
- npm install -g @stalfh233/omc-cli@0.4.10
254
+ npm install -g @stalfh233/omc-cli@0.4.12
255
255
  omc setup
256
256
  omc doctor
257
257
  omc help omc-write-hazards
package/dist/call.js CHANGED
@@ -106,10 +106,21 @@ export async function runToolCall(toolName, options = {}) {
106
106
  };
107
107
  const result = options.timeoutMs === undefined
108
108
  ? await invoke()
109
- : await Promise.race([
110
- invoke(),
111
- new Promise((resolve) => setTimeout(() => resolve({ status: "uncertain", blocker: "cli-timeout", nextAction: "read back the requestId before retrying; retry only after the outcome is established", retryable: true }), options.timeoutMs)),
112
- ]);
109
+ : await (async () => {
110
+ let timer;
111
+ try {
112
+ return await Promise.race([
113
+ invoke(),
114
+ new Promise((resolve) => { timer = setTimeout(() => resolve({ status: "uncertain", blocker: "cli-timeout", nextAction: "read back the requestId before retrying; retry only after the outcome is established", retryable: true }), options.timeoutMs); }),
115
+ ]);
116
+ }
117
+ finally {
118
+ // Clear the losing timeout so a completed call does not leave a
119
+ // pending timer that would otherwise keep the event loop alive.
120
+ if (timer)
121
+ clearTimeout(timer);
122
+ }
123
+ })();
113
124
  // The stderr line is a human diagnostic, NOT a second copy of the result: the
114
125
  // stdout envelope is the single machine truth. Dumping the whole result here
115
126
  // doubled every call's payload on stderr (unbounded and un-sanitized — it also
@@ -13,27 +13,16 @@ export function envelope(status, result, requestId, error = null) {
13
13
  /**
14
14
  * The single stdout serialization for every envelope.
15
15
  *
16
- * On zh-CN Windows, PowerShell decodes a native process's bytes with the legacy
17
- * console code page and mangles UTF-8 Chinese ("付文�?"), which forces callers
18
- * into a "write to file, then re-read" workaround. When `OMC_ASCII_STDOUT`
19
- * resolves on, non-ASCII is escaped to `\uXXXX`: stdout stays pure ASCII and
20
- * decodes identically under any code page while still parsing to the original
21
- * string. It is on by default only on win32, so Linux output keeps its smaller
22
- * UTF-8 bytes. Override with `OMC_ASCII_STDOUT=1|0`. Artifacts keep raw UTF-8 —
23
- * they are files, not a console stream. See `CONTEXT.md` → Agent-facing CLI.
16
+ * stdout is always UTF-8, on every platform. Escaping non-ASCII to `\uXXXX`
17
+ * (an earlier win32 "ASCII-safe" mode) is deliberately gone: it made Windows
18
+ * output diverge from POSIX byte-for-byte, broke plain string matching
19
+ * (`findstr 采购`), and only worked around a legacy console code page that a
20
+ * modern terminal (Windows Terminal, PowerShell 7, `chcp 65001`) fixes by
21
+ * itself. JSON is UTF-8 by spec; downstream tools parse it losslessly. Callers
22
+ * that truly need a file use `--out`, which was always raw UTF-8.
24
23
  */
25
- export function asciiStdout() {
26
- const override = process.env.OMC_ASCII_STDOUT;
27
- if (override === "1")
28
- return true;
29
- if (override === "0")
30
- return false;
31
- return process.platform === "win32";
32
- }
33
24
  export function serializeEnvelope(value) {
34
- const json = JSON.stringify(value);
35
- const escaped = asciiStdout() ? json.replace(/[\u007f-\uffff]/g, (character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`) : json;
36
- return escaped + "\n";
25
+ return JSON.stringify(value) + "\n";
37
26
  }
38
27
  export function requestId() {
39
28
  return randomUUID();
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createInterface } from "node:readline/promises";
3
- import { stdin, argv, exit } from "node:process";
3
+ import { stdin, argv } from "node:process";
4
4
  import { Command, CommanderError } from "commander";
5
5
  import { ConfigStore, defaultPaths, removedProfileKeys } from "./config-store.js";
6
6
  import { loadCoverageManifest, versionFamilyNotice } from "./coverage.js";
@@ -1373,22 +1373,35 @@ async function main() {
1373
1373
  await command.parseAsync(stripOutputFlags(argv));
1374
1374
  return commandExitCode;
1375
1375
  }
1376
+ /**
1377
+ * End the process with `code` without the Windows-only libuv abort a bare
1378
+ * `process.exit()` triggers while undici is still closing its sockets:
1379
+ * Assertion failed: !(handle->flags & UV_HANDLE_CLOSING), src\win\async.c
1380
+ * We set `exitCode` so the loop drains and the process exits with the right
1381
+ * status; an unref'd guard force-exits only if some ref'd handle (e.g. an
1382
+ * optional `--timeout-ms` race timer) would otherwise keep the loop alive — by
1383
+ * which point the HTTP sockets are closed, so the forced exit is safe.
1384
+ */
1385
+ function finish(code) {
1386
+ process.exitCode = code;
1387
+ setTimeout(() => process.exit(code), 1000).unref();
1388
+ }
1376
1389
  const request = requestId();
1377
1390
  main().then((code) => {
1378
1391
  if (argv[2] === "call" || argv[2] === "artifact" || argv[2] === "commands" || argv[2] === "describe" || argv[2] === "contract" || argv[2] === "capabilities" || argv[2] === "capability" || argv[2] === "next" || argv[2] === "usage" || argv[2] === "intent" || argv[2] === "help") {
1379
1392
  completeUsage(code);
1380
- exit(code);
1393
+ finish(code);
1381
1394
  return;
1382
1395
  }
1383
1396
  writeEnvelope(envelope(code === 0 ? "ok" : "error", {}, request, code === 0 ? null : { code: "internal", message: "command failed", retryable: false }));
1384
1397
  completeUsage(code);
1385
- exit(code);
1398
+ finish(code);
1386
1399
  }, (error) => {
1387
1400
  // commander prints `--help` / `-h` usage to stderr and signals success with
1388
1401
  // this code; it is not an error and must not grow a spurious error envelope.
1389
1402
  if (error instanceof CommanderError && error.code === "commander.helpDisplayed") {
1390
1403
  completeUsage(0);
1391
- exit(0);
1404
+ finish(0);
1392
1405
  return;
1393
1406
  }
1394
1407
  const commander = error instanceof CommanderError;
@@ -1413,6 +1426,6 @@ main().then((code) => {
1413
1426
  const parsed = errorEnvelope(new Error(message), commander ? "invalid-input" : "internal", commander ? CLI_EXIT_CODES.invalidInput : CLI_EXIT_CODES.internal, request);
1414
1427
  writeEnvelope(parsed.envelope);
1415
1428
  completeUsage(parsed.exitCode);
1416
- exit(parsed.exitCode);
1429
+ finish(parsed.exitCode);
1417
1430
  });
1418
1431
  //# sourceMappingURL=cli.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stalfh233/omc-cli",
3
- "version": "0.4.10",
3
+ "version": "0.4.12",
4
4
  "description": "CloudPivot 8.6 configuration capability CLI — governed, fail-closed, coverage-manifest bounded.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -51,7 +51,7 @@
51
51
  },
52
52
  "dependencies": {
53
53
  "commander": "14.0.3",
54
- "omc-core": "0.4.10",
54
+ "omc-core": "0.4.12",
55
55
  "proper-lockfile": "4.1.2",
56
56
  "write-file-atomic": "6.0.0",
57
57
  "zod": "^3.23.8",