@stalfh233/omc-cli 0.4.37 → 0.4.38

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.
@@ -1,11 +1,6 @@
1
1
  import { z } from "zod";
2
- export class ToolRefusalError extends Error {
3
- payload;
4
- constructor(payload) {
5
- super(String(payload["blocker"] ?? "tool refused"));
6
- this.payload = payload;
7
- }
8
- }
2
+ export { ToolRefusalError } from "omc-core/refusal";
3
+ import { ToolRefusalError } from "omc-core/refusal";
9
4
  /**
10
5
  * The most informative message an error carries. `ToolRefusalError.message` is
11
6
  * the BLOCKER code (its constructor sets it so), while the actionable human
package/dist/zip.js CHANGED
@@ -1,156 +1,3 @@
1
- import { inflateRawSync } from "node:zlib";
2
- /**
3
- * Ticket 106 — a minimal, dependency-free ZIP reader/writer for the bizservice
4
- * IE package face.
5
- *
6
- * The platform export answers a ZIP with manifest.json + version.md
7
- * (BizServiceIEController.java:124-138). Java's ZipOutputStream typically
8
- * writes local headers with zeroed sizes plus a trailing data descriptor
9
- * (general-purpose bit 3), so the READER resolves entries through the central
10
- * directory (whose sizes/CRCs are authoritative) and only uses each local
11
- * header to locate the data offset. The WRITER emits stored (method 0)
12
- * entries — real zips for fake routes and tests; the platform reader accepts
13
- * both stored and deflated entries.
14
- */
15
- const EOCD_SIGNATURE = 0x06054b50;
16
- const CENTRAL_SIGNATURE = 0x02014b50;
17
- const LOCAL_SIGNATURE = 0x04034b50;
18
- const EOCD_SCAN_LIMIT = 65_557; // fixed EOCD (22) + max comment (65_535)
19
- export class ZipFormatError extends Error {
20
- constructor(message) {
21
- super(message);
22
- this.name = "ZipFormatError";
23
- }
24
- }
25
- /** CRC-32 (IEEE 802.3), table-driven. */
26
- const CRC_TABLE = (() => {
27
- const table = new Array(256);
28
- for (let n = 0; n < 256; n += 1) {
29
- let c = n;
30
- for (let k = 0; k < 8; k += 1)
31
- c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
32
- table[n] = c >>> 0;
33
- }
34
- return table;
35
- })();
36
- function crc32(buffer) {
37
- let crc = 0xffffffff;
38
- for (const byte of buffer)
39
- crc = CRC_TABLE[(crc ^ byte) & 0xff] ^ (crc >>> 8);
40
- return (crc ^ 0xffffffff) >>> 0;
41
- }
42
- /** Locate the End Of Central Directory record; returns its byte offset. */
43
- function locateEocd(buffer) {
44
- const start = Math.max(0, buffer.length - EOCD_SCAN_LIMIT);
45
- for (let offset = buffer.length - 22; offset >= start; offset -= 1) {
46
- if (buffer.readUInt32LE(offset) === EOCD_SIGNATURE) {
47
- const commentLength = buffer.readUInt16LE(offset + 20);
48
- if (offset + 22 + commentLength === buffer.length)
49
- return offset;
50
- }
51
- }
52
- throw new ZipFormatError("no end-of-central-directory record found");
53
- }
54
- /** Read every central-directory entry as name → decompressed Buffer. */
55
- export function readZipEntries(buffer) {
56
- const eocd = locateEocd(buffer);
57
- const entryCount = buffer.readUInt16LE(eocd + 10);
58
- let cursor = buffer.readUInt32LE(eocd + 16);
59
- const entries = new Map();
60
- for (let index = 0; index < entryCount; index += 1) {
61
- if (cursor + 46 > buffer.length || buffer.readUInt32LE(cursor) !== CENTRAL_SIGNATURE)
62
- throw new ZipFormatError(`central directory entry ${index} is malformed`);
63
- const method = buffer.readUInt16LE(cursor + 10);
64
- const compressedSize = buffer.readUInt32LE(cursor + 20);
65
- const nameLength = buffer.readUInt16LE(cursor + 28);
66
- const extraLength = buffer.readUInt16LE(cursor + 30);
67
- const commentLength = buffer.readUInt16LE(cursor + 32);
68
- const localOffset = buffer.readUInt32LE(cursor + 42);
69
- const name = buffer.subarray(cursor + 46, cursor + 46 + nameLength).toString("utf8");
70
- // The local header carries its OWN name/extra lengths (they may differ
71
- // from the central copies); the data starts right after them.
72
- if (localOffset + 30 > buffer.length || buffer.readUInt32LE(localOffset) !== LOCAL_SIGNATURE)
73
- throw new ZipFormatError(`local header for "${name}" is malformed`);
74
- const localNameLength = buffer.readUInt16LE(localOffset + 26);
75
- const localExtraLength = buffer.readUInt16LE(localOffset + 28);
76
- const dataStart = localOffset + 30 + localNameLength + localExtraLength;
77
- const data = buffer.subarray(dataStart, dataStart + compressedSize);
78
- if (method === 0)
79
- entries.set(name, Buffer.from(data));
80
- else if (method === 8)
81
- entries.set(name, inflateRawSync(data));
82
- else
83
- throw new ZipFormatError(`entry "${name}" uses unsupported compression method ${method}`);
84
- cursor += 46 + nameLength + extraLength + commentLength;
85
- }
86
- return entries;
87
- }
88
- /** Build a stored-entry ZIP (method 0, UTF-8 names flagged via bit 11). */
89
- export function buildZip(files) {
90
- const chunks = [];
91
- const central = [];
92
- let offset = 0;
93
- for (const file of files) {
94
- const nameBytes = Buffer.from(file.name, "utf8");
95
- const crc = crc32(file.data);
96
- const local = Buffer.alloc(30);
97
- local.writeUInt32LE(LOCAL_SIGNATURE, 0);
98
- local.writeUInt16LE(0x0800, 6); // UTF-8 name flag
99
- local.writeUInt16LE(0, 8); // stored
100
- local.writeUInt16LE(0, 10); // time
101
- local.writeUInt16LE(0x2100, 12); // date (1996-01-01, deterministic)
102
- local.writeUInt32LE(crc, 14);
103
- local.writeUInt32LE(file.data.length, 18);
104
- local.writeUInt32LE(file.data.length, 22);
105
- local.writeUInt16LE(nameBytes.length, 26);
106
- local.writeUInt16LE(0, 28);
107
- chunks.push(local, nameBytes, file.data);
108
- const entry = Buffer.alloc(46);
109
- entry.writeUInt32LE(CENTRAL_SIGNATURE, 0);
110
- entry.writeUInt16LE(0x031e, 4); // made by UNIX/ZIP 3.0
111
- entry.writeUInt16LE(0x0014, 6); // extract by DOS/ZIP 2.0
112
- entry.writeUInt16LE(0x0800, 8);
113
- entry.writeUInt16LE(0, 10);
114
- entry.writeUInt16LE(0, 12);
115
- entry.writeUInt16LE(0x2100, 14);
116
- entry.writeUInt32LE(crc, 16);
117
- entry.writeUInt32LE(file.data.length, 20);
118
- entry.writeUInt32LE(file.data.length, 24);
119
- entry.writeUInt16LE(nameBytes.length, 28);
120
- entry.writeUInt16LE(0, 30);
121
- entry.writeUInt16LE(0, 32);
122
- entry.writeUInt16LE(0, 34);
123
- entry.writeUInt16LE(0, 36);
124
- entry.writeUInt32LE(0, 38);
125
- entry.writeUInt32LE(offset, 42);
126
- central.push(entry, nameBytes);
127
- offset += 30 + nameBytes.length + file.data.length;
128
- }
129
- const centralBuffer = Buffer.concat(central);
130
- const eocd = Buffer.alloc(22);
131
- eocd.writeUInt32LE(EOCD_SIGNATURE, 0);
132
- eocd.writeUInt16LE(0, 4);
133
- eocd.writeUInt16LE(0, 6);
134
- eocd.writeUInt16LE(files.length, 8);
135
- eocd.writeUInt16LE(files.length, 10);
136
- eocd.writeUInt32LE(centralBuffer.length, 12);
137
- eocd.writeUInt32LE(offset, 16);
138
- eocd.writeUInt16LE(0, 20);
139
- return Buffer.concat([...chunks, centralBuffer, eocd]);
140
- }
141
- /**
142
- * Resolve an entry by BASENAME: the platform export compresses the staging
143
- * DIRECTORY, so entries carry a `bizService-<uuid>/` prefix
144
- * (live 2026-09-15: bizService-59d72d4a…/manifest.json).
145
- */
146
- export function zipEntryByBasename(entries, basename) {
147
- const direct = entries.get(basename);
148
- if (direct !== undefined)
149
- return direct;
150
- const suffix = `/${basename}`;
151
- for (const [name, data] of entries)
152
- if (name.endsWith(suffix))
153
- return data;
154
- return undefined;
155
- }
1
+ // C1 拆分:zip 已下沉 omc-core(真 lane 与 @stalfh233/omc-fake-platform 共用唯一事实源);此处 re-export 保持既有 import 路径不变。
2
+ export * from "omc-core/zip";
156
3
  //# sourceMappingURL=zip.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stalfh233/omc-cli",
