@hcmai/sdk 0.3.7 → 0.3.9

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/index.js CHANGED
@@ -177,25 +177,25 @@ var TokenStore = class _TokenStore {
177
177
  throw e;
178
178
  }
179
179
  }
180
- async setAccessToken(token) {
180
+ async setAccessToken(token2) {
181
181
  if (await this.canUseKeychain()) {
182
182
  const keytar = await loadKeytar();
183
- if (!keytar) return this.writeTokenFile("access", token);
183
+ if (!keytar) return this.writeTokenFile("access", token2);
184
184
  const account = `${this.keychainAccountPrefix()}/access`;
185
- await keytar.setPassword(SERVICE_PREFIX, account, token);
185
+ await keytar.setPassword(SERVICE_PREFIX, account, token2);
186
186
  return `keychain:${SERVICE_PREFIX}/${account}`;
187
187
  }
188
- return this.writeTokenFile("access", token);
188
+ return this.writeTokenFile("access", token2);
189
189
  }
190
- async setRefreshToken(token) {
190
+ async setRefreshToken(token2) {
191
191
  if (await this.canUseKeychain()) {
192
192
  const keytar = await loadKeytar();
193
- if (!keytar) return this.writeTokenFile("refresh", token);
193
+ if (!keytar) return this.writeTokenFile("refresh", token2);
194
194
  const account = `${this.keychainAccountPrefix()}/refresh`;
195
- await keytar.setPassword(SERVICE_PREFIX, account, token);
195
+ await keytar.setPassword(SERVICE_PREFIX, account, token2);
196
196
  return `keychain:${SERVICE_PREFIX}/${account}`;
197
197
  }
198
- return this.writeTokenFile("refresh", token);
198
+ return this.writeTokenFile("refresh", token2);
199
199
  }
200
200
  async getAccessToken() {
201
201
  if (process.env.HCM_PAT) return process.env.HCM_PAT;
@@ -258,10 +258,10 @@ var TokenStore = class _TokenStore {
258
258
  return false;
259
259
  }
260
260
  }
261
- async writeTokenFile(kind, token) {
261
+ async writeTokenFile(kind, token2) {
262
262
  const file = `${this.metaFile()}.${kind}`;
263
263
  await fs.mkdir(this.dataDir(), { recursive: true });
264
- await fs.writeFile(file, token, { mode: 384 });
264
+ await fs.writeFile(file, token2, { mode: 384 });
265
265
  if (kind === "access") {
266
266
  console.warn(`[hcm] WARNING: OS keychain unavailable. Token saved to ${file} (0600).`);
267
267
  }
@@ -308,14 +308,14 @@ async function loginPassword(input) {
308
308
  },
309
309
  { headers: { "Content-Type": "application/json" } }
310
310
  );
311
- const { token, expiresIn, user } = resp.data;
312
- if (!token) {
311
+ const { token: token2, expiresIn, user } = resp.data;
312
+ if (!token2) {
313
313
  throw new Error("Login response missing token");
314
314
  }
315
315
  const ttlSeconds = expiresIn ?? DEFAULT_SESSION_TTL_SECONDS;
316
316
  const expiresAt = new Date(Date.now() + ttlSeconds * 1e3).toISOString();
317
317
  const store = new TokenStore(input.profile);
318
- const accessTokenRef = await store.setAccessToken(token);
318
+ const accessTokenRef = await store.setAccessToken(token2);
319
319
  const record = {
320
320
  scheme: "password",
321
321
  accessTokenRef,
@@ -1068,18 +1068,18 @@ async function action(http, model, actionName, input) {
1068
1068
  if (scope === "object" && !input.id) {
1069
1069
  throw new Error(`object action ${model}.${actionName} requires id`);
1070
1070
  }
1071
- const path9 = scope === "object" ? `/api/models/${model}/${input.id}/action/${actionName}` : `/api/models/${model}/action/${actionName}`;
1071
+ const path12 = scope === "object" ? `/api/models/${model}/${input.id}/action/${actionName}` : `/api/models/${model}/action/${actionName}`;
1072
1072
  const resp = await (async () => {
1073
1073
  if (method === "GET") {
1074
- return http.get(path9, { params: queryParams(input) });
1074
+ return http.get(path12, { params: queryParams(input) });
1075
1075
  }
1076
1076
  if (method === "DELETE") {
1077
- return http.delete(path9, { params: queryParams(input) });
1077
+ return http.delete(path12, { params: queryParams(input) });
1078
1078
  }
1079
1079
  if (method === "PUT") {
1080
- return http.put(path9, scope === "object" ? objectBody(input) : classBody(input));
1080
+ return http.put(path12, scope === "object" ? objectBody(input) : classBody(input));
1081
1081
  }
1082
- return http.post(path9, scope === "object" ? objectBody(input) : classBody(input));
1082
+ return http.post(path12, scope === "object" ? objectBody(input) : classBody(input));
1083
1083
  })();
1084
1084
  return resp.data;
1085
1085
  }
@@ -1690,14 +1690,14 @@ async function loginPairing(input) {
1690
1690
  { code: input.code },
1691
1691
  { headers: { "Content-Type": "application/json" } }
1692
1692
  );
1693
- const { token, expiresIn, user } = resp.data;
1694
- if (!token) {
1693
+ const { token: token2, expiresIn, user } = resp.data;
1694
+ if (!token2) {
1695
1695
  throw new Error("Pairing exchange response missing token");
1696
1696
  }
1697
1697
  const ttlSeconds = expiresIn ?? DEFAULT_SESSION_TTL_SECONDS;
1698
1698
  const expiresAt = new Date(Date.now() + ttlSeconds * 1e3).toISOString();
1699
1699
  const store = new TokenStore(input.profile);
1700
- const accessTokenRef = await store.setAccessToken(token);
1700
+ const accessTokenRef = await store.setAccessToken(token2);
1701
1701
  const record = {
1702
1702
  scheme: "pairing",
1703
1703
  accessTokenRef,
@@ -1730,10 +1730,10 @@ function detectPasswordChangeChallenge(err) {
1730
1730
  const body = err?.response?.data;
1731
1731
  const error = body?.error ?? body;
1732
1732
  if (error?.code !== PASSWORD_CHANGE_REQUIRED) return null;
1733
- const token = error?.details?.changePasswordToken;
1734
- if (!token) return null;
1733
+ const token2 = error?.details?.changePasswordToken;
1734
+ if (!token2) return null;
1735
1735
  return {
1736
- changePasswordToken: String(token),
1736
+ changePasswordToken: String(token2),
1737
1737
  expiresInSeconds: Number(error?.details?.expiresInSeconds) || void 0
1738
1738
  };
1739
1739
  }
@@ -5035,18 +5035,18 @@ async function listTenantMeta(http, opts = {}) {
5035
5035
  const items = payload?.items ?? payload?.list ?? payload?.records ?? [];
5036
5036
  return { items, total: payload?.total, raw: payload };
5037
5037
  }
5038
- async function getTenantMeta(http, path9) {
5039
- const resp = await http.get("/api/tenant-meta/meta", { params: { path: path9 } });
5038
+ async function getTenantMeta(http, path12) {
5039
+ const resp = await http.get("/api/tenant-meta/meta", { params: { path: path12 } });
5040
5040
  const payload = resp.data?.data ?? resp.data;
5041
5041
  if (typeof payload === "string") return payload;
5042
5042
  return String(payload?.content ?? "");
5043
5043
  }
5044
- async function saveTenantMeta(http, path9, content) {
5045
- const resp = await http.put("/api/tenant-meta/meta", { content }, { params: { path: path9 } });
5044
+ async function saveTenantMeta(http, path12, content) {
5045
+ const resp = await http.put("/api/tenant-meta/meta", { content }, { params: { path: path12 } });
5046
5046
  return resp.data?.data ?? resp.data;
5047
5047
  }
5048
- async function deleteTenantMeta(http, path9) {
5049
- const resp = await http.delete("/api/tenant-meta/meta", { params: { path: path9 } });
5048
+ async function deleteTenantMeta(http, path12) {
5049
+ const resp = await http.delete("/api/tenant-meta/meta", { params: { path: path12 } });
5050
5050
  return resp.data?.data ?? resp.data;
5051
5051
  }
5052
5052
 
@@ -5148,14 +5148,14 @@ function resolveSkillInstallOrder(manifest2, targetId) {
5148
5148
  throw invalid(`\u6280\u80FD\u76EE\u5F55\u4E2D\u4E0D\u5B58\u5728 ${targetId}`);
5149
5149
  }
5150
5150
  const state = /* @__PURE__ */ new Map();
5151
- const path9 = [];
5151
+ const path12 = [];
5152
5152
  const order = [];
5153
5153
  const visit = (id, requiredBy) => {
5154
5154
  const current = state.get(id);
5155
5155
  if (current === "done") return;
5156
5156
  if (current === "visiting") {
5157
- const cycleStart = path9.indexOf(id);
5158
- const cycle = [...path9.slice(Math.max(0, cycleStart)), id];
5157
+ const cycleStart = path12.indexOf(id);
5158
+ const cycle = [...path12.slice(Math.max(0, cycleStart)), id];
5159
5159
  throw invalid(`\u6280\u80FD\u4F9D\u8D56\u5B58\u5728\u73AF: ${cycle.join(" -> ")}`);
5160
5160
  }
5161
5161
  const skill = byId.get(id);
@@ -5164,11 +5164,11 @@ function resolveSkillInstallOrder(manifest2, targetId) {
5164
5164
  }
5165
5165
  assertSafeSkillId(skill.id);
5166
5166
  state.set(id, "visiting");
5167
- path9.push(id);
5167
+ path12.push(id);
5168
5168
  for (const required of normalizeRequirements(skill.requires, skill.id)) {
5169
5169
  visit(required, skill.id);
5170
5170
  }
5171
- path9.pop();
5171
+ path12.pop();
5172
5172
  state.set(id, "done");
5173
5173
  order.push(skill);
5174
5174
  };
@@ -5259,11 +5259,11 @@ async function resetSettingItem(http, domain, namespace, settingKey, revision) {
5259
5259
  function parseSettingAssignment(raw) {
5260
5260
  const eq = raw.indexOf("=");
5261
5261
  if (eq <= 0) throw new Error(`--set \u9700\u8981 namespace.key=value \u5F62\u6001\uFF0C\u6536\u5230 "${raw}"`);
5262
- const path9 = raw.slice(0, eq).trim();
5262
+ const path12 = raw.slice(0, eq).trim();
5263
5263
  const value = raw.slice(eq + 1);
5264
- const dot = path9.lastIndexOf(".");
5265
- if (dot <= 0) throw new Error(`--set \u7684\u952E\u9700\u542B namespace\uFF0C\u5982 security.password.passwordPolicy=complex\uFF0C\u6536\u5230 "${path9}"`);
5266
- return { namespace: path9.slice(0, dot), settingKey: path9.slice(dot + 1), value };
5264
+ const dot = path12.lastIndexOf(".");
5265
+ if (dot <= 0) throw new Error(`--set \u7684\u952E\u9700\u542B namespace\uFF0C\u5982 security.password.passwordPolicy=complex\uFF0C\u6536\u5230 "${path12}"`);
5266
+ return { namespace: path12.slice(0, dot), settingKey: path12.slice(dot + 1), value };
5267
5267
  }
5268
5268
 
5269
5269
  // src/fde/layout.ts
@@ -5657,11 +5657,11 @@ function classifyStatus(status) {
5657
5657
  return "bad-response";
5658
5658
  }
5659
5659
  var CAPABILITIES_HEADER = "x-hcm-capabilities";
5660
- function buildUrl(path9, params) {
5660
+ function buildUrl(path12, params) {
5661
5661
  const entries = Object.entries(params ?? {}).filter(([, v]) => v !== void 0 && v !== null);
5662
- if (entries.length === 0) return path9;
5662
+ if (entries.length === 0) return path12;
5663
5663
  const qs = entries.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`).join("&");
5664
- return `${path9}${path9.includes("?") ? "&" : "?"}${qs}`;
5664
+ return `${path12}${path12.includes("?") ? "&" : "?"}${qs}`;
5665
5665
  }
5666
5666
  function lowerHeaders(raw) {
5667
5667
  const out = {};
@@ -5703,14 +5703,14 @@ function httpProbe(http, capabilities) {
5703
5703
  const headers = { [CAPABILITIES_HEADER]: capabilities };
5704
5704
  const probe = {
5705
5705
  capabilities,
5706
- get(path9, params) {
5706
+ get(path12, params) {
5707
5707
  return once(
5708
- () => http.get(buildUrl(path9, params), { headers, validateStatus: () => true })
5708
+ () => http.get(buildUrl(path12, params), { headers, validateStatus: () => true })
5709
5709
  );
5710
5710
  },
5711
- post(path9, body) {
5711
+ post(path12, body) {
5712
5712
  return once(
5713
- () => http.post(path9, body, {
5713
+ () => http.post(path12, body, {
5714
5714
  headers: { ...headers, "content-type": "application/json" },
5715
5715
  validateStatus: () => true
5716
5716
  })
@@ -5822,8 +5822,8 @@ async function crawlMeta(probe, modelKeys2, metaType = DEFAULT_META_TYPE) {
5822
5822
  const results = probe.getMany ? await probe.getMany([...paths.keys()]) : await sequentialGet(probe, [...paths.keys()]);
5823
5823
  const metas = {};
5824
5824
  const unavailable = [];
5825
- for (const [path9, key] of paths) {
5826
- const out = results[path9];
5825
+ for (const [path12, key] of paths) {
5826
+ const out = results[path12];
5827
5827
  if (out === void 0) {
5828
5828
  unavailable.push({
5829
5829
  modelKey: key,
@@ -6039,8 +6039,8 @@ async function collectActionGates(probe, modelKeys2, state = "") {
6039
6039
  const statesEchoed = /* @__PURE__ */ new Set();
6040
6040
  let noStateEcho = 0;
6041
6041
  let answered = 0;
6042
- for (const [path9, model] of paths) {
6043
- const out = results[path9];
6042
+ for (const [path12, model] of paths) {
6043
+ const out = results[path12];
6044
6044
  if (out === void 0) {
6045
6045
  unavailable.push({
6046
6046
  modelKey: model,
@@ -6419,8 +6419,8 @@ async function collectMutation(probe, modelKeys2) {
6419
6419
  const results = probe.getMany ? await probe.getMany([...paths.keys()]) : await sequentialGet(probe, [...paths.keys()]);
6420
6420
  const mutation = {};
6421
6421
  const problems = [];
6422
- for (const [path9, key] of paths) {
6423
- const out = results[path9];
6422
+ for (const [path12, key] of paths) {
6423
+ const out = results[path12];
6424
6424
  if (out === void 0) {
6425
6425
  problems.push(`${key}: mutation-capability ${BATCH_LOST}`);
6426
6426
  mutation[key] = Object.fromEntries(
@@ -6865,11 +6865,11 @@ async function collectCodeTables(probe, modelEntries2, opts = {}) {
6865
6865
  keys.push(key);
6866
6866
  }
6867
6867
  for (const key of [...new Set(keys)].sort()) {
6868
- const path9 = listPath(key);
6868
+ const path12 = listPath(key);
6869
6869
  const started = tick();
6870
6870
  let requests = 0;
6871
6871
  let truncatedBy = null;
6872
- const probeOut = await post.call(probe, path9, { page: 0, size: 0 });
6872
+ const probeOut = await post.call(probe, path12, { page: 0, size: 0 });
6873
6873
  requests += 1;
6874
6874
  let total = null;
6875
6875
  let reason = null;
@@ -6918,7 +6918,7 @@ async function collectCodeTables(probe, modelEntries2, opts = {}) {
6918
6918
  failed = `\u89E6\u53D1\u5DE5\u5177\u7684\u6BCF\u8868${which === "requests" ? "\u8BF7\u6C42" : "\u5899\u949F"}\u4E0A\u9650\uFF08${which === "requests" ? `\u5DF2\u53D1 ${requests} \u6B21\u8BF7\u6C42` : `\u5DF2\u82B1 ${elapsed.toFixed(3)}s`}\uFF09\uFF0C\u505C\u5728\u7B2C ${page} \u9875\uFF0C\u5DF2\u6536 ${rows.length} \u884C / \u8BA1\u6570 ${total} \u884C\uFF0C\u672C\u8868\u6807 partial\u3002**\u8FD9\u662F\u5DE5\u5177\u7684\u622A\u65AD\uFF0C\u4E0D\u662F\u670D\u52A1\u7AEF\u7684\u6BDB\u75C5** \u2014\u2014 \u8C03\u5927 valuedomain.${which === "requests" ? "MAX_REQUESTS_PER_TABLE" : "MAX_SECONDS_PER_TABLE"} \u6216\u7ED9 collectCodeTables \u4F20 ${which === "requests" ? "maxRequests" : "maxSeconds"} \u540E\u91CD\u8DD1\u5C31\u80FD\u53D6\u5168`;
6919
6919
  break;
6920
6920
  }
6921
- const out = await post.call(probe, path9, { page, size: PAGE_SIZE });
6921
+ const out = await post.call(probe, path12, { page, size: PAGE_SIZE });
6922
6922
  requests += 1;
6923
6923
  if (out.error !== "ok") {
6924
6924
  failed = `\u7B2C ${page} \u9875\u5931\u8D25\uFF08HTTP ${out.status} / ${out.error}\uFF09`;
@@ -7551,16 +7551,1153 @@ async function runRecon(probe, layout, opts = {}) {
7551
7551
  dir: layout.dir
7552
7552
  };
7553
7553
  }
7554
+
7555
+ // src/fde/gate0/aclass.ts
7556
+ import { existsSync as existsSync4, readFileSync as readFileSync5, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
7557
+ import * as path9 from "path";
7558
+
7559
+ // src/fde/gate0/mapping-artifact.ts
7560
+ import { readFileSync as readFileSync4 } from "fs";
7561
+ var MAPPING_ARTIFACT_VERSION = 1;
7562
+ var MappingArtifactError = class extends Error {
7563
+ constructor(reason, message) {
7564
+ super(`[${reason}] ${message}`);
7565
+ this.reason = reason;
7566
+ this.message = message;
7567
+ this.name = "MappingArtifactError";
7568
+ }
7569
+ reason;
7570
+ message;
7571
+ };
7572
+ function isRecord6(value) {
7573
+ return typeof value === "object" && value !== null && !Array.isArray(value);
7574
+ }
7575
+ function readBusinessKeyFields(file) {
7576
+ let text;
7577
+ try {
7578
+ text = readFileSync4(file, "utf8");
7579
+ } catch (e) {
7580
+ const code = e?.code;
7581
+ if (code === "ENOENT") throw new MappingArtifactError("not-found", `\u627E\u4E0D\u5230\u6620\u5C04\u5DE5\u4EF6 ${file}`);
7582
+ throw new MappingArtifactError("unreadable", `${file} \u8BFB\u4E0D\u52A8\uFF08${String(e)}\uFF09`);
7583
+ }
7584
+ if (text.charCodeAt(0) === 65279) text = text.slice(1);
7585
+ let body;
7586
+ try {
7587
+ body = JSON.parse(text);
7588
+ } catch (e) {
7589
+ throw new MappingArtifactError("not-json", `${file} \u4E0D\u662F\u5408\u6CD5 JSON\uFF1A${String(e)}`);
7590
+ }
7591
+ if (!isRecord6(body)) {
7592
+ throw new MappingArtifactError("bad-shape", `${file} \u7684\u6839\u4E0D\u662F\u5BF9\u8C61`);
7593
+ }
7594
+ if (!("version" in body)) {
7595
+ throw new MappingArtifactError("version-missing", `${file} \u6CA1\u6709 version \u5B57\u6BB5`);
7596
+ }
7597
+ if (body.version !== MAPPING_ARTIFACT_VERSION) {
7598
+ throw new MappingArtifactError(
7599
+ "unsupported-version",
7600
+ `${file} \u7684 version \u662F ${JSON.stringify(body.version)}\uFF0C\u672C\u5DE5\u5177\u53EA\u8BA4 ${MAPPING_ARTIFACT_VERSION} \u2014\u2014\u300C\u5C3D\u91CF\u6309\u8001\u7248\u672C\u8BFB\u300D\u4F1A\u628A\u65B0\u8BED\u4E49\u9759\u9ED8\u4E22\u6389`
7601
+ );
7602
+ }
7603
+ const models = body.models;
7604
+ if (!Array.isArray(models)) {
7605
+ throw new MappingArtifactError(
7606
+ "bad-shape",
7607
+ `${file} \u7684 models \u5E94\u5F53\u662F\u4E00\u4E2A\u6570\u7EC4\uFF0C\u5B9E\u9645\u662F ${models === null ? "null" : typeof models}`
7608
+ );
7609
+ }
7610
+ if (models.length === 0) {
7611
+ throw new MappingArtifactError(
7612
+ "empty",
7613
+ `${file} \u7684 models \u662F\u7A7A\u7684 \u2014\u2014 \u7A7A\u5DE5\u4EF6\u8DD1\u5B8C\u4EC0\u4E48\u4E5F\u4E0D\u4F1A\u53D1\u751F\uFF0C\u800C\u987E\u95EE\u4F1A\u4EE5\u4E3A\u300C\u5BFC\u8FC7\u4E86\u300D`
7614
+ );
7615
+ }
7616
+ return models.map((raw, i) => {
7617
+ if (!isRecord6(raw)) {
7618
+ throw new MappingArtifactError("bad-shape", `${file} \u7684 models[${i}] \u4E0D\u662F\u5BF9\u8C61`);
7619
+ }
7620
+ const businessKey = raw.businessKey;
7621
+ if (businessKey === void 0 || businessKey === null) return [];
7622
+ if (!isRecord6(businessKey)) {
7623
+ throw new MappingArtifactError("bad-shape", `${file} \u7684 models[${i}].businessKey \u4E0D\u662F\u5BF9\u8C61`);
7624
+ }
7625
+ const fields = businessKey.fields;
7626
+ if (fields === void 0 || fields === null) return [];
7627
+ if (!Array.isArray(fields)) {
7628
+ throw new MappingArtifactError(
7629
+ "bad-shape",
7630
+ `${file} \u7684 models[${i}].businessKey.fields \u4E0D\u662F\u6570\u7EC4`
7631
+ );
7632
+ }
7633
+ return fields.filter((f) => typeof f === "string" && f !== "");
7634
+ });
7635
+ }
7636
+
7637
+ // src/fde/gate0/aclass.ts
7638
+ var ACLASS_KINDS = [
7639
+ "fieldKey",
7640
+ "fieldLabel",
7641
+ "enumValue",
7642
+ "modelName",
7643
+ "codeValue",
7644
+ "naturalKey",
7645
+ "caliber"
7646
+ ];
7647
+ var FIELDS_INDEX = ["index", "fields.jsonl"];
7648
+ var ENUM_MIRROR = ["valuedomain", "_enums.jsonl"];
7649
+ var MODEL_ROSTER = ["models.json"];
7650
+ var VALUE_DOMAIN_DIR = "valuedomain";
7651
+ var ENUM_ELEMENT_KEYS = ["value", "label", "key"];
7652
+ var MAPPING_ARTIFACT_HINT = "work/mapping.json";
7653
+ var CLASS_SCOPE = "class";
7654
+ var ENTRY_SCOPE = "entry";
7655
+ var SCOPES = [CLASS_SCOPE, ENTRY_SCOPE];
7656
+ var REASON_UNREAD = "unread";
7657
+ var REASON_EMPTY = "empty";
7658
+ var CLASS_REASONS = [REASON_UNREAD, REASON_EMPTY];
7659
+ function unguardedKinds(problems) {
7660
+ const out = /* @__PURE__ */ new Set();
7661
+ for (const problem of problems) {
7662
+ if (!SCOPES.includes(problem.scope)) {
7663
+ throw new Error(
7664
+ `\u53F0\u8D26\u7684 scope \u53EA\u6709 ${SCOPES.join("/")} \u4E24\u4E2A\u53D6\u503C\uFF0C\u62FF\u5230\u7684\u662F ${JSON.stringify(problem.scope)}\uFF08${problem.message}\uFF09`
7665
+ );
7666
+ }
7667
+ if (problem.scope === CLASS_SCOPE) for (const kind of problem.kinds) out.add(kind);
7668
+ }
7669
+ return out;
7670
+ }
7671
+ function unguardedWord(kinds) {
7672
+ return kinds.join("/");
7673
+ }
7674
+ function token(value) {
7675
+ if (typeof value === "string") return value === "" ? null : value;
7676
+ if (typeof value === "number" && Number.isFinite(value)) return String(value);
7677
+ return null;
7678
+ }
7679
+ function scalarsWithin(value) {
7680
+ if (Array.isArray(value)) return value.flatMap(scalarsWithin);
7681
+ if (typeof value === "object" && value !== null) {
7682
+ return Object.values(value).flatMap(scalarsWithin);
7683
+ }
7684
+ const one = token(value);
7685
+ return one === null ? [] : [one];
7686
+ }
7687
+ function readText(file, kinds, scope, problems) {
7688
+ try {
7689
+ return readFileSync5(file, "utf8");
7690
+ } catch (e) {
7691
+ const code = e?.code;
7692
+ const name = path9.basename(file);
7693
+ problems.push({
7694
+ scope,
7695
+ reason: REASON_UNREAD,
7696
+ kinds,
7697
+ message: code === "ENOENT" ? `\u7F3A\u4EA7\u7269 ${name} \u21D2 ${unguardedWord(kinds)} \u8FD9\u51E0\u7C7B\u6B64\u523B\u65E0\u4EBA\u5B88` : `\u4EA7\u7269 ${name} \u8BFB\u4E0D\u52A8\uFF08${String(e)}\uFF09\u21D2 ${unguardedWord(kinds)} \u8FD9\u51E0\u7C7B\u6B64\u523B\u65E0\u4EBA\u5B88`
7698
+ });
7699
+ return null;
7700
+ }
7701
+ }
7702
+ function readJsonl(file, kinds, scope, problems) {
7703
+ const text = readText(file, kinds, scope, problems);
7704
+ if (text === null) return [];
7705
+ const name = path9.basename(file);
7706
+ const rows = [];
7707
+ text.split("\n").forEach((raw, i) => {
7708
+ const line = raw.trim();
7709
+ if (line === "") return;
7710
+ let row;
7711
+ try {
7712
+ row = JSON.parse(line);
7713
+ } catch (e) {
7714
+ problems.push({
7715
+ scope: ENTRY_SCOPE,
7716
+ reason: "bad-line",
7717
+ kinds,
7718
+ message: `${name}:${i + 1} \u4E0D\u662F\u5408\u6CD5 JSON\uFF08${String(e)}\uFF09\u21D2 \u8FD9\u4E00\u884C\u7684\u53D6\u503C\u6CA1\u6709\u8FDB ${unguardedWord(kinds)}`
7719
+ });
7720
+ return;
7721
+ }
7722
+ if (typeof row !== "object" || row === null || Array.isArray(row)) {
7723
+ problems.push({
7724
+ scope: ENTRY_SCOPE,
7725
+ reason: "bad-line",
7726
+ kinds,
7727
+ message: `${name}:${i + 1} \u4E0D\u662F\u5BF9\u8C61\uFF08${row === null ? "null" : typeof row}\uFF09\u21D2 \u8FD9\u4E00\u884C\u7684\u53D6\u503C\u6CA1\u6709\u8FDB ${unguardedWord(kinds)}`
7728
+ });
7729
+ return;
7730
+ }
7731
+ rows.push(row);
7732
+ });
7733
+ return rows;
7734
+ }
7735
+ var UNREADABLE = /* @__PURE__ */ Symbol("unreadable");
7736
+ function readJson(file, kinds, scope, problems) {
7737
+ const text = readText(file, kinds, scope, problems);
7738
+ if (text === null) return UNREADABLE;
7739
+ try {
7740
+ return JSON.parse(text);
7741
+ } catch (e) {
7742
+ problems.push({
7743
+ scope,
7744
+ reason: REASON_UNREAD,
7745
+ kinds,
7746
+ message: `\u4EA7\u7269 ${path9.basename(file)} \u4E0D\u662F\u5408\u6CD5 JSON\uFF08${String(e)}\uFF09\u21D2 ${unguardedWord(kinds)} \u8FD9\u51E0\u7C7B\u6B64\u523B\u65E0\u4EBA\u5B88`
7747
+ });
7748
+ return UNREADABLE;
7749
+ }
7750
+ }
7751
+ function listUnder(payload, key, file, kinds, scope, problems) {
7752
+ const name = path9.basename(file);
7753
+ if (typeof payload !== "object" || payload === null || Array.isArray(payload)) {
7754
+ problems.push({
7755
+ scope,
7756
+ reason: REASON_UNREAD,
7757
+ kinds,
7758
+ message: `\u4EA7\u7269 ${name} \u4E0D\u662F\u5BF9\u8C61\uFF08${payload === null ? "null" : Array.isArray(payload) ? "array" : typeof payload}\uFF09\u21D2 ${unguardedWord(kinds)} \u8FD9\u51E0\u7C7B\u6B64\u523B\u65E0\u4EBA\u5B88`
7759
+ });
7760
+ return [];
7761
+ }
7762
+ const body = payload;
7763
+ if (!(key in body)) {
7764
+ problems.push({
7765
+ scope,
7766
+ reason: REASON_UNREAD,
7767
+ kinds,
7768
+ message: `\u4EA7\u7269 ${name} \u91CC\u6CA1\u6709 ${key} \u8FD9\u4E2A\u952E\uFF08\u9876\u5C42\u952E\u662F ${JSON.stringify(Object.keys(body).sort())}\uFF09\u21D2 ${unguardedWord(kinds)} \u8FD9\u51E0\u7C7B\u6B64\u523B\u65E0\u4EBA\u5B88`
7769
+ });
7770
+ return [];
7771
+ }
7772
+ const value = body[key];
7773
+ if (!Array.isArray(value)) {
7774
+ problems.push({
7775
+ scope,
7776
+ reason: REASON_UNREAD,
7777
+ kinds,
7778
+ message: `\u4EA7\u7269 ${name} \u7684 ${key} \u4E0D\u662F\u6570\u7EC4\uFF08${value === null ? "null" : typeof value}\uFF09\u21D2 ${unguardedWord(kinds)} \u8FD9\u51E0\u7C7B\u6B64\u523B\u65E0\u4EBA\u5B88`
7779
+ });
7780
+ return [];
7781
+ }
7782
+ return value;
7783
+ }
7784
+ function deriveAclass(root, mappingArtifact = null) {
7785
+ const problems = [];
7786
+ const out = Object.fromEntries(ACLASS_KINDS.map((k) => [k, /* @__PURE__ */ new Set()]));
7787
+ for (const row of readJsonl(
7788
+ path9.join(root, ...FIELDS_INDEX),
7789
+ ["fieldKey", "fieldLabel", "caliber"],
7790
+ CLASS_SCOPE,
7791
+ problems
7792
+ )) {
7793
+ const key = token(row.key);
7794
+ if (key !== null) out.fieldKey.add(key);
7795
+ const name = token(row.name);
7796
+ if (name !== null) out.fieldLabel.add(name);
7797
+ const synonyms = row.synonyms;
7798
+ for (const syn of Array.isArray(synonyms) ? synonyms : []) {
7799
+ const one = token(syn);
7800
+ if (one !== null) out.caliber.add(one);
7801
+ }
7802
+ }
7803
+ for (const row of readJsonl(
7804
+ path9.join(root, ...ENUM_MIRROR),
7805
+ ["enumValue"],
7806
+ CLASS_SCOPE,
7807
+ problems
7808
+ )) {
7809
+ const enums = row.enums;
7810
+ for (const element of Array.isArray(enums) ? enums : []) {
7811
+ if (typeof element !== "object" || element === null || Array.isArray(element)) continue;
7812
+ for (const field of ENUM_ELEMENT_KEYS) {
7813
+ const one = token(element[field]);
7814
+ if (one !== null) out.enumValue.add(one);
7815
+ }
7816
+ }
7817
+ }
7818
+ const rosterPath = path9.join(root, ...MODEL_ROSTER);
7819
+ const roster = readJson(rosterPath, ["modelName"], CLASS_SCOPE, problems);
7820
+ if (roster !== UNREADABLE) {
7821
+ const rows = listUnder(roster, "models", rosterPath, ["modelName"], CLASS_SCOPE, problems);
7822
+ const entries = modelEntries(roster);
7823
+ const keys = modelKeys(roster);
7824
+ for (const key of keys) out.modelName.add(key);
7825
+ for (const entry of entries) {
7826
+ const name = token(entry.name);
7827
+ if (name !== null) out.modelName.add(name);
7828
+ }
7829
+ if (rows.length !== entries.length) {
7830
+ problems.push({
7831
+ scope: ENTRY_SCOPE,
7832
+ reason: "dropped-entries",
7833
+ kinds: ["modelName"],
7834
+ message: `models.json \u91CC ${rows.length} \u6761\u6A21\u578B\u6761\u76EE\u6709 ${rows.length - entries.length} \u6761\u4E0D\u662F\u5BF9\u8C61 \u21D2 \u5B83\u4EEC\u7684\u6A21\u578B\u540D\u6CA1\u6709\u8FDB modelName`
7835
+ });
7836
+ }
7837
+ if (entries.length !== keys.length) {
7838
+ problems.push({
7839
+ scope: ENTRY_SCOPE,
7840
+ reason: "dropped-keys",
7841
+ kinds: ["modelName"],
7842
+ message: `models.json \u91CC ${entries.length} \u6761\u6A21\u578B\u6761\u76EE\u6709 ${entries.length - keys.length} \u6761\u6CA1\u6709 modelKey \u21D2 \u5B83\u4EEC\u7684\u82F1\u6587\u6A21\u578B\u540D\u6CA1\u6709\u8FDB modelName`
7843
+ });
7844
+ }
7845
+ }
7846
+ const valueDomain = path9.join(root, VALUE_DOMAIN_DIR);
7847
+ if (existsSync4(valueDomain) && statSync2(valueDomain).isDirectory()) {
7848
+ const tables = readdirSync2(valueDomain).filter((f) => f.endsWith(".json") && !RESERVED_FILENAMES.includes(f)).sort();
7849
+ for (const name of tables) {
7850
+ const file = path9.join(valueDomain, name);
7851
+ const payload = readJson(file, ["codeValue"], ENTRY_SCOPE, problems);
7852
+ if (payload === UNREADABLE) continue;
7853
+ for (const row of listUnder(payload, "rows", file, ["codeValue"], ENTRY_SCOPE, problems)) {
7854
+ if (typeof row !== "object" || row === null || Array.isArray(row)) {
7855
+ problems.push({
7856
+ scope: ENTRY_SCOPE,
7857
+ reason: "bad-row",
7858
+ kinds: ["codeValue"],
7859
+ message: `${name} \u7684 rows \u91CC\u6709\u4E00\u4E2A\u5143\u7D20\u4E0D\u662F\u5BF9\u8C61\uFF08${row === null ? "null" : typeof row}\uFF09\u21D2 \u5B83\u7684\u53D6\u503C\u6CA1\u6709\u8FDB codeValue`
7860
+ });
7861
+ continue;
7862
+ }
7863
+ for (const value of scalarsWithin(row)) out.codeValue.add(value);
7864
+ }
7865
+ }
7866
+ } else {
7867
+ problems.push({
7868
+ scope: CLASS_SCOPE,
7869
+ reason: REASON_UNREAD,
7870
+ kinds: ["codeValue"],
7871
+ message: `\u7F3A\u4EA7\u7269\u76EE\u5F55 ${VALUE_DOMAIN_DIR}/ \u21D2 codeValue \u8FD9\u4E00\u7C7B\u6B64\u523B\u65E0\u4EBA\u5B88`
7872
+ });
7873
+ }
7874
+ let businessKeys = null;
7875
+ if (mappingArtifact === null) {
7876
+ problems.push({
7877
+ scope: CLASS_SCOPE,
7878
+ reason: REASON_UNREAD,
7879
+ kinds: ["naturalKey"],
7880
+ message: `\u6CA1\u6709\u6307\u5B9A\u6620\u5C04\u5DE5\u4EF6 \u21D2 naturalKey \u8FD9\u4E00\u7C7B\u6B64\u523B\u65E0\u4EBA\u5B88\uFF08\u628A ${MAPPING_ARTIFACT_HINT} \u7684\u8DEF\u5F84\u4F20\u8FDB\u6765\uFF09`
7881
+ });
7882
+ } else {
7883
+ try {
7884
+ businessKeys = readBusinessKeyFields(mappingArtifact);
7885
+ } catch (e) {
7886
+ const err = e;
7887
+ problems.push({
7888
+ scope: CLASS_SCOPE,
7889
+ reason: REASON_UNREAD,
7890
+ kinds: ["naturalKey"],
7891
+ message: `\u6620\u5C04\u5DE5\u4EF6\u8BFB\u4E0D\u52A8\uFF08[${err.reason ?? "unknown"}] ${err.message}\uFF09\u21D2 naturalKey \u8FD9\u4E00\u7C7B\u6B64\u523B\u65E0\u4EBA\u5B88`
7892
+ });
7893
+ }
7894
+ }
7895
+ for (const fields of businessKeys ?? []) {
7896
+ for (const field of fields) out.naturalKey.add(field);
7897
+ if (fields.length > 1) {
7898
+ out.naturalKey.add(fields.join("+"));
7899
+ }
7900
+ }
7901
+ const named = unguardedKinds(problems);
7902
+ for (const kind of ACLASS_KINDS) {
7903
+ if (out[kind].size === 0 && !named.has(kind)) {
7904
+ problems.push({
7905
+ scope: CLASS_SCOPE,
7906
+ reason: REASON_EMPTY,
7907
+ kinds: [kind],
7908
+ message: `${kind}\uFF1A\u4EA7\u7269\u8BFB\u5230\u4E86\uFF0C\u4F46\u4E00\u6761\u53D6\u503C\u90FD\u6CA1\u6D3E\u751F\u51FA\u6765 \u21D2 \u95E8 0 \u5BF9\u8FD9\u4E00\u7C7B\u6052\u7EFF\uFF08\u540C\u6279\u53F0\u8D26\u91CC\u82E5\u6709\u6761\u76EE\u7EA7\u95EE\u9898\uFF0C\u771F\u56E0\u5728\u90A3\u91CC\uFF09`
7909
+ });
7910
+ }
7911
+ }
7912
+ return { aclass: out, problems };
7913
+ }
7914
+
7915
+ // src/fde/gate0/facts.ts
7916
+ import { existsSync as existsSync5, readFileSync as readFileSync6 } from "fs";
7917
+ import * as path10 from "path";
7918
+ var REGISTRY_SCOPE = "registry";
7919
+ var ENTRY_SCOPE2 = "entry";
7920
+ var REASON_NO_ENTRIES = "no-entries";
7921
+ var REASON_PROBE_UNVERIFIED = "probe-unverified";
7922
+ var REGISTRY_REASONS = [REASON_NO_ENTRIES, REASON_PROBE_UNVERIFIED];
7923
+ var REASON_PROBE_SHAPE = "probe-shape";
7924
+ var REASON_PROBE_ABSENT = "probe-absent";
7925
+ var REASON_DUPLICATE_TOKEN = "duplicate-token";
7926
+ var ENTRY_REASONS = [
7927
+ REASON_PROBE_SHAPE,
7928
+ REASON_PROBE_ABSENT,
7929
+ REASON_DUPLICATE_TOKEN
7930
+ ];
7931
+ var FACTS_REASONS = [...REGISTRY_REASONS, ...ENTRY_REASONS];
7932
+ var PROBE_SHAPE = /^(?<file>[A-Za-z0-9_./-]+\.test\.ts)::(?<mark>[A-Za-z0-9_-]+)$/;
7933
+ var PROBE_MARK_PREFIX = "// P:";
7934
+ var PROTOCOL_FACTS = [
7935
+ {
7936
+ token: "/api/models/{model}/meta",
7937
+ probe: "packages/core/tests/fde-recon-crawl.test.ts::meta-path-wire-shape",
7938
+ note: "\u5B57\u6BB5\u5143\u6570\u636E\u8D70\u88F8\u8DEF\u5F84 GET\uFF0C\u9ED8\u8BA4\u4E0D\u7F00 ?type=\u3002\u63A2\u9488\u65AD\u7684\u662F**\u5B9E\u9645\u53D1\u51FA\u53BB\u7684 URL**\uFF0C\u4E0D\u662F\u62FC\u4E32\u51FD\u6570\u7684\u8FD4\u56DE\u503C\u3002"
7939
+ },
7940
+ {
7941
+ token: "/api/models/{model}/list/dsl",
7942
+ probe: "packages/core/tests/fde-recon-valuedomain.test.ts::list-dsl-count-probe",
7943
+ note: "\u5217\u8868\u67E5\u8BE2\u8D70 POST DSL\u3002\u63A2\u9488\u65AD\u7684\u662F\u884C\u4E3A\uFF1Asize=0 \u7684\u90A3\u4E00\u53D1\u5148\u51FA\u4E14\u8FD4\u56DE totalElements\uFF0C\u53D6\u9875\u5224\u636E\u4EE5\u6B64\u4E3A\u524D\u63D0\u3002"
7944
+ },
7945
+ {
7946
+ token: "/api/auth/login",
7947
+ probe: "packages/core/tests/fde-gate0-facts.test.ts::login-body-carries-tenant",
7948
+ note: "\u767B\u5F55\u7684 tenantId \u5728**\u8BF7\u6C42\u4F53**\u91CC\uFF0C\u4E0D\u5728 header\u3002\u63A2\u9488\u65AD\u7684\u662F\u5B9E\u9645\u53D1\u51FA\u53BB\u7684\u8BF7\u6C42\u4F53\u4E0E\u8BF7\u6C42\u5934\uFF0C\u5220\u6389 tenantId \u6216\u632A\u8FDB header \u90FD\u4F1A\u7EA2\u3002"
7949
+ }
7950
+ ];
7951
+ function loadProtocolFacts(entries = PROTOCOL_FACTS, options = {}) {
7952
+ const problems = [];
7953
+ const probeRoot = options.probeRoot;
7954
+ if (probeRoot === void 0 && entries !== PROTOCOL_FACTS) {
7955
+ problems.push({
7956
+ scope: REGISTRY_SCOPE,
7957
+ reason: REASON_PROBE_UNVERIFIED,
7958
+ index: 0,
7959
+ token: null,
7960
+ message: "\u8FD9\u4EFD\u767B\u8BB0\u518C\u4E0D\u662F\u968F\u5305\u90A3\u4E00\u4EFD\uFF0C\u53C8\u6CA1\u6709\u7ED9\u63A2\u9488\u6839\u76EE\u5F55 \u21D2 \u4E00\u6761\u63A2\u9488\u90FD\u6CA1\u9A8C\u8FC7 \u2014\u2014\u300C\u63A2\u9488\u90FD\u5728\u300D\u4E0E\u300C\u6CA1\u67E5\u63A2\u9488\u300D\u5728\u8FD4\u56DE\u503C\u4E0A\u540C\u5F62\uFF0C\u6240\u4EE5\u8FD9\u91CC\u8BB0\u4E00\u7B14\uFF0C\u4E0D\u88C5\u4F5C\u9A8C\u8FC7"
7961
+ });
7962
+ }
7963
+ if (entries.length === 0) {
7964
+ problems.push({
7965
+ scope: REGISTRY_SCOPE,
7966
+ reason: REASON_NO_ENTRIES,
7967
+ index: 0,
7968
+ token: null,
7969
+ message: "\u767B\u8BB0\u518C\u4E00\u6761\u90FD\u6CA1\u6709 \u2014\u2014 **\u67E5\u8FC7\u4E14\u4E3A\u7A7A**\uFF0C\u4E0D\u662F\u300C\u6CA1\u67E5\u300D"
7970
+ });
7971
+ }
7972
+ const times = /* @__PURE__ */ new Map();
7973
+ for (const entry of entries) times.set(entry.token, (times.get(entry.token) ?? 0) + 1);
7974
+ const facts = [];
7975
+ entries.forEach((entry, position) => {
7976
+ const index = position + 1;
7977
+ if ((times.get(entry.token) ?? 0) > 1) {
7978
+ problems.push({
7979
+ scope: ENTRY_SCOPE2,
7980
+ reason: REASON_DUPLICATE_TOKEN,
7981
+ index,
7982
+ token: entry.token,
7983
+ message: `${entry.token} \u767B\u8BB0\u4E86\u4E0D\u6B62\u4E00\u6B21 \u21D2 \u4E24\u6761\u90FD\u4E0D\u8FDB P\uFF08\u7559\u4E0B\u4EFB\u4F55\u4E00\u8FB9\u90FD\u8981\u56DE\u7B54\u300C\u4EE5\u54EA\u4EFD\u4E3A\u51C6\u300D\uFF09`
7984
+ });
7985
+ return;
7986
+ }
7987
+ const shape = PROBE_SHAPE.exec(entry.probe);
7988
+ if (!shape?.groups) {
7989
+ problems.push({
7990
+ scope: ENTRY_SCOPE2,
7991
+ reason: REASON_PROBE_SHAPE,
7992
+ index,
7993
+ token: entry.token,
7994
+ message: `${entry.token} \u7684\u63A2\u9488 ${JSON.stringify(entry.probe)} \u4E0D\u662F \`<\u6D4B\u8BD5\u6587\u4EF6>.test.ts::<\u6807\u8BB0>\` \u5F62\u6001 \u2014\u2014 \u53EA\u7ED9\u6587\u4EF6\u8DEF\u5F84\u662F\u540C\u4E49\u53CD\u590D\uFF08\u300C\u90A3\u4E2A\u6587\u4EF6\u5B58\u5728\u300D\u4E0D\u7B97\u80CC\u4E66\uFF09`
7995
+ });
7996
+ return;
7997
+ }
7998
+ if (probeRoot !== void 0) {
7999
+ const file = path10.join(probeRoot, shape.groups.file);
8000
+ const mark = `${PROBE_MARK_PREFIX} ${shape.groups.mark}`;
8001
+ const found = existsSync5(file) && readFileSync6(file, "utf8").includes(mark);
8002
+ if (!found) {
8003
+ problems.push({
8004
+ scope: ENTRY_SCOPE2,
8005
+ reason: REASON_PROBE_ABSENT,
8006
+ index,
8007
+ token: entry.token,
8008
+ message: `${entry.token} \u7684\u63A2\u9488\u6307\u5411 ${entry.probe}\uFF0C\u4F46\u90A3\u91CC\u627E\u4E0D\u5230 \`${mark}\` \u8FD9\u6761\u6807\u8BB0 \u21D2 \u8FD9\u6761\u767B\u8BB0\u6CA1\u6709\u80CC\u4E66\uFF0C\u4E0D\u8FDB P`
8009
+ });
8010
+ return;
8011
+ }
8012
+ }
8013
+ facts.push(entry.token);
8014
+ });
8015
+ return { facts, problems };
8016
+ }
8017
+
8018
+ // src/fde/gate0/scan.ts
8019
+ import { readFileSync as readFileSync7, readdirSync as readdirSync3, readlinkSync, statSync as statSync3 } from "fs";
8020
+ import * as path11 from "path";
8021
+ var CHANNEL_ACLASS = "aclass";
8022
+ var CHANNEL_ARTIFACT = "artifact-path";
8023
+ var CHANNEL_UNREGISTERED = "protocol-unregistered";
8024
+ var CHANNEL_REGISTERED_IS_ACLASS = "registered-but-is-aclass";
8025
+ var CHANNEL_NO_PROBE = "no-probe";
8026
+ var CHANNELS = [
8027
+ CHANNEL_ACLASS,
8028
+ CHANNEL_ARTIFACT,
8029
+ CHANNEL_UNREGISTERED,
8030
+ CHANNEL_REGISTERED_IS_ACLASS,
8031
+ CHANNEL_NO_PROBE
8032
+ ];
8033
+ var REASON_NO_SKILL_ROOT = "no-skill-root";
8034
+ var REASON_NOTHING_SCANNED = "nothing-scanned";
8035
+ var REASON_FILE_UNREADABLE = "file-unreadable";
8036
+ var REASON_ACLASS_EMPTY = "aclass-empty";
8037
+ var REASON_ACLASS_PARTIALLY_UNREAD = "aclass-partially-unread";
8038
+ var REASON_REGISTRY = "registry-not-established";
8039
+ var REASON_CHANNEL_FOUR_UNCHECKED = "channel-four-unchecked";
8040
+ var REASON_BASELINE_ROUND_NOT_COMPLETE = "baseline-round-not-complete";
8041
+ var REASON_SYMLINK_NOT_SCANNED = "symlink-not-scanned";
8042
+ var PREMISE_REASONS = [
8043
+ REASON_NO_SKILL_ROOT,
8044
+ REASON_NOTHING_SCANNED,
8045
+ REASON_FILE_UNREADABLE,
8046
+ REASON_ACLASS_EMPTY,
8047
+ REASON_ACLASS_PARTIALLY_UNREAD,
8048
+ REASON_REGISTRY,
8049
+ REASON_CHANNEL_FOUR_UNCHECKED,
8050
+ REASON_BASELINE_ROUND_NOT_COMPLETE,
8051
+ REASON_SYMLINK_NOT_SCANNED
8052
+ ];
8053
+ var PREMISE_REGISTRY_REASONS = REGISTRY_REASONS.filter(
8054
+ (r) => r !== REASON_NO_ENTRIES
8055
+ );
8056
+ var WORD_RE = /[A-Za-z0-9_]+/g;
8057
+ var SIMPLE_TOKEN = /^[A-Za-z0-9_]+$/;
8058
+ var WORD_CHARS = new Set("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_");
8059
+ function isWordChar(char) {
8060
+ return char !== void 0 && WORD_CHARS.has(char);
8061
+ }
8062
+ var ENDPOINT_PREFIXES = ["api", "ws"];
8063
+ var ENDPOINT_PATH = `/(?:${ENDPOINT_PREFIXES.join("|")})(?:/(?:\\{[A-Za-z0-9_]+\\}|[A-Za-z0-9_.\\-]+))+`;
8064
+ var BARE_ENDPOINT_RE = new RegExp(`(?<![A-Za-z0-9_.\\-/])${ENDPOINT_PATH}`, "g");
8065
+ var URL_ENDPOINT_RE = new RegExp(
8066
+ `[A-Za-z][A-Za-z0-9+.\\-]*://[^\\s"'\`<>]*?(${ENDPOINT_PATH})`,
8067
+ "g"
8068
+ );
8069
+ var HOSTLESS_HOST = `(?:(?:[A-Za-z0-9_\\-]+\\.)+[A-Za-z]{2,}(?::[0-9]+)?|[A-Za-z0-9_\\-]+:[0-9]+)`;
8070
+ var HOSTLESS_ENDPOINT_RE = new RegExp(
8071
+ `(?<![A-Za-z0-9_.\\-/:@])${HOSTLESS_HOST}(${ENDPOINT_PATH})`,
8072
+ "g"
8073
+ );
8074
+ var ERROR_CODE_RE = /(?<![A-Za-z0-9_])[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+(?![A-Za-z0-9_])/g;
8075
+ var PATHISH_RE = /(?<![A-Za-z0-9_./-])\.?[A-Za-z0-9_.-]+(?:\/[A-Za-z0-9_.-]+)+/g;
8076
+ var ARTIFACT_SUFFIXES = [".json", ".jsonl"];
8077
+ var PRODUCT_FILE_RE = new RegExp(
8078
+ `(?<![A-Za-z0-9_./\\-])[A-Za-z0-9_.\\-]+(?:${ARTIFACT_SUFFIXES.map((s) => s.replace(".", "\\.")).join("|")})(?![A-Za-z0-9_])`,
8079
+ "g"
8080
+ );
8081
+ var PLACEHOLDER_RE2 = /\{[A-Za-z0-9_]*\}/g;
8082
+ var ARTIFACT_ROOT = ".hcmnx";
8083
+ var RECON_DIRNAME = "recon";
8084
+ var RECON_SEGMENTS_BELOW_ROOT = 2;
8085
+ var PRODUCT_RELATIVE_SHAPES = [
8086
+ ["index", ".md"],
8087
+ ["index", ".jsonl"],
8088
+ ["mapping", ".json"],
8089
+ ["meta", ".json"],
8090
+ ["valuedomain", ".json"],
8091
+ ["valuedomain", ".jsonl"]
8092
+ ];
8093
+ var REASON_ENVIRONMENT_FACT = "environment-fact";
8094
+ var REASON_PRODUCT_TREE_PATH = "product-tree-path";
8095
+ var REASON_PRODUCT_RELATIVE_PATH = "product-relative-path";
8096
+ var REASON_PRODUCT_FILE_NAME = "product-file-name";
8097
+ var REASON_ENDPOINT = "endpoint";
8098
+ var REASON_ERROR_CODE = "error-code";
8099
+ var REASON_REGISTERED_IS_ACLASS = "registered-is-aclass";
8100
+ var REASON_REJECTED_REGISTRATION = "rejected-registration";
8101
+ var RED_REASONS = {
8102
+ [CHANNEL_ACLASS]: [REASON_ENVIRONMENT_FACT],
8103
+ [CHANNEL_ARTIFACT]: [
8104
+ REASON_PRODUCT_TREE_PATH,
8105
+ REASON_PRODUCT_RELATIVE_PATH,
8106
+ REASON_PRODUCT_FILE_NAME
8107
+ ],
8108
+ [CHANNEL_UNREGISTERED]: [REASON_ENDPOINT, REASON_ERROR_CODE],
8109
+ [CHANNEL_REGISTERED_IS_ACLASS]: [REASON_REGISTERED_IS_ACLASS],
8110
+ [CHANNEL_NO_PROBE]: [REASON_REJECTED_REGISTRATION]
8111
+ };
8112
+ var ARTIFACT_WORDING = {
8113
+ [REASON_PRODUCT_TREE_PATH]: (t) => `\u51FA\u73B0**\u4EA7\u7269\u6811\u91CC\u7684**\u8DEF\u5F84 ${JSON.stringify(t)}`,
8114
+ [REASON_PRODUCT_RELATIVE_PATH]: (t) => `\u51FA\u73B0**\u4EA7\u7269\u6839\u76F8\u5BF9\u8DEF\u5F84** ${JSON.stringify(t)}\uFF08\u4EA7\u7269\u5B50\u76EE\u5F55\u4E0B\u7684\u90A3\u4E00\u4EFD\uFF09`,
8115
+ [REASON_PRODUCT_FILE_NAME]: (t) => `\u51FA\u73B0\u4EA7\u7269\u6587\u4EF6\u540D\u5F62\u6001 ${JSON.stringify(t)}\uFF08\u4EE5 .json/.jsonl \u6536\u5C3E\uFF1B**\u8FD9\u4E00\u6863\u4F1A\u8FC7\u5224**\uFF0C\u5B83\u4E0E\u4EA7\u7269\u65E0\u5173\u65F6\u8BF7\u7167\u76F4\u8BF4\u660E\uFF09`
8116
+ };
8117
+ function artifactWordingFor(reason) {
8118
+ const wording = ARTIFACT_WORDING[reason];
8119
+ if (wording === void 0) {
8120
+ throw new Error(
8121
+ `\u4EA7\u7269\u8DEF\u5F84\u6210\u56E0 ${JSON.stringify(reason)} \u6CA1\u6709\u5BF9\u5E94\u7684\u63AA\u8F9E\uFF08\u8BA4\u5F97\u7684\u662F ${Object.keys(ARTIFACT_WORDING).join("/")}\uFF09`
8122
+ );
8123
+ }
8124
+ return wording;
8125
+ }
8126
+ var ACLASS_EMPTY_WHY = {
8127
+ [REASON_UNREAD]: "\uFF08\u4EA7\u7269/\u5DE5\u4EF6\u90A3\u4E00\u5934\u6839\u672C\u6CA1\u8BFB\u5230\uFF09",
8128
+ [REASON_EMPTY]: "\uFF08\u4EA7\u7269\u8BFB\u5230\u4E86\uFF0C\u4E00\u6761\u53D6\u503C\u90FD\u6CA1\u6D3E\u751F\u51FA\u6765\uFF09"
8129
+ };
8130
+ var GAP_NOISE_TOKEN = "pure-digit-or-single-char";
8131
+ var GAP_CJK_INSIDE_LONGER_RUN = "cjk-inside-longer-run";
8132
+ var GAP_REASONS = [GAP_NOISE_TOKEN, GAP_CJK_INSIDE_LONGER_RUN];
8133
+ function checkReds(reds) {
8134
+ for (const red of reds) {
8135
+ if (!CHANNELS.includes(red.channel)) {
8136
+ throw new Error(
8137
+ `\u5224\u7EA2\u7684 channel \u53EA\u6709 ${CHANNELS.join("/")} \u8FD9\u51E0\u4E2A\u53D6\u503C\uFF0C\u62FF\u5230\u7684\u662F ${JSON.stringify(red.channel)}\uFF08${red.message}\uFF09`
8138
+ );
8139
+ }
8140
+ if (!RED_REASONS[red.channel].includes(red.reason)) {
8141
+ throw new Error(
8142
+ `${JSON.stringify(red.reason)} \u8FD9\u4E2A reason \u4E0D\u5C5E\u4E8E ${red.channel} \u8FD9\u6761\u901A\u9053\uFF08\u8BA4\u5F97\u7684\u662F ${RED_REASONS[red.channel].join("/")}\uFF1B${red.message}\uFF09`
8143
+ );
8144
+ }
8145
+ }
8146
+ return [...reds];
8147
+ }
8148
+ function checkGaps(gaps) {
8149
+ for (const gap of gaps) {
8150
+ if (!GAP_REASONS.includes(gap.reason)) {
8151
+ throw new Error(
8152
+ `\u7F3A\u53E3\u53F0\u8D26\u7684 reason \u53EA\u6709 ${GAP_REASONS.join("/")} \u4E24\u4E2A\u53D6\u503C\uFF0C\u62FF\u5230\u7684\u662F ${JSON.stringify(gap.reason)}\uFF08${gap.why}\uFF09`
8153
+ );
8154
+ }
8155
+ }
8156
+ return [...gaps];
8157
+ }
8158
+ function checkPremise(problems) {
8159
+ for (const problem of problems) {
8160
+ if (!PREMISE_REASONS.includes(problem.reason)) {
8161
+ throw new Error(
8162
+ `\u524D\u63D0\u7EA7\u53F0\u8D26\u7684 reason \u4E0D\u5728\u53D6\u503C\u57DF\u91CC\uFF1A${JSON.stringify(problem.reason)}\uFF08${problem.message}\uFF09`
8163
+ );
8164
+ }
8165
+ }
8166
+ return [...problems];
8167
+ }
8168
+ function baselineRoundPremise(round) {
8169
+ const state = round && typeof round === "object" ? round.state : void 0;
8170
+ if (state === "complete") return [];
8171
+ return [
8172
+ {
8173
+ reason: REASON_BASELINE_ROUND_NOT_COMPLETE,
8174
+ message: `\u8FD9\u4EFD\u57FA\u7EBF\u7684\u8F6E\u6B21\u72B6\u6001\u662F ${JSON.stringify(state)}\uFF08\u4E0D\u662F complete\uFF09\u21D2 A \u7C7B\u4E8B\u5B9E\u662F\u4ECE**\u6DF7\u7740\u4E0D\u540C\u8F6E\u6B21 / \u5224\u4E0D\u4E86\u8F6E\u6B21**\u7684\u4EA7\u7269\u91CC\u73B0\u7B97\u7684\uFF0C\u300C\u5224\u7EA2 0 \u6761\u300D\u5BF9\u54EA\u4E00\u8F6E\u90FD\u4E0D\u7B97\u6570\u3002\u5148\u8DD1 \`hcm delivery recon round\` \u770B\u662F\u54EA\u51E0\u4EFD\uFF0C\u6216\u91CD\u8DD1\u4E00\u6B21 \`hcm delivery recon\`\u3002\u26A0\uFE0F **\`hcm delivery recon\` \u8981\u8FDE\u5BA2\u6237\u5185\u7F51\u7684 HCM** \u2014\u2014 \u62FF\u4E0D\u5230\u7F51\u7684\u673A\u5668\u4E0A\u8FD9\u6761\u51FA\u8DEF\u8D70\u4E0D\u901A\uFF0C\u6B64\u65F6**\u522B\u628A\u8FD9\u4EFD\u57FA\u7EBF\u5F53 complete \u7528**\uFF0C\u628A\u5B83\u5E26\u56DE\u8FDE\u5F97\u4E0A\u7684\u5730\u65B9\u91CD\u722C`
8175
+ }
8176
+ ];
8177
+ }
8178
+ function inGap(token2) {
8179
+ return [...token2].length <= 1 || /^\p{Nd}+$/u.test(token2);
8180
+ }
8181
+ function allMatches(regex, line) {
8182
+ const out = [];
8183
+ const re = new RegExp(regex.source, regex.flags.includes("g") ? regex.flags : `${regex.flags}g`);
8184
+ let m;
8185
+ while ((m = re.exec(line)) !== null) {
8186
+ if (m[0] === "") {
8187
+ re.lastIndex += 1;
8188
+ continue;
8189
+ }
8190
+ out.push(m);
8191
+ }
8192
+ return out;
8193
+ }
8194
+ function overlaps(span, spans) {
8195
+ return spans.some(([s, e]) => span[0] < e && s < span[1]);
8196
+ }
8197
+ function endpointsIn(line) {
8198
+ const out = [];
8199
+ for (const regex of [URL_ENDPOINT_RE, HOSTLESS_ENDPOINT_RE]) {
8200
+ for (const m of allMatches(regex, line)) {
8201
+ const span = [m.index, m.index + m[0].length];
8202
+ if (!overlaps(
8203
+ span,
8204
+ out.map(([, s]) => s)
8205
+ )) {
8206
+ out.push([m[1], span]);
8207
+ }
8208
+ }
8209
+ }
8210
+ for (const m of allMatches(BARE_ENDPOINT_RE, line)) {
8211
+ const span = [m.index, m.index + m[0].length];
8212
+ if (!overlaps(
8213
+ span,
8214
+ out.map(([, s]) => s)
8215
+ )) {
8216
+ out.push([m[0], span]);
8217
+ }
8218
+ }
8219
+ return out;
8220
+ }
8221
+ function normalize(token2) {
8222
+ return token2.replace(PLACEHOLDER_RE2, "{}");
8223
+ }
8224
+ function factsIndex(facts) {
8225
+ return facts.map((token2) => segmentsOf(normalize(token2)));
8226
+ }
8227
+ function covered(token2, index) {
8228
+ const segments = segmentsOf(normalize(token2));
8229
+ return index.some(
8230
+ (template) => template.length === segments.length && template.every((t, i) => t === "{}" || t === segments[i])
8231
+ );
8232
+ }
8233
+ var SEGMENT_SEPARATOR = "/";
8234
+ function segmentsOf(token2) {
8235
+ return token2.split(SEGMENT_SEPARATOR);
8236
+ }
8237
+ function artifactReason(token2) {
8238
+ const segments = segmentsOf(token2);
8239
+ const head = segments.slice(0, -1);
8240
+ const last = segments[segments.length - 1] ?? "";
8241
+ if (head.includes(ARTIFACT_ROOT)) return REASON_PRODUCT_TREE_PATH;
8242
+ for (let i = 0; i < head.length; i += 1) {
8243
+ if (head[i] === RECON_DIRNAME && segments.length - i - 1 > RECON_SEGMENTS_BELOW_ROOT) {
8244
+ return REASON_PRODUCT_TREE_PATH;
8245
+ }
8246
+ }
8247
+ if (segments.length === 2 && PRODUCT_RELATIVE_SHAPES.some(
8248
+ ([subdir, suffix]) => segments[0] === subdir && last.endsWith(suffix)
8249
+ )) {
8250
+ return REASON_PRODUCT_RELATIVE_PATH;
8251
+ }
8252
+ if (ARTIFACT_SUFFIXES.some((suffix) => last.endsWith(suffix))) return REASON_PRODUCT_FILE_NAME;
8253
+ return null;
8254
+ }
8255
+ var CJK_RANGES = [
8256
+ [13312, 19903],
8257
+ [19968, 40959],
8258
+ [63744, 64255]
8259
+ ];
8260
+ function isCjk(char) {
8261
+ const code = char?.codePointAt(0);
8262
+ return code !== void 0 && CJK_RANGES.some(([low, high]) => code >= low && code <= high);
8263
+ }
8264
+ function boundedFind(line, token2) {
8265
+ let start = line.indexOf(token2);
8266
+ while (start >= 0) {
8267
+ const end = start + token2.length;
8268
+ const leftOk = start === 0 || !(isWordChar(token2[0]) && isWordChar(line[start - 1]));
8269
+ const rightOk = end >= line.length || !(isWordChar(token2[token2.length - 1]) && isWordChar(line[end]));
8270
+ if (leftOk && rightOk) return start;
8271
+ start = line.indexOf(token2, start + 1);
8272
+ }
8273
+ return -1;
8274
+ }
8275
+ function cjkRunAt(line, start, token2) {
8276
+ const end = start + token2.length;
8277
+ if (isCjk(token2[0]) && start > 0 && isCjk(line[start - 1])) return true;
8278
+ return isCjk(token2[token2.length - 1]) && end < line.length && isCjk(line[end]);
8279
+ }
8280
+ var Matcher = class {
8281
+ owners;
8282
+ simple;
8283
+ byFirst;
8284
+ constructor(aclass) {
8285
+ this.owners = /* @__PURE__ */ new Map();
8286
+ for (const kind of ACLASS_KINDS) {
8287
+ for (const token2 of [...aclass[kind] ?? []].sort()) {
8288
+ const owned = this.owners.get(token2);
8289
+ if (owned) owned.push(kind);
8290
+ else this.owners.set(token2, [kind]);
8291
+ }
8292
+ }
8293
+ this.simple = new Set([...this.owners.keys()].filter((t) => SIMPLE_TOKEN.test(t)));
8294
+ this.byFirst = /* @__PURE__ */ new Map();
8295
+ for (const token2 of this.owners.keys()) {
8296
+ if (this.simple.has(token2)) continue;
8297
+ const first = token2[0];
8298
+ if (first === void 0) continue;
8299
+ const bucket = this.byFirst.get(first);
8300
+ if (bucket) bucket.push(token2);
8301
+ else this.byFirst.set(first, [token2]);
8302
+ }
8303
+ }
8304
+ /**
8305
+ * → 这一行命中的 `[(token, **有边界的**那一处的位置)]`,同一 token 一行只报一次。
8306
+ *
8307
+ * 🔴 **位置必须来自 `boundedFind`,不许再算一遍 `indexOf`**。起手那版用 `boundedFind`
8308
+ * 确认「这一行**存在**一处合法边界命中」,返回的却是第一处裸子串 —— 可能根本不是那一处。
8309
+ * 下游把这个位置交给 `cjkRunAt` 做分桶,于是**在同一行前面加一处诱饵写法就能把一条
8310
+ * 真红压掉**。辖区 = 首/末字符为 CJK、另一端为词字符的**混合形态** token;纯 ASCII 与
8311
+ * 纯 CJK 两个位置必然相等,所以此前每一项变异都照不到它。
8312
+ * 「存在一处合法命中」是「这一处合法」的**必要条件**,不是充分条件。
8313
+ *
8314
+ * 🔴 **`sort` 不是洁癖,它是这份输出的确定性本身**:按插入序遍历会让非纯词形 token 的
8315
+ * 先后随输入变化,集合、rc、判词全都一样,只有顺序变 —— 那正是「静默」的定义,
8316
+ * 而它坏的是**验证仪器**:任何「前后两版输出逐字相等」的复核都会假红。
8317
+ */
8318
+ hits(line) {
8319
+ const seen = /* @__PURE__ */ new Set();
8320
+ const result = [];
8321
+ for (const m of allMatches(WORD_RE, line)) {
8322
+ const token2 = m[0];
8323
+ if (token2 !== void 0 && this.simple.has(token2) && !seen.has(token2)) {
8324
+ seen.add(token2);
8325
+ result.push([token2, boundedFind(line, token2)]);
8326
+ }
8327
+ }
8328
+ for (const char of [.../* @__PURE__ */ new Set([...line])].sort()) {
8329
+ for (const token2 of this.byFirst.get(char) ?? []) {
8330
+ if (seen.has(token2)) continue;
8331
+ const start = boundedFind(line, token2);
8332
+ if (start >= 0) {
8333
+ seen.add(token2);
8334
+ result.push([token2, start]);
8335
+ }
8336
+ }
8337
+ }
8338
+ return result;
8339
+ }
8340
+ };
8341
+ function classReasons(problems) {
8342
+ const out = /* @__PURE__ */ new Map();
8343
+ for (const problem of problems ?? []) {
8344
+ if (problem.scope === CLASS_SCOPE) {
8345
+ for (const kind of problem.kinds) out.set(kind, problem.reason);
8346
+ }
8347
+ }
8348
+ return out;
8349
+ }
8350
+ var INVISIBLE_RE = /\p{Cf}/u;
8351
+ var FULLWIDTH_ALNUM_RANGES = [
8352
+ [65296, 65305, 65296 - 48],
8353
+ [65313, 65338, 65313 - 65],
8354
+ [65345, 65370, 65345 - 97]
8355
+ ];
8356
+ var FOLDED_NOTE = "\uFF1B\u26A0\uFE0F \u8FD9\u4E00\u5904\u662F**\u5F52\u4E00\u4E4B\u540E**\u624D\u8BA4\u51FA\u6765\u7684\uFF1A\u539F\u6587\u91CC\u5939\u4E86\u4E0D\u53EF\u89C1\u5B57\u7B26\u6216\u5168\u89D2\u5B57\u7B26\uFF0C\u76F4\u63A5\u6309\u4E0A\u9762\u8FD9\u4E2A\u8BCD\u53BB grep \u4F1A\u641C\u4E0D\u5230";
8357
+ var foldedOriginal = (literal) => `\uFF0C\u539F\u6587\u91CC\u90A3\u4E00\u6BB5\u662F ${JSON.stringify(literal)}`;
8358
+ function foldWithMap(line) {
8359
+ const out = [];
8360
+ const origin = [];
8361
+ for (let i = 0; i < line.length; i += 1) {
8362
+ const char = line[i];
8363
+ if (INVISIBLE_RE.test(char)) continue;
8364
+ const code = char.charCodeAt(0);
8365
+ let folded = char;
8366
+ for (const [low, high, offset] of FULLWIDTH_ALNUM_RANGES) {
8367
+ if (code >= low && code <= high) {
8368
+ folded = String.fromCharCode(code - offset);
8369
+ break;
8370
+ }
8371
+ }
8372
+ out.push(folded);
8373
+ origin.push(i);
8374
+ }
8375
+ return [out.join(""), origin];
8376
+ }
8377
+ function foldConfusables(line) {
8378
+ return foldWithMap(line)[0];
8379
+ }
8380
+ function foldedNoteFor(original, folded, token2) {
8381
+ if (original.includes(token2)) return "";
8382
+ let start = boundedFind(folded, token2);
8383
+ if (start < 0) start = folded.indexOf(token2);
8384
+ if (start < 0) {
8385
+ return FOLDED_NOTE;
8386
+ }
8387
+ const [, origin] = foldWithMap(original);
8388
+ const from = origin[start];
8389
+ const to = origin[start + token2.length - 1];
8390
+ if (from === void 0 || to === void 0) return FOLDED_NOTE;
8391
+ return FOLDED_NOTE + foldedOriginal(original.slice(from, to + 1));
8392
+ }
8393
+ function judgeLine(line, lineno, rel, matcher, index, reds, gaps) {
8394
+ const folded = foldConfusables(line);
8395
+ const lineReds = [];
8396
+ const lineGaps = [];
8397
+ judgePass(line, lineno, rel, matcher, index, lineReds, lineGaps);
8398
+ if (folded !== line) judgePass(folded, lineno, rel, matcher, index, lineReds, lineGaps);
8399
+ const seen = /* @__PURE__ */ new Set();
8400
+ const unique2 = [];
8401
+ for (const red of lineReds) {
8402
+ const key = `${red.channel} ${red.token}`;
8403
+ if (seen.has(key)) continue;
8404
+ seen.add(key);
8405
+ unique2.push({ ...red, message: red.message + foldedNoteFor(line, folded, red.token) });
8406
+ }
8407
+ reds.push(...unique2);
8408
+ const redTokens = new Set(unique2.filter((r) => r.channel === CHANNEL_ACLASS).map((r) => r.token));
8409
+ const seenGaps = /* @__PURE__ */ new Set();
8410
+ for (const gap of lineGaps) {
8411
+ const key = `${gap.reason} ${gap.token}`;
8412
+ if (seenGaps.has(key) || folded !== line && redTokens.has(gap.token)) continue;
8413
+ seenGaps.add(key);
8414
+ gaps.push({ ...gap, why: gap.why + foldedNoteFor(line, folded, gap.token) });
8415
+ }
8416
+ }
8417
+ function judgePass(line, lineno, rel, matcher, index, reds, gaps) {
8418
+ for (const [token2, start] of matcher.hits(line)) {
8419
+ const kinds = matcher.owners.get(token2) ?? [];
8420
+ if (inGap(token2)) {
8421
+ gaps.push({
8422
+ reason: GAP_NOISE_TOKEN,
8423
+ token: token2,
8424
+ kinds,
8425
+ path: rel,
8426
+ line: lineno,
8427
+ why: `${rel}:${lineno} \u7EAF\u6570\u5B57 / \u5355\u5B57\u7B26 ${JSON.stringify(token2)} \u2014\u2014 \u5224\u7EA2\u8FD9\u4E00\u5C42**\u58F0\u660E\u7684\u7F3A\u53E3**\uFF0C\u67E5\u8FC7\u3001\u6309\u7F3A\u53E3\u653E\u884C`
8428
+ });
8429
+ continue;
8430
+ }
8431
+ if (cjkRunAt(line, start, token2)) {
8432
+ gaps.push({
8433
+ reason: GAP_CJK_INSIDE_LONGER_RUN,
8434
+ token: token2,
8435
+ kinds,
8436
+ path: rel,
8437
+ line: lineno,
8438
+ why: `${rel}:${lineno} ${JSON.stringify(token2)}\uFF08A \u7C7B ${kinds.join("/")}\uFF09\u843D\u5728\u4E00\u4E32\u66F4\u957F\u7684\u4E2D\u6587\u91CC \u2014\u2014 \u4E2D\u6587\u6CA1\u6709\u5206\u8BCD\u8FB9\u754C\uFF0C**\u8BF4\u4E0D\u51C6**\u5B83\u662F\u4E0D\u662F\u90A3\u4E2A\u53D6\u503C\uFF1B\u4E0D\u9876 rc\uFF0C\u8BF7\u81EA\u5DF1\u770B\u4E00\u773C`
8439
+ });
8440
+ continue;
8441
+ }
8442
+ reds.push({
8443
+ channel: CHANNEL_ACLASS,
8444
+ reason: REASON_ENVIRONMENT_FACT,
8445
+ token: token2,
8446
+ path: rel,
8447
+ line: lineno,
8448
+ kinds,
8449
+ message: `${rel}:${lineno} \u51FA\u73B0\u73AF\u5883\u4E8B\u5B9E ${JSON.stringify(token2)}\uFF08A \u7C7B ${kinds.join("/")}\uFF09\u2014\u2014 \u6362\u4E2A\u5BA2\u6237\u5C31\u5168\u9519\uFF0C**\u65E0\u8C41\u514D**`
8450
+ });
8451
+ }
8452
+ const spans = [];
8453
+ for (const [token2, span] of endpointsIn(line)) {
8454
+ spans.push(span);
8455
+ judgeProtocol(token2, REASON_ENDPOINT, "\u7AEF\u70B9", lineno, rel, matcher, index, reds);
8456
+ }
8457
+ for (const regex of [PATHISH_RE, PRODUCT_FILE_RE]) {
8458
+ for (const m of allMatches(regex, line)) {
8459
+ const span = [m.index, m.index + m[0].length];
8460
+ if (overlaps(span, spans)) continue;
8461
+ const token2 = m[0];
8462
+ const reason = artifactReason(token2);
8463
+ if (reason === null) continue;
8464
+ spans.push(span);
8465
+ reds.push({
8466
+ channel: CHANNEL_ARTIFACT,
8467
+ reason,
8468
+ token: token2,
8469
+ path: rel,
8470
+ line: lineno,
8471
+ kinds: [],
8472
+ message: `${rel}:${lineno} ${artifactWordingFor(reason)(token2)} \u2014\u2014 \u4EA7\u7269\u8DEF\u5F84**\u65E0\u8C41\u514D**\uFF0C\u767B\u8BB0\u518C\u4E0D\u53D7\u7406\u5B83\uFF1Bskill \u6B63\u6587\u8BE5\u8BF4\u7684\u662F\u8DD1\u54EA\u6761\u547D\u4EE4\uFF0C\u4E0D\u662F\u53BB\u8BFB\u54EA\u4E2A\u6587\u4EF6`
8473
+ });
8474
+ }
8475
+ }
8476
+ for (const m of allMatches(ERROR_CODE_RE, line)) {
8477
+ const span = [m.index, m.index + m[0].length];
8478
+ if (overlaps(span, spans)) continue;
8479
+ spans.push(span);
8480
+ judgeProtocol(m[0], REASON_ERROR_CODE, "\u9519\u8BEF\u7801", lineno, rel, matcher, index, reds);
8481
+ }
8482
+ }
8483
+ function judgeProtocol(token2, reason, shape, lineno, rel, matcher, index, reds) {
8484
+ if (matcher.owners.has(token2)) return;
8485
+ if (covered(token2, index)) return;
8486
+ reds.push({
8487
+ channel: CHANNEL_UNREGISTERED,
8488
+ reason,
8489
+ token: token2,
8490
+ path: rel,
8491
+ line: lineno,
8492
+ kinds: [],
8493
+ message: `${rel}:${lineno} \u51FA\u73B0${shape} ${JSON.stringify(token2)}\uFF0C\u800C\u5B83**\u6CA1\u6709\u767B\u8BB0**\u5728\u968F\u5305\u7684\u534F\u8BAE\u4E8B\u5B9E\u767B\u8BB0\u518C\u91CC \u21D2 \u8981\u4E48\u6539\u5199\u6210\u4E0D\u4F9D\u8D56\u5B83\u7684\u8BF4\u6CD5\uFF0C\u8981\u4E48\u7ED9 CLI \u63D0\u4E00\u6761\u767B\u8BB0\uFF08\u767B\u8BB0\u5FC5\u987B\u9644\u4E00\u4E2A\u65AD\u884C\u4E3A\u7684\u63A2\u9488\uFF09`
8494
+ });
8495
+ }
8496
+ function scan(skillRoot, aclass, facts, options = {}) {
8497
+ const reds = [];
8498
+ const premise = [];
8499
+ const gaps = [];
8500
+ const scanned = [];
8501
+ const matcher = new Matcher(aclass);
8502
+ const index = factsIndex(facts);
8503
+ const reasons = classReasons(options.aclassProblems);
8504
+ for (const kind of ACLASS_KINDS) {
8505
+ if ((aclass[kind]?.size ?? 0) > 0) continue;
8506
+ const reason = reasons.get(kind);
8507
+ let why = "";
8508
+ if (reason !== void 0) {
8509
+ if (!(reason in ACLASS_EMPTY_WHY)) {
8510
+ throw new Error(
8511
+ `\u7C7B\u7EA7\u6210\u56E0 ${JSON.stringify(reason)} \u6CA1\u6709\u5BF9\u5E94\u7684\u63AA\u8F9E\uFF08\u8BA4\u5F97\u7684\u662F ${CLASS_REASONS.join("/")}\uFF09`
8512
+ );
8513
+ }
8514
+ why = ACLASS_EMPTY_WHY[reason];
8515
+ }
8516
+ premise.push({
8517
+ reason: REASON_ACLASS_EMPTY,
8518
+ message: `A \u7C7B\u5B50\u96C6 ${kind} \u662F\u7A7A\u7684${why} \u21D2 \u95E8 0 \u5BF9\u8FD9\u4E00\u7C7B**\u6052\u7EFF**\uFF0C\u8FD9\u4E00\u8F6E\u7684\u7EFF\u4E0D\u7B97\u6570`
8519
+ });
8520
+ }
8521
+ for (const problem of options.aclassProblems ?? []) {
8522
+ if (problem.scope !== ENTRY_SCOPE) continue;
8523
+ premise.push({
8524
+ reason: REASON_ACLASS_PARTIALLY_UNREAD,
8525
+ message: `A \u7C7B\u5B50\u96C6 ${problem.kinds.join("/")} \u5C11\u4E86\u4E00\u90E8\u5206\uFF08${problem.reason}\uFF09\uFF1A${problem.message} \u21D2 \u5C11\u6389\u7684\u90A3\u90E8\u5206\u95E8 0 \u5224\u4E0D\u51FA\u6765\uFF0C\u8FD9\u4E00\u8F6E\u7684\u7EFF\u4E0D\u7B97\u6570`
8526
+ });
8527
+ }
8528
+ let factsProblems = options.factsProblems;
8529
+ if (factsProblems === void 0) {
8530
+ premise.push({
8531
+ reason: REASON_CHANNEL_FOUR_UNCHECKED,
8532
+ message: "\u6CA1\u6709\u628A loadProtocolFacts \u7684\u53F0\u8D26\u4F20\u8FDB\u6765 \u21D2 \u901A\u9053\u56DB\uFF08\u767B\u8BB0\u9879\u88AB\u62D2\uFF09\u4E00\u6761\u90FD\u6CA1\u67E5\u8FC7\u2014\u2014\u300C\u767B\u8BB0\u518C\u5E72\u51C0\u300D\u4E0E\u300C\u6CA1\u67E5\u767B\u8BB0\u518C\u300D\u5728\u8FD4\u56DE\u503C\u4E0A\u540C\u5F62"
8533
+ });
8534
+ factsProblems = [];
8535
+ }
8536
+ for (const problem of factsProblems) {
8537
+ if (problem.scope === REGISTRY_SCOPE && PREMISE_REGISTRY_REASONS.includes(problem.reason)) {
8538
+ premise.push({
8539
+ reason: REASON_REGISTRY,
8540
+ message: `\u767B\u8BB0\u518C\u8FD9\u4E00\u5C42\u6CA1\u7ACB\u4F4F\uFF08${problem.reason}\uFF09\uFF1A${problem.message} \u21D2 \u8C41\u514D\u901A\u9053 P \u4E0D\u53EF\u4FE1`
8541
+ });
8542
+ }
8543
+ }
8544
+ for (const problem of factsProblems) {
8545
+ if (problem.scope === REGISTRY_SCOPE) continue;
8546
+ reds.push({
8547
+ channel: CHANNEL_NO_PROBE,
8548
+ reason: REASON_REJECTED_REGISTRATION,
8549
+ token: problem.token ?? `(\u7B2C${problem.index}\u6761)`,
8550
+ path: null,
8551
+ line: 0,
8552
+ kinds: [],
8553
+ message: `\u767B\u8BB0\u518C\u7B2C ${problem.index} \u6761\u88AB\u62D2\uFF08${problem.reason}\uFF09\uFF1A${problem.message}`
8554
+ });
8555
+ }
8556
+ for (const token2 of [...facts].sort()) {
8557
+ const kinds = matcher.owners.get(token2);
8558
+ if (!kinds) continue;
8559
+ reds.push({
8560
+ channel: CHANNEL_REGISTERED_IS_ACLASS,
8561
+ reason: REASON_REGISTERED_IS_ACLASS,
8562
+ token: token2,
8563
+ path: null,
8564
+ line: 0,
8565
+ kinds,
8566
+ message: `\u767B\u8BB0\u518C\u767B\u8BB0\u4E86 ${JSON.stringify(token2)}\uFF0C\u800C\u5B83\u662F A \u7C7B\u73AF\u5883\u4E8B\u5B9E\uFF08${kinds.join("/")}\uFF09\u2014\u2014 recon \u67E5\u5F97\u5230\u7684\u4E1C\u897F\u4E0D\u662F\u7248\u672C\u7EA7\u534F\u8BAE\uFF0C\u767B\u8BB0\u5B83\u4E70\u4E0D\u5230\u4EFB\u4F55\u8C41\u514D`
8567
+ });
8568
+ }
8569
+ let files = [];
8570
+ if (!isDirectory(skillRoot)) {
8571
+ premise.push({
8572
+ reason: REASON_NO_SKILL_ROOT,
8573
+ message: `\u626B\u63CF\u9762 ${skillRoot} \u4E0D\u662F\u4E00\u4E2A\u76EE\u5F55 \u21D2 \u4E00\u4E2A\u5B57\u90FD\u6CA1\u626B\u8FC7\uFF08\u8FD9\u4E0D\u662F\u300C\u626B\u8FC7\u3001\u5E72\u51C0\u300D\uFF09`
8574
+ });
8575
+ } else {
8576
+ const walked = walk2(skillRoot);
8577
+ files = walked.files;
8578
+ for (const link of walked.unscannedLinks) {
8579
+ let target;
8580
+ try {
8581
+ target = readlinkSync(link);
8582
+ } catch {
8583
+ target = "(\u8BFB\u4E0D\u51FA\u94FE\u63A5\u76EE\u6807)";
8584
+ }
8585
+ premise.push({
8586
+ reason: REASON_SYMLINK_NOT_SCANNED,
8587
+ message: `${path11.relative(skillRoot, link)} \u662F\u4E00\u4E2A\u7B26\u53F7\u94FE\u63A5\uFF08\u6307\u5411 ${JSON.stringify(target)}\uFF09\u21D2 \u95E8 0 **\u6CA1\u6709\u987A\u7740\u5B83\u626B\u8FC7\u4E00\u4E2A\u5B57**\uFF0C\u8FD9\u4E00\u8F6E\u7684\u7EFF\u4E0D\u7B97\u6570\u3002\u51FA\u8DEF\uFF1A\u628A\u8FD9\u6761\u94FE\u4ECE skill \u91CC\u53BB\u6389 \u2014\u2014 \u94FE\u540E\u9762\u90A3\u4EFD\u5185\u5BB9\u672C\u8BE5\u88AB\u5224\u5C31 \`cp -RL\` \u62F7\u6210\u771F\u5185\u5BB9\uFF08\u26A0\uFE0F \u73AF\u8DEF\u4E0E\u65AD\u94FE\u4E0A\u5B83\u4F1A\u5F53\u573A\u62A5\u9519\uFF0C\u90A3\u4E24\u79CD\u76F4\u63A5\u5220\uFF09\uFF1B\u5185\u5BB9\u5DF2\u7ECF\u5728 skill \u91CC\uFF08\u6307\u5411\u540C\u6811\u7684\u522B\u540D\uFF09\u4E5F\u76F4\u63A5\u5220\u3002**\u4E0D\u8DDF\u968F**\u662F\u523B\u610F\u7684 \u2014\u2014 \u8DDF\u8FC7\u53BB\u4F1A\u8FDE\u4E0A\u73AF\u8DEF\u3001\u6216\u8D8A\u51FA skill \u76EE\u5F55\u626B\u5230\u65E0\u5173\u6587\u4EF6`
8588
+ });
8589
+ }
8590
+ if (files.length === 0) {
8591
+ premise.push({
8592
+ reason: REASON_NOTHING_SCANNED,
8593
+ message: `\u626B\u63CF\u9762 ${skillRoot} \u5728\u76D8\u4E0A\uFF0C\u4F46\u91CC\u9762\u4E00\u4E2A\u6587\u4EF6\u90FD\u6CA1\u6709 \u2014\u2014 \u67E5\u8FC7\u4E14\u4E3A\u7A7A`
8594
+ });
8595
+ }
8596
+ }
8597
+ for (const file of files) {
8598
+ let text;
8599
+ try {
8600
+ text = readFileSync7(file, "utf8");
8601
+ } catch (e) {
8602
+ premise.push({
8603
+ reason: REASON_FILE_UNREADABLE,
8604
+ message: `${file} \u8BFB\u4E0D\u52A8\uFF08${String(e)}\uFF09\u21D2 \u5224\u4E0D\u4E86\u5B83\u5E72\u4E0D\u5E72\u51C0\uFF0C\u95E8 0 \u4E0D\u80FD\u5BF9\u7740\u5B83\u8BF4\u7EFF`
8605
+ });
8606
+ continue;
8607
+ }
8608
+ const rel = path11.relative(skillRoot, file);
8609
+ scanned.push(rel);
8610
+ text.split("\n").forEach((line, i) => {
8611
+ judgeLine(line, i + 1, rel, matcher, index, reds, gaps);
8612
+ });
8613
+ }
8614
+ const seen = /* @__PURE__ */ new Set();
8615
+ const unique2 = [];
8616
+ for (const red of checkReds(reds)) {
8617
+ const key = `${red.channel} ${red.token} ${red.path} ${red.line}`;
8618
+ if (seen.has(key)) continue;
8619
+ seen.add(key);
8620
+ unique2.push(red);
8621
+ }
8622
+ const channels = Object.fromEntries(
8623
+ CHANNELS.map((name) => [name, unique2.filter((r) => r.channel === name)])
8624
+ );
8625
+ return {
8626
+ red: unique2,
8627
+ channels,
8628
+ scanned,
8629
+ gaps: checkGaps(gaps),
8630
+ premise: checkPremise(premise)
8631
+ };
8632
+ }
8633
+ function isDirectory(target) {
8634
+ try {
8635
+ return statSync3(target).isDirectory();
8636
+ } catch {
8637
+ return false;
8638
+ }
8639
+ }
8640
+ function walk2(root) {
8641
+ const files = [];
8642
+ const unscannedLinks = [];
8643
+ const visit = (dir) => {
8644
+ for (const entry of readdirSync3(dir, { withFileTypes: true })) {
8645
+ const full = path11.join(dir, entry.name);
8646
+ let followed = null;
8647
+ try {
8648
+ followed = statSync3(full);
8649
+ } catch {
8650
+ followed = null;
8651
+ }
8652
+ if (followed?.isFile()) {
8653
+ files.push(full);
8654
+ } else if (entry.isSymbolicLink()) {
8655
+ unscannedLinks.push(full);
8656
+ } else if (followed?.isDirectory()) {
8657
+ visit(full);
8658
+ }
8659
+ }
8660
+ };
8661
+ visit(root);
8662
+ return { files: files.sort(), unscannedLinks: unscannedLinks.sort() };
8663
+ }
8664
+ function exitCode(result) {
8665
+ if (result.premise.length > 0) return 2;
8666
+ if (result.red.length > 0) return 1;
8667
+ return 0;
8668
+ }
7554
8669
  export {
8670
+ ACLASS_EMPTY_WHY,
8671
+ ACLASS_KINDS,
8672
+ ARTIFACT_ROOT,
8673
+ ARTIFACT_SUFFIXES,
8674
+ ARTIFACT_WORDING,
7555
8675
  AUTH_INFO_PATH,
7556
8676
  BLIND_SPOTS,
8677
+ CHANNELS,
8678
+ CHANNEL_ACLASS,
8679
+ CHANNEL_ARTIFACT,
8680
+ CHANNEL_NO_PROBE,
8681
+ CHANNEL_REGISTERED_IS_ACLASS,
8682
+ CHANNEL_UNREGISTERED,
8683
+ CLASS_REASONS,
8684
+ CLASS_SCOPE,
7557
8685
  CliError,
7558
8686
  CliErrorCode,
7559
8687
  DEFAULT_AGENT_ID,
7560
8688
  DEFAULT_SESSION_TTL_SECONDS,
7561
8689
  DOCTOR_ANCHORS,
8690
+ ENDPOINT_PREFIXES,
8691
+ ENTRY_SCOPE,
8692
+ ENUM_ELEMENT_KEYS,
7562
8693
  EXTENSION_SOURCE_HEADER,
7563
8694
  ExitCode,
8695
+ FACTS_REASONS,
8696
+ FOLDED_NOTE,
8697
+ FULLWIDTH_ALNUM_RANGES,
8698
+ GAP_CJK_INSIDE_LONGER_RUN,
8699
+ GAP_NOISE_TOKEN,
8700
+ GAP_REASONS,
7564
8701
  GATE_COMPONENTS,
7565
8702
  HcmClient,
7566
8703
  KIT_CARRY_OVER_KEY,
@@ -7568,6 +8705,7 @@ export {
7568
8705
  LEDGER_MISSING_WORD,
7569
8706
  LayoutContainmentError,
7570
8707
  MANIFEST_PATH,
8708
+ MAPPING_ARTIFACT_VERSION,
7571
8709
  MAX_MANIFEST_PAGES,
7572
8710
  MAX_SOURCE_PROBES,
7573
8711
  META_PATH,
@@ -7578,16 +8716,37 @@ export {
7578
8716
  MINI_REMOTE_ROOT,
7579
8717
  MINI_STATE_DIR,
7580
8718
  MODELS_PATH,
8719
+ MappingArtifactError,
8720
+ Matcher,
7581
8721
  PASSWORD_CHANGE_REQUIRED,
8722
+ PREMISE_REASONS,
8723
+ PREMISE_REGISTRY_REASONS,
7582
8724
  PROACTIVE_REFRESH_MARGIN_SECONDS,
8725
+ PROBE_MARK_PREFIX,
8726
+ PRODUCT_RELATIVE_SHAPES,
7583
8727
  PRODUCT_STATE_WORDS,
8728
+ PROTOCOL_FACTS,
8729
+ REASON_DUPLICATE_TOKEN,
8730
+ REASON_EMPTY,
8731
+ REASON_NO_ENTRIES,
8732
+ REASON_PROBE_ABSENT,
8733
+ REASON_PROBE_SHAPE,
8734
+ REASON_PROBE_UNVERIFIED,
8735
+ REASON_UNREAD,
8736
+ RECON_DIRNAME,
8737
+ RECON_SEGMENTS_BELOW_ROOT,
8738
+ RED_REASONS,
8739
+ REGISTRY_REASONS,
8740
+ REGISTRY_SCOPE,
7584
8741
  ROUND_EXIT_CODES,
7585
8742
  ROUND_STAMPED_PRODUCTS,
7586
8743
  ROUND_STATES,
7587
8744
  ROUND_SUBCOMMAND,
7588
8745
  ReconLayout,
7589
8746
  RefStore,
8747
+ SCOPES,
7590
8748
  SDK_VERSION,
8749
+ SEGMENT_SEPARATOR,
7591
8750
  TargetModelNotFound,
7592
8751
  TokenStore,
7593
8752
  VERSION_PATH,
@@ -7595,10 +8754,13 @@ export {
7595
8754
  absoluteDownloadUrl,
7596
8755
  adminResetPassword,
7597
8756
  archiveDir,
8757
+ artifactReason,
7598
8758
  assertSafeReferencePath,
7599
8759
  assertSafeSkillFilePath,
7600
8760
  assertSafeSkillId,
8761
+ baselineRoundPremise,
7601
8762
  bootstrapTenant,
8763
+ boundedFind,
7602
8764
  buildAnswer,
7603
8765
  buildConfirm,
7604
8766
  buildInterrupt,
@@ -7610,6 +8772,10 @@ export {
7610
8772
  buildSteer,
7611
8773
  camelizeKeys,
7612
8774
  changePassword,
8775
+ checkGaps,
8776
+ checkPremise,
8777
+ checkReds,
8778
+ cjkRunAt,
7613
8779
  classifyMessage,
7614
8780
  clearMetaCache,
7615
8781
  clearModelCache,
@@ -7617,6 +8783,7 @@ export {
7617
8783
  computeFingerprint,
7618
8784
  computeReconSourceKey,
7619
8785
  conversationStateFile,
8786
+ covered,
7620
8787
  create,
7621
8788
  createConversation,
7622
8789
  createHttpClient,
@@ -7629,6 +8796,7 @@ export {
7629
8796
  deleteIdentity,
7630
8797
  deleteTenantMeta,
7631
8798
  deleteWorkspaceFile,
8799
+ deriveAclass,
7632
8800
  deriveNamelessToolLabel,
7633
8801
  describePrincipal,
7634
8802
  detectDelegationPause,
@@ -7636,12 +8804,15 @@ export {
7636
8804
  detectPasswordChangeChallenge,
7637
8805
  displayWidth,
7638
8806
  downloadDocument,
8807
+ endpointsIn,
7639
8808
  ensureSessionFresh,
7640
8809
  envDir,
7641
8810
  envFile,
7642
8811
  envsDir,
8812
+ exitCode,
7643
8813
  exitCodeFor,
7644
8814
  extractNextSteps,
8815
+ factsIndex,
7645
8816
  fetchConversationTimeline,
7646
8817
  fetchConversationTimelineStrict,
7647
8818
  fetchRecentConversations,
@@ -7653,6 +8824,8 @@ export {
7653
8824
  filterByStage,
7654
8825
  findLastAssistantSeq,
7655
8826
  flattenSkills,
8827
+ foldConfusables,
8828
+ foldedNoteFor,
7656
8829
  formatMiniVerifyReport,
7657
8830
  formatObject,
7658
8831
  formatRows,
@@ -7668,10 +8841,12 @@ export {
7668
8841
  identitiesDir,
7669
8842
  identityDir,
7670
8843
  identityMetaFile,
8844
+ inGap,
7671
8845
  inferEnvName,
7672
8846
  inferMiniWritableTemplateOptionsFromModel,
7673
8847
  initMiniAppProject,
7674
8848
  inspectRound,
8849
+ isCjk,
7675
8850
  isDelegationToolName,
7676
8851
  isServerSlidingSession,
7677
8852
  listEnvs,
@@ -7684,6 +8859,7 @@ export {
7684
8859
  loadGlobalConfig,
7685
8860
  loadIdentity,
7686
8861
  loadProfile,
8862
+ loadProtocolFacts,
7687
8863
  loadWorkspaceFileContent,
7688
8864
  loginClientCredentials,
7689
8865
  loginPairing,
@@ -7695,6 +8871,7 @@ export {
7695
8871
  modelKeys,
7696
8872
  needsRefresh,
7697
8873
  newRoundId,
8874
+ normalize,
7698
8875
  normalizeReferences,
7699
8876
  oneShot,
7700
8877
  parseConfirmToolName,
@@ -7711,6 +8888,7 @@ export {
7711
8888
  profileFile,
7712
8889
  pullMiniAppProject,
7713
8890
  pushMiniAppProject,
8891
+ readBusinessKeyFields,
7714
8892
  readMiniContext,
7715
8893
  readPullManifest,
7716
8894
  refreshToken,
@@ -7738,6 +8916,8 @@ export {
7738
8916
  saveProfile,
7739
8917
  saveTenantMeta,
7740
8918
  saveWorkspaceFileContent,
8919
+ scan,
8920
+ segmentsOf,
7741
8921
  sendMessageAndStream,
7742
8922
  snakeToCamel,
7743
8923
  tenantSegment,
@@ -7747,6 +8927,7 @@ export {
7747
8927
  toTable,
7748
8928
  toYaml,
7749
8929
  truncateDisplay,
8930
+ unguardedKinds,
7750
8931
  update,
7751
8932
  uploadDocument,
7752
8933
  validateMiniProject