3
- "version": "0.4.37",
3
+ "version": "0.4.38",
4
4
  "description": "CloudPivot 8.6 configuration capability CLI — governed, fail-closed, coverage-manifest bounded.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -50,8 +50,9 @@
50
50
  "access": "public"
51
51
  },
52
52
  "dependencies": {
53
+ "@stalfh233/omc-fake-platform": "0.4.38",
53
54
  "commander": "14.0.3",
54
- "omc-core": "0.4.37",
55
+ "omc-core": "0.4.38",
55
56
  "proper-lockfile": "4.1.2",
56
57
  "write-file-atomic": "6.0.0",
57
58
  "zod": "^3.23.8",
@@ -1,65 +0,0 @@
1
- import { createServer } from "node:http";
2
- import { FakeCloudPivot } from "../fake/index.js";
3
- export async function startFakeHttpServer() {
4
- const server = createServer();
5
- await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
6
- const address = server.address();
7
- if (address === null || typeof address === "string") {
8
- server.closeAllConnections?.();
9
- await new Promise((resolve) => server.close(() => resolve()));
10
- throw new Error("fake http server has no listen address");
11
- }
12
- const url = `http://127.0.0.1:${address.port}`;
13
- const fake = new FakeCloudPivot({ version: "8.6.26", baseUrl: url });
14
- server.on("request", (request, response) => {
15
- const chunks = [];
16
- request.on("data", (chunk) => chunks.push(chunk));
17
- request.on("end", () => {
18
- const target = new URL(request.url ?? "/", url);
19
- const query = {};
20
- for (const [key, value] of target.searchParams)
21
- query[key] = value;
22
- const raw = Buffer.concat(chunks);
23
- const contentType = request.headers["content-type"] ?? "";
24
- const body = raw.length === 0 ? undefined : contentType.includes("json") ? JSON.parse(raw.toString("utf8")) : raw.toString("utf8");
25
- const headers = {};
26
- for (const [key, value] of Object.entries(request.headers)) {
27
- if (typeof value === "string") {
28
- const capitalized = key.replace(/\b\w/g, (c) => c.toUpperCase()).replace(/-(\w)/g, (_m, c) => `-${c.toUpperCase()}`);
29
- headers[capitalized] = value;
30
- }
31
- }
32
- fake
33
- .request({
34
- path: target.pathname,
35
- method: request.method === "POST" ? "POST" : "GET",
36
- ...(Object.keys(query).length > 0 ? { query } : {}),
37
- ...(body === undefined ? {} : { body }),
38
- headers,
39
- })
40
- .then((result) => {
41
- const payload = Buffer.isBuffer(result.body) ? result.body : JSON.stringify(result.body);
42
- response.writeHead(result.status, Buffer.isBuffer(result.body) ? undefined : { "Content-Type": "application/json" });
43
- response.end(payload);
44
- })
45
- .catch(() => {
46
- response.writeHead(500, { "Content-Type": "application/json" });
47
- response.end(JSON.stringify({ errcode: 500, errmsg: "fake transport failure", data: null }));
48
- });
49
- });
50
- });
51
- return {
52
- fake,
53
- url,
54
- close: () => new Promise((resolve, reject) => {
55
- server.closeAllConnections?.();
56
- server.close((error) => (error ? reject(error) : resolve()));
57
- }),
58
- };
59
- }
60
- export function canonicalBusinessCalls(fake) {
61
- return JSON.stringify(fake.state.callLog
62
- .filter((entry) => !entry.path.startsWith("/user/") && !entry.path.startsWith("/api/public/") && !entry.path.startsWith("/api/api/organization/"))
63
- .map((entry) => ({ path: entry.path, method: entry.method, body: entry.body ?? null, query: entry.query && Object.keys(entry.query).length > 0 ? entry.query : null })));
64
- }
65
- //# sourceMappingURL=fake-http-server.js.map
package/dist/fake/app.js DELETED
@@ -1,45 +0,0 @@
1
- import { NOT_HANDLED } from "./state.js";
2
- /** app-management lane: application package CRUD. Twin of src/lanes/app.ts. */
3
- export const appRoute = (ctx, input) => {
4
- const q = input.query ?? {};
5
- const body = (input.body ?? {});
6
- switch (input.path) {
7
- case "/api/api/app/apppackage/list":
8
- return ctx.options.applicationList ?? [...ctx.state.apps.values()].map((app) => ({ appCode: app.code, appName: app.name, id: app.id, groupId: app.groupId, published: app.published !== false }));
9
- case "/api/api/app/apppackage/list_all_group":
10
- return [...ctx.state.appGroups.values()].map((group) => ({
11
- id: group.id,
12
- code: group.code,
13
- name: group.name,
14
- children: [...ctx.state.apps.values()].filter((app) => app.groupId === group.id).map((app) => ({ id: app.id, code: app.code, name: app.name, groupId: app.groupId })),
15
- }));
16
- case "/api/api/app/apppackage/create": {
17
- const code = String(body.code);
18
- ctx.state.apps.set(code, { id: `app-${ctx.state.apps.size + 1}`, code, name: String(body.name ?? code), groupId: String(body.groupId ?? [...ctx.state.appGroups.keys()][0] ?? "group-1") });
19
- return null;
20
- }
21
- case "/api/api/app/apppackage/get": {
22
- const app = [...ctx.state.apps.values()].find((row) => row.code === q.appCode);
23
- return app ? { id: app.id, code: app.code, name: app.name, name_i18n: JSON.stringify({ "zh-CN": app.name }), groupId: app.groupId, enabled: true } : null;
24
- }
25
- case "/api/api/app/apppackage/update": {
26
- // AppIntegrationFacadeImpl.updateAppPackage: id-required whole-record
27
- // update; explicit groupId honored; blank groupId would be forced to
28
- // the "default" group; enabled !== true wipes workflow favorites.
29
- const target = [...ctx.state.apps.values()].find((row) => row.id === body.id);
30
- if (target) {
31
- if (typeof body.groupId === "string" && body.groupId)
32
- target.groupId = body.groupId;
33
- if (typeof body.name === "string" && body.name)
34
- target.name = body.name;
35
- }
36
- return null;
37
- }
38
- case "/api/api/app/apppackage/delete":
39
- ctx.state.apps.delete(String(q.appCode));
40
- return null;
41
- default:
42
- return NOT_HANDLED;
43
- }
44
- };
45
- //# sourceMappingURL=app.js.map