@thinkingai/ae-cli 6.1.17 → 6.1.19

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.
Files changed (126) hide show
  1. package/README.md +2 -0
  2. package/README.zh.md +6 -0
  3. package/dist/{auth-77BUFLGC.js → auth-QPEVVBKT.js} +20 -15
  4. package/dist/auth-UMJAA72O.js +15 -0
  5. package/dist/{capability-72DTW5M2.js → capability-ASI62I4A.js} +53 -15
  6. package/dist/{chunk-UW5UN47B.js → chunk-533JK3YX.js} +2 -0
  7. package/dist/{chunk-UOUS37JQ.js → chunk-6QK7SYYY.js} +5 -4
  8. package/dist/{chunk-TUKQZTMI.js → chunk-7K24F7T2.js} +2 -0
  9. package/dist/{chunk-OO6XR6LK.js → chunk-AMBFK2K3.js} +2 -0
  10. package/dist/{sync-DAVKYVMW.js → chunk-B5HMQAOM.js} +31 -540
  11. package/dist/{chunk-VR3LCBHW.js → chunk-DKEXH6Q5.js} +6 -5
  12. package/dist/{chunk-VTWMIC5L.js → chunk-E2JKXMVO.js} +2 -0
  13. package/dist/{chunk-LYVNONC4.js → chunk-FR2EDAQM.js} +36 -0
  14. package/dist/{chunk-ILIU36SU.js → chunk-GJXRF7Y6.js} +6 -5
  15. package/dist/{chunk-DWO43OIB.js → chunk-JQ3ENZZH.js} +2 -0
  16. package/dist/chunk-JYMGHGCE.js +191 -0
  17. package/dist/{chunk-GT46FPXN.js → chunk-KEWVSO64.js} +18 -8
  18. package/dist/chunk-KZ6ZHF5J.js +294 -0
  19. package/dist/chunk-O6K2ODUE.js +318 -0
  20. package/dist/chunk-QL6R6TSK.js +25215 -0
  21. package/dist/{chunk-4SGZG4XY.js → chunk-RWXIXOZG.js} +28 -13
  22. package/dist/{chunk-YA6SMTXG.js → chunk-S5PONFBM.js} +5 -4
  23. package/dist/{chunk-4NN5IWVN.js → chunk-T6OSFQZD.js} +2 -0
  24. package/dist/{chunk-PTE56QPL.js → chunk-TKHSULJT.js} +6 -0
  25. package/dist/{chunk-6EIJSNBD.js → chunk-Y74WTIKJ.js} +2 -0
  26. package/dist/{client-TKG4WBHN.js → client-N7NGZUNI.js} +6 -4
  27. package/dist/{community-report-client-FI4LNVYS.js → community-report-client-6OL6GBQW.js} +3 -3
  28. package/dist/{config-RE6CMGPK.js → config-XNMACCKX.js} +10 -8
  29. package/dist/{data-integration-XQYB4X4F.js → data-integration-4NZGZ45E.js} +2502 -272
  30. package/dist/index.js +137 -1245
  31. package/dist/{local-data-upload-client-BWHSUQQK.js → local-data-upload-client-EFHDLXFG.js} +3 -3
  32. package/dist/{memory-YK33G4T7.js → memory-HBJQ2GC5.js} +8 -7
  33. package/dist/{metadata-UILXHBWF.js → metadata-62EWBEIG.js} +12 -11
  34. package/dist/{model-NR3JHFSJ.js → model-BHLJ2QMT.js} +10 -9
  35. package/dist/personal-semantic-preference-JBVMAI7L.js +240 -0
  36. package/dist/project-semantic-BQ4MPUS5.js +1115 -0
  37. package/dist/sync-MUWPRM5I.js +522 -0
  38. package/dist/{te-agent-4BKBODMF.js → te-agent-WQZTMEK4.js} +12 -10
  39. package/dist/{te-analysis-O6DCO6BS.js → te-analysis-MNCG65LU.js} +534 -48
  40. package/dist/{te-community-HLC43QKH.js → te-community-BNE6KREL.js} +8 -7
  41. package/dist/{te-dataops-EJP56W3K.js → te-dataops-TXLKM2W6.js} +469 -68
  42. package/dist/{te-engage-FGBGQ4IY.js → te-engage-TPKLRVTL.js} +84 -10
  43. package/dist/{te-experiment-SO5MPDMJ.js → te-experiment-6BYKTCY7.js} +303 -12
  44. package/dist/{te-kb-SQCLHG6X.js → te-kb-BUD6N3NI.js} +312 -25
  45. package/dist/{te-system-YARIK4S5.js → te-system-44LZJDTQ.js} +573 -37
  46. package/dist/{te-team-EFKWYKMK.js → te-team-XMP47YXE.js} +10 -7
  47. package/dist/{update-OGPSZM5A.js → update-UODFOZ4P.js} +9 -7
  48. package/package.json +18 -9
  49. package/skills/ae-agent/SKILL.md +3 -4
  50. package/skills/ae-agent/references/edit-skill.md +3 -0
  51. package/skills/ae-agent/references/get-skill-content.md +1 -1
  52. package/skills/ae-agent/references/rescan-skills.md +15 -13
  53. package/skills/ae-agent/references/upload-skill.md +7 -4
  54. package/skills/ae-analysis/SKILL.md +45 -4
  55. package/skills/ae-analysis/metadata_resolution.md +38 -4
  56. package/skills/ae-analysis/references/analysis_data_retrieval.md +29 -0
  57. package/skills/ae-analysis/references/analysis_gateway_assets.md +1 -1
  58. package/skills/ae-analysis/references/asset_authentication_export.md +22 -0
  59. package/skills/ae-analysis/references/asset_authentication_list.md +18 -14
  60. package/skills/ae-analysis/references/asset_authentication_update.md +29 -14
  61. package/skills/ae-analysis/references/audience_models.md +18 -0
  62. package/skills/ae-analysis/references/command_index.md +19 -11
  63. package/skills/ae-analysis/references/dashboard_get.md +18 -1
  64. package/skills/ae-analysis/references/dashboard_update.md +3 -0
  65. package/skills/ae-analysis/references/personal_semantic_preference_add.md +23 -0
  66. package/skills/ae-analysis/references/personal_semantic_preference_delete.md +17 -0
  67. package/skills/ae-analysis/references/personal_semantic_preference_get.md +19 -0
  68. package/skills/ae-analysis/references/personal_semantic_preference_list.md +21 -0
  69. package/skills/ae-analysis/references/personal_semantic_preference_update.md +19 -0
  70. package/skills/ae-analysis/references/project_timezone_update.md +13 -4
  71. package/skills/ae-analysis/references/property_create.md +2 -0
  72. package/skills/ae-analysis/references/super_metadata_batch_create.md +2 -0
  73. package/skills/ae-analysis/references/user_cluster_models.md +2 -0
  74. package/skills/ae-analysis/references/user_cluster_update.md +8 -4
  75. package/skills/ae-analysis/references/user_tag_create.md +7 -1
  76. package/skills/ae-analysis/references/user_tag_models.md +8 -2
  77. package/skills/ae-data-integration/SKILL.md +24 -4
  78. package/skills/ae-data-integration/references/custom-layer.md +93 -0
  79. package/skills/ae-data-integration/references/error-handling.md +145 -0
  80. package/skills/ae-data-integration/references/handoff.md +77 -18
  81. package/skills/ae-data-integration/references/local-analysis.md +1 -1
  82. package/skills/ae-data-integration/references/reuse.md +9 -5
  83. package/skills/ae-data-integration/references/sink-upload.md +1 -1
  84. package/skills/ae-data-integration/references/source-inspect.md +35 -13
  85. package/skills/ae-data-integration/references/tracking-plan.md +7 -5
  86. package/skills/ae-data-integration/references/transform.md +12 -10
  87. package/skills/ae-data-integration/references/ue-mapping.md +33 -11
  88. package/skills/ae-data-integration/references/ue-routing.md +23 -0
  89. package/skills/ae-dataops/SKILL.md +11 -1
  90. package/skills/ae-dataops/references/dataops-backfill.md +135 -0
  91. package/skills/ae-engage/SKILL.md +5 -0
  92. package/skills/ae-engage/references/build-task-save-guide.md +14 -1
  93. package/skills/ae-engage/references/save-flow.md +37 -1
  94. package/skills/ae-engage/references/save-task.md +88 -0
  95. package/skills/ae-experiment/SKILL.md +14 -4
  96. package/skills/ae-experiment/references/manage_feature_whitelist.md +66 -0
  97. package/skills/ae-experiment/references/manage_guardrail_metrics.md +26 -0
  98. package/skills/ae-experiment/references/save_experiment.md +1 -1
  99. package/skills/ae-experiment/references/save_metric.md +20 -8
  100. package/skills/ae-kb/SKILL.md +121 -10
  101. package/skills/ae-project-semantic/SKILL.md +193 -0
  102. package/skills/ae-project-semantic/references/query-routing-v5.md +165 -0
  103. package/skills/ae-project-semantic/references/recommendation-quality.md +68 -0
  104. package/skills/ae-system/SKILL.md +28 -30
  105. package/skills/ae-system/references/channel-management.md +303 -0
  106. package/dist/auth-2WTQOP77.js +0 -14
  107. package/dist/capability-PJHNI4GJ.js +0 -315
  108. package/dist/chunk-4KVPKXFX.js +0 -98
  109. package/dist/chunk-C4MGVGJW.js +0 -13
  110. package/dist/chunk-P3FGXJTU.js +0 -349
  111. package/dist/chunk-QGM4M3NI.js +0 -37
  112. package/dist/chunk-RGKJGKT7.js +0 -71
  113. package/dist/chunk-SAU3QFIQ.js +0 -556
  114. package/dist/chunk-VPKZ7I72.js +0 -509
  115. package/dist/chunk-ZZUOD757.js +0 -598
  116. package/dist/memory-CHRU2F7W.js +0 -893
  117. package/dist/metadata-XXR34N5P.js +0 -339
  118. package/dist/model-K3KLWIW6.js +0 -139
  119. package/dist/sync-FCKOVWWS.js +0 -10261
  120. package/dist/te-agent-HLW4VTQK.js +0 -3893
  121. package/dist/te-analysis-ZMNGOVNW.js +0 -8958
  122. package/dist/te-community-6HPBWJUZ.js +0 -1859
  123. package/dist/te-dataops-HDRUXY4K.js +0 -2208
  124. package/dist/te-engage-RAK5PESW.js +0 -4898
  125. package/dist/te-experiment-VZF7BT6G.js +0 -770
  126. package/dist/te-system-Z77IKZFN.js +0 -2213
@@ -0,0 +1,1115 @@
1
+ import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
2
+ import {
3
+ assertOutputPathAvailable,
4
+ downloadAnalysisArtifact,
5
+ withAsyncArtifactLifecycle
6
+ } from "./chunk-S5PONFBM.js";
7
+ import {
8
+ createCapabilityCommand
9
+ } from "./chunk-DKEXH6Q5.js";
10
+ import {
11
+ registerCapabilityGatewayRoute,
12
+ resolveGatewayDomain
13
+ } from "./chunk-TKHSULJT.js";
14
+ import "./chunk-KEWVSO64.js";
15
+ import {
16
+ CapabilityGatewayError,
17
+ buildCapabilityGatewayUrl,
18
+ executeCapabilityWithEnvelope
19
+ } from "./chunk-GJXRF7Y6.js";
20
+ import "./chunk-Y74WTIKJ.js";
21
+ import "./chunk-RWXIXOZG.js";
22
+ import "./chunk-O6K2ODUE.js";
23
+ import "./chunk-KZ6ZHF5J.js";
24
+ import "./chunk-533JK3YX.js";
25
+ import "./chunk-FR2EDAQM.js";
26
+
27
+ // src/commands/project-semantic/shared.ts
28
+ import { readFileSync } from "fs";
29
+ import { resolve } from "path";
30
+ function createProjectSemanticCommand(config) {
31
+ return createCapabilityCommand({
32
+ ...config,
33
+ cliService: "project-semantic",
34
+ gatewayDomain: "analysis"
35
+ });
36
+ }
37
+ function optionalString(ctx, name) {
38
+ const value = ctx.str(name);
39
+ return value === "" ? void 0 : value;
40
+ }
41
+ function optionalNumber(ctx, name) {
42
+ return ctx.optionalNum(name);
43
+ }
44
+ function optionalJson(ctx, name) {
45
+ if (ctx.str(name) === "") {
46
+ return void 0;
47
+ }
48
+ return ctx.json(name);
49
+ }
50
+ function compactInput(input) {
51
+ return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== void 0));
52
+ }
53
+ function readJsonFile(file, maxBytes = 1024 * 1024) {
54
+ const text = readFileSync(resolve(file), "utf8");
55
+ if (Buffer.byteLength(text, "utf8") > maxBytes) {
56
+ throw new Error(`JSON file must not exceed ${maxBytes} bytes.`);
57
+ }
58
+ return JSON.parse(text);
59
+ }
60
+ function arrayValue(value, label) {
61
+ if (!Array.isArray(value)) {
62
+ throw new Error(`${label} must be a JSON array.`);
63
+ }
64
+ return value;
65
+ }
66
+
67
+ // src/commands/project-semantic/list.ts
68
+ var projectSemanticList = createProjectSemanticCommand({
69
+ resource: "",
70
+ command: "list",
71
+ capabilityId: "business_semantics.catalog.get",
72
+ description: "List project semantics by lifecycle status; defaults to enabled semantics for consumption.",
73
+ flags: [
74
+ {
75
+ name: "project-id",
76
+ type: "number",
77
+ required: true,
78
+ desc: "Numeric project ID.",
79
+ alias: "p",
80
+ min: 1
81
+ },
82
+ {
83
+ name: "status",
84
+ type: "string",
85
+ desc: "Lifecycle status: active or disabled. Defaults to active."
86
+ }
87
+ ],
88
+ risk: "read",
89
+ validate: (ctx) => {
90
+ const status = optionalString(ctx, "status");
91
+ if (status && !["active", "disabled"].includes(status.toLowerCase())) {
92
+ throw new Error("--status must be active or disabled.");
93
+ }
94
+ },
95
+ buildInput: (ctx) => compactInput({
96
+ project_id: ctx.num("project-id"),
97
+ status: optionalString(ctx, "status")?.toLowerCase()
98
+ })
99
+ });
100
+
101
+ // src/commands/project-semantic/get.ts
102
+ var projectSemanticGet = createProjectSemanticCommand({
103
+ resource: "",
104
+ command: "get",
105
+ capabilityId: "business_semantics.entry.get",
106
+ description: "Get one enabled project semantic; use --mark-used only after adopting it.",
107
+ flags: [
108
+ { name: "project-id", type: "number", required: true, desc: "Numeric project ID.", alias: "p", min: 1 },
109
+ { name: "id", type: "string", required: true, desc: "Semantic ID returned by project-semantic list." },
110
+ { name: "mark-used", type: "boolean", desc: "Count this project semantic as used by CLI or Agent." }
111
+ ],
112
+ risk: "read",
113
+ buildInput: (ctx) => ({
114
+ project_id: ctx.num("project-id"),
115
+ id: ctx.str("id"),
116
+ mark_used: ctx.bool("mark-used")
117
+ })
118
+ });
119
+
120
+ // src/commands/project-semantic/enable.ts
121
+ var projectSemanticEnable = createProjectSemanticCommand({
122
+ resource: "",
123
+ command: "enable",
124
+ capabilityId: "business_semantics.entry.enable",
125
+ description: "Enable one disabled project semantic. Enabled semantics are immediately used by CLI and Agent.",
126
+ flags: [
127
+ {
128
+ name: "project-id",
129
+ type: "number",
130
+ required: true,
131
+ desc: "Numeric project ID.",
132
+ alias: "p",
133
+ min: 1
134
+ },
135
+ {
136
+ name: "semantic-id",
137
+ type: "string",
138
+ required: true,
139
+ desc: "Exact disabled semantic ID to enable."
140
+ },
141
+ {
142
+ name: "expected-version",
143
+ type: "number",
144
+ required: true,
145
+ desc: "Latest semantic revision.",
146
+ min: 1
147
+ },
148
+ {
149
+ name: "reason",
150
+ type: "string",
151
+ required: true,
152
+ desc: "Business reason for enabling."
153
+ },
154
+ {
155
+ name: "request-id",
156
+ type: "string",
157
+ desc: "Optional idempotency key; generated when omitted.",
158
+ maxLength: 128
159
+ }
160
+ ],
161
+ risk: "high-risk-write",
162
+ buildInput: (ctx) => compactInput({
163
+ project_id: ctx.num("project-id"),
164
+ semantic_id: ctx.str("semantic-id"),
165
+ expected_version: ctx.num("expected-version"),
166
+ reason: ctx.str("reason"),
167
+ request_id: optionalString(ctx, "request-id")
168
+ })
169
+ });
170
+
171
+ // src/commands/project-semantic/disable.ts
172
+ var projectSemanticDisable = createProjectSemanticCommand({
173
+ resource: "",
174
+ command: "disable",
175
+ capabilityId: "business_semantics.entry.disable",
176
+ description: "Disable one active project semantic in one step. Disabled semantics stop being used by CLI and Agent.",
177
+ flags: [
178
+ { name: "project-id", type: "number", required: true, desc: "Numeric project ID.", alias: "p", min: 1 },
179
+ { name: "semantic-id", type: "string", required: true, desc: "Exact semantic ID to disable." },
180
+ { name: "expected-version", type: "number", required: true, desc: "Latest semantic revision.", min: 1 },
181
+ { name: "reason", type: "string", required: true, desc: "Business reason for disabling." },
182
+ { name: "request-id", type: "string", desc: "Optional idempotency key; generated when omitted.", maxLength: 128 }
183
+ ],
184
+ risk: "high-risk-write",
185
+ buildInput: (ctx) => compactInput({
186
+ project_id: ctx.num("project-id"),
187
+ semantic_id: ctx.str("semantic-id"),
188
+ expected_version: ctx.num("expected-version"),
189
+ reason: ctx.str("reason"),
190
+ request_id: optionalString(ctx, "request-id")
191
+ })
192
+ });
193
+
194
+ // src/commands/project-semantic/delete.ts
195
+ var projectSemanticDelete = createProjectSemanticCommand({
196
+ resource: "",
197
+ command: "delete",
198
+ capabilityId: "business_semantics.entry.delete",
199
+ description: "Physically delete one disabled project semantic and its private revisions. Future scans may recommend it again.",
200
+ flags: [
201
+ {
202
+ name: "project-id",
203
+ type: "number",
204
+ required: true,
205
+ desc: "Numeric project ID.",
206
+ alias: "p",
207
+ min: 1
208
+ },
209
+ {
210
+ name: "semantic-id",
211
+ type: "string",
212
+ required: true,
213
+ desc: "Exact semantic ID to delete."
214
+ },
215
+ {
216
+ name: "expected-version",
217
+ type: "number",
218
+ required: true,
219
+ desc: "Latest semantic revision.",
220
+ min: 1
221
+ },
222
+ {
223
+ name: "reason",
224
+ type: "string",
225
+ required: true,
226
+ desc: "Business reason for physical deletion."
227
+ },
228
+ {
229
+ name: "request-id",
230
+ type: "string",
231
+ desc: "Optional request ID; generated when omitted.",
232
+ maxLength: 128
233
+ }
234
+ ],
235
+ risk: "high-risk-write",
236
+ buildInput: (ctx) => compactInput({
237
+ project_id: ctx.num("project-id"),
238
+ semantic_id: ctx.str("semantic-id"),
239
+ expected_version: ctx.num("expected-version"),
240
+ reason: ctx.str("reason"),
241
+ request_id: optionalString(ctx, "request-id")
242
+ })
243
+ });
244
+
245
+ // src/commands/project-semantic/delete-impact.ts
246
+ var projectSemanticDeleteImpact = createProjectSemanticCommand({
247
+ resource: "",
248
+ command: "delete-impact",
249
+ capabilityId: "business_semantics.entry.delete_impact",
250
+ description: "Preview rows affected by physically deleting one disabled project semantic.",
251
+ flags: [
252
+ {
253
+ name: "project-id",
254
+ type: "number",
255
+ required: true,
256
+ desc: "Numeric project ID.",
257
+ alias: "p",
258
+ min: 1
259
+ },
260
+ {
261
+ name: "semantic-id",
262
+ type: "string",
263
+ required: true,
264
+ desc: "Exact semantic ID to inspect."
265
+ }
266
+ ],
267
+ risk: "read",
268
+ buildInput: (ctx) => ({
269
+ project_id: ctx.num("project-id"),
270
+ semantic_id: ctx.str("semantic-id")
271
+ })
272
+ });
273
+
274
+ // src/commands/project-semantic/asset-package/materializer.ts
275
+ import { createHash, randomBytes } from "crypto";
276
+ import { createReadStream } from "fs";
277
+ import {
278
+ appendFile,
279
+ mkdir,
280
+ readFile,
281
+ rename,
282
+ rm,
283
+ stat,
284
+ writeFile
285
+ } from "fs/promises";
286
+ import { createInterface } from "readline";
287
+ import { createGunzip } from "zlib";
288
+ import { basename, dirname, resolve as resolve2 } from "path";
289
+ var MAX_COMPRESSED_BYTES = 64 * 1024 * 1024;
290
+ var MAX_UNCOMPRESSED_BYTES = 512 * 1024 * 1024;
291
+ var MAX_RECORDS = 2e5;
292
+ var SHA256_PATTERN = /^[0-9a-f]{64}$/;
293
+ var REQUIRED_FILES = [
294
+ "manifest.json",
295
+ "indexes/work-units.jsonl",
296
+ "indexes/asset-directory.jsonl",
297
+ "indexes/coverage-batches.jsonl",
298
+ "indexes/definition-families.jsonl",
299
+ "indexes/governance-coverage.jsonl",
300
+ "catalog/published.jsonl",
301
+ "catalog/active-candidates.jsonl",
302
+ "catalog/rejected-candidates.jsonl"
303
+ ];
304
+ async function preflightAssetPackageOutput(args) {
305
+ await assertOutputPathAvailable(args.output, args.force);
306
+ }
307
+ async function materializeProjectSemanticAssetPackage(args) {
308
+ const descriptor = packageDescriptor(args.finalDescriptor);
309
+ const output = resolve2(args.output);
310
+ const parent = dirname(output);
311
+ const nonce = `${process.pid}-${randomBytes(6).toString("hex")}`;
312
+ const staging = resolve2(parent, `.${basename(output)}.staging-${nonce}`);
313
+ const archive = resolve2(parent, `.${basename(output)}.archive-${nonce}.jsonl.gz`);
314
+ const backup = resolve2(parent, `.${basename(output)}.backup-${nonce}`);
315
+ let movedExisting = false;
316
+ await assertOutputPathAvailable(output, args.force, {
317
+ run_id: args.runId,
318
+ artifact_id: args.artifactId
319
+ });
320
+ await mkdir(parent, { recursive: true });
321
+ await mkdir(staging, { recursive: false });
322
+ try {
323
+ const download = await downloadAnalysisArtifact(
324
+ args.ctx.host(),
325
+ args.runId,
326
+ args.artifactId,
327
+ archive,
328
+ { signal: args.signal, ensureReady: false }
329
+ );
330
+ if (download.bytes > MAX_COMPRESSED_BYTES) {
331
+ throw packageError("Asset package archive exceeds 64 MiB.", "ASSET_PACKAGE_ARCHIVE_TOO_LARGE");
332
+ }
333
+ const materialized = await materializeArchive(archive, staging, descriptor);
334
+ if (args.force && await exists(output)) {
335
+ await rename(output, backup);
336
+ movedExisting = true;
337
+ }
338
+ await rename(staging, output);
339
+ if (movedExisting) {
340
+ await rm(backup, { recursive: true, force: true });
341
+ movedExisting = false;
342
+ }
343
+ return {
344
+ ...args.finalDescriptor,
345
+ output_path: output,
346
+ archive_bytes: download.bytes,
347
+ record_count: materialized.recordCount,
348
+ uncompressed_bytes: materialized.uncompressedBytes
349
+ };
350
+ } catch (error) {
351
+ if (movedExisting) {
352
+ await rename(backup, output).catch(() => void 0);
353
+ }
354
+ throw error;
355
+ } finally {
356
+ await rm(archive, { force: true }).catch(() => void 0);
357
+ await rm(staging, { recursive: true, force: true }).catch(() => void 0);
358
+ if (!movedExisting) {
359
+ await rm(backup, { recursive: true, force: true }).catch(() => void 0);
360
+ }
361
+ }
362
+ }
363
+ async function materializeArchive(archive, staging, descriptor) {
364
+ const compressed = await stat(archive);
365
+ if (compressed.size > MAX_COMPRESSED_BYTES) {
366
+ throw packageError("Asset package archive exceeds 64 MiB.", "ASSET_PACKAGE_ARCHIVE_TOO_LARGE");
367
+ }
368
+ const digest = createHash("sha256");
369
+ const lines = createInterface({
370
+ input: createReadStream(archive).pipe(createGunzip()),
371
+ crlfDelay: Infinity
372
+ });
373
+ let recordCount = 0;
374
+ let uncompressedBytes = 0;
375
+ let manifest;
376
+ for await (const line of lines) {
377
+ if (!line.trim()) continue;
378
+ uncompressedBytes += Buffer.byteLength(line, "utf8") + 1;
379
+ if (uncompressedBytes > MAX_UNCOMPRESSED_BYTES) {
380
+ throw packageError(
381
+ "Asset package archive exceeds 512 MiB after decompression.",
382
+ "ASSET_PACKAGE_ARCHIVE_TOO_LARGE"
383
+ );
384
+ }
385
+ recordCount += 1;
386
+ if (recordCount > MAX_RECORDS) {
387
+ throw packageError("Asset package has too many records.", "ASSET_PACKAGE_RECORD_LIMIT_EXCEEDED");
388
+ }
389
+ digest.update(line, "utf8");
390
+ digest.update("\n", "utf8");
391
+ const record = parseRecord(line);
392
+ const target = resolveRecordPath(staging, record.path);
393
+ await mkdir(dirname(target), { recursive: true });
394
+ const content = `${JSON.stringify(record.content)}
395
+ `;
396
+ if (record.append) {
397
+ await appendFile(target, content, "utf8");
398
+ } else {
399
+ await writeFile(target, content, { encoding: "utf8", flag: "wx" });
400
+ }
401
+ if (record.path === "manifest.json") {
402
+ manifest = asObject(record.content);
403
+ }
404
+ }
405
+ const actualHash = digest.digest("hex");
406
+ if (actualHash !== descriptor.snapshotHash) {
407
+ throw packageError(
408
+ `Asset package content hash mismatch: expected ${descriptor.snapshotHash}, received ${actualHash}.`,
409
+ "ASSET_PACKAGE_HASH_MISMATCH"
410
+ );
411
+ }
412
+ if (!manifest || !Number.isInteger(Number(manifest.project_id))) {
413
+ throw packageError("Asset package manifest is missing project identity.", "ASSET_PACKAGE_MANIFEST_INVALID");
414
+ }
415
+ if (manifest.schema_version !== "1.0") {
416
+ throw packageError("Project semantic asset package schema 1.0 is required.", "ASSET_PACKAGE_VERSION_MISMATCH");
417
+ }
418
+ for (const required of REQUIRED_FILES) {
419
+ if (!await exists(resolve2(staging, required))) {
420
+ throw packageError(`Asset package is missing required file ${required}.`, "ASSET_PACKAGE_MANIFEST_INVALID");
421
+ }
422
+ }
423
+ await verifyDetailLocators(staging);
424
+ await writeFile(resolve2(staging, ".asset-package.json"), JSON.stringify({
425
+ snapshot_id: descriptor.snapshotId,
426
+ snapshot_hash: descriptor.snapshotHash,
427
+ schema_version: "1.0",
428
+ company_id: Number(manifest.company_id),
429
+ project_id: Number(manifest.project_id),
430
+ record_count: recordCount,
431
+ asset_scope: typeof manifest.asset_scope === "string" ? manifest.asset_scope : "governed",
432
+ exported_asset_count: Number(manifest.exported_asset_count ?? manifest.authenticated_asset_count),
433
+ authenticated_asset_count: Number(manifest.authenticated_asset_count),
434
+ unauthenticated_asset_count: Number(manifest.unauthenticated_asset_count ?? 0),
435
+ truncated: Boolean(manifest.truncated),
436
+ counts: manifest.counts,
437
+ filter_policy: manifest.filter_policy
438
+ }, null, 2), "utf8");
439
+ return { recordCount, uncompressedBytes };
440
+ }
441
+ async function verifyDetailLocators(root) {
442
+ const directory = await readFile(resolve2(root, "indexes/asset-directory.jsonl"), "utf8");
443
+ for (const line of directory.split(/\r?\n/)) {
444
+ if (!line.trim()) continue;
445
+ const row = asObject(JSON.parse(line));
446
+ if (!row || row.record_type === "header") continue;
447
+ const detail = await verifyContentLocator(root, row.detail_locator, "Detail");
448
+ await verifyContentLocator(root, detail.raw_locator, "Raw detail");
449
+ }
450
+ }
451
+ async function verifyContentLocator(root, value, label) {
452
+ const locator = asObject(value);
453
+ if (!locator || typeof locator.path !== "string" || typeof locator.content_hash !== "string" || !SHA256_PATTERN.test(locator.content_hash)) {
454
+ throw packageError(
455
+ `Asset package contains an invalid ${label.toLowerCase()} locator.`,
456
+ "ASSET_PACKAGE_MANIFEST_INVALID"
457
+ );
458
+ }
459
+ const target = resolveRecordPath(root, locator.path);
460
+ if (!await exists(target)) {
461
+ throw packageError(`Asset package is missing ${label.toLowerCase()} file ${locator.path}.`, "ASSET_PACKAGE_MANIFEST_INVALID");
462
+ }
463
+ const content = asObject(JSON.parse(await readFile(target, "utf8")));
464
+ if (!content) {
465
+ throw packageError(`${label} file is not a JSON object: ${locator.path}.`, "ASSET_PACKAGE_MANIFEST_INVALID");
466
+ }
467
+ const actualHash = createHash("sha256").update(JSON.stringify(content), "utf8").digest("hex");
468
+ if (actualHash !== locator.content_hash) {
469
+ throw packageError(`${label} content hash mismatch for ${locator.path}.`, "ASSET_PACKAGE_HASH_MISMATCH");
470
+ }
471
+ return content;
472
+ }
473
+ function parseRecord(line) {
474
+ const value = JSON.parse(line);
475
+ const record = asObject(value);
476
+ if (!record || typeof record.path !== "string") {
477
+ throw packageError("Asset package record is missing path.", "ASSET_PACKAGE_RECORD_INVALID");
478
+ }
479
+ if (!Object.prototype.hasOwnProperty.call(record, "content")) {
480
+ throw packageError("Asset package record is missing content.", "ASSET_PACKAGE_RECORD_INVALID");
481
+ }
482
+ return {
483
+ path: record.path,
484
+ append: Boolean(record.append),
485
+ content: record.content
486
+ };
487
+ }
488
+ function resolveRecordPath(root, path) {
489
+ if (path.startsWith("/") || path.includes("\0")) {
490
+ throw packageError(`Invalid asset package path: ${path}`, "ASSET_PACKAGE_PATH_INVALID");
491
+ }
492
+ const target = resolve2(root, path);
493
+ const normalizedRoot = `${resolve2(root)}/`;
494
+ if (!target.startsWith(normalizedRoot)) {
495
+ throw packageError(`Invalid asset package path: ${path}`, "ASSET_PACKAGE_PATH_INVALID");
496
+ }
497
+ return target;
498
+ }
499
+ function packageDescriptor(descriptor) {
500
+ const snapshotHash = stringValue(descriptor.snapshot_hash, "snapshot_hash").toLowerCase();
501
+ if (!SHA256_PATTERN.test(snapshotHash)) {
502
+ throw packageError("Asset package export returned invalid snapshot_hash.", "ASSET_PACKAGE_DESCRIPTOR_INVALID");
503
+ }
504
+ return {
505
+ snapshotId: typeof descriptor.snapshot_id === "string" ? descriptor.snapshot_id : void 0,
506
+ snapshotHash
507
+ };
508
+ }
509
+ function asObject(value) {
510
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
511
+ return value;
512
+ }
513
+ function stringValue(value, label) {
514
+ if (typeof value !== "string" || value.trim() === "") {
515
+ throw packageError(`${label} must be a non-empty string.`, "ASSET_PACKAGE_DESCRIPTOR_INVALID");
516
+ }
517
+ return value;
518
+ }
519
+ async function exists(path) {
520
+ try {
521
+ await stat(path);
522
+ return true;
523
+ } catch {
524
+ return false;
525
+ }
526
+ }
527
+ function packageError(message, code) {
528
+ return new CapabilityGatewayError(message, code, 422);
529
+ }
530
+
531
+ // src/commands/project-semantic/asset-package/export.ts
532
+ var ASSET_PACKAGE_EXPORT_CAPABILITY = "business_semantics.asset_package.export";
533
+ var ASSET_SCOPES = /* @__PURE__ */ new Set(["governed", "collaborative", "all_visible"]);
534
+ function assetScope(ctx) {
535
+ const value = ctx.str("asset-scope") || "governed";
536
+ if (!ASSET_SCOPES.has(value)) {
537
+ throw new Error("asset-scope must be one of: governed, collaborative, all_visible");
538
+ }
539
+ return value;
540
+ }
541
+ var assetPackageExportCommand = {
542
+ service: "project-semantic",
543
+ resource: "asset-package",
544
+ command: "export",
545
+ description: "Export and materialize a project asset package for CLI Agent semantic recommendation.",
546
+ flags: [
547
+ { name: "project-id", type: "number", required: true, desc: "Numeric project ID.", alias: "p", min: 1 },
548
+ {
549
+ name: "asset-scope",
550
+ type: "string",
551
+ required: false,
552
+ desc: "Asset scope: governed, collaborative, or all_visible. Defaults to governed."
553
+ }
554
+ ],
555
+ risk: "read",
556
+ dryRun: (ctx) => ({
557
+ method: "POST",
558
+ url: buildCapabilityGatewayUrl(
559
+ ctx.host(),
560
+ resolveGatewayDomain("analysis", "analysis"),
561
+ `capabilities/${ASSET_PACKAGE_EXPORT_CAPABILITY}/execute`
562
+ ),
563
+ body: { input: { project_id: ctx.num("project-id"), asset_scope: assetScope(ctx) } }
564
+ }),
565
+ execute: async (ctx) => {
566
+ const projectId = ctx.num("project-id");
567
+ const scope = assetScope(ctx);
568
+ const response = await executeCapabilityWithEnvelope(
569
+ ctx.host(),
570
+ resolveGatewayDomain("analysis", "analysis"),
571
+ ASSET_PACKAGE_EXPORT_CAPABILITY,
572
+ { project_id: projectId, asset_scope: scope }
573
+ );
574
+ return response.data;
575
+ }
576
+ };
577
+ var projectSemanticAssetPackageExport = withAsyncArtifactLifecycle(assetPackageExportCommand, {
578
+ preflightOutput: ({ output, force }) => preflightAssetPackageOutput({ output, force }),
579
+ materialize: materializeProjectSemanticAssetPackage
580
+ });
581
+
582
+ // src/commands/project-semantic/candidate/submit.ts
583
+ var projectSemanticCandidateSubmit = createProjectSemanticCommand({
584
+ resource: "candidate",
585
+ command: "submit",
586
+ capabilityId: "business_semantics.candidate.submit",
587
+ description: "Submit CLI-Agent generated project semantic candidates grouped by topic domain.",
588
+ flags: [
589
+ { name: "project-id", type: "number", required: true, desc: "Numeric project ID.", alias: "p", min: 1 },
590
+ { name: "topic-groups", type: "json", desc: "Topic-domain grouped recommendations JSON array." },
591
+ { name: "submit-file", type: "string", desc: "JSON file containing topic_groups or an array of groups." },
592
+ { name: "snapshot-hash", type: "string", desc: "Optional exported asset package SHA-256." },
593
+ { name: "request-id", type: "string", desc: "Optional idempotency key; generated when omitted.", maxLength: 128 }
594
+ ],
595
+ risk: "write",
596
+ validate: validateSubmitSource,
597
+ buildInput: (ctx) => compactInput({
598
+ project_id: ctx.num("project-id"),
599
+ snapshot_hash: optionalString(ctx, "snapshot-hash"),
600
+ topic_groups: topicGroups(ctx),
601
+ request_id: optionalString(ctx, "request-id")
602
+ })
603
+ });
604
+ function validateSubmitSource(ctx) {
605
+ topicGroups(ctx);
606
+ }
607
+ function topicGroups(ctx) {
608
+ const hasInline = ctx.str("topic-groups") !== "";
609
+ const hasFile = ctx.str("submit-file") !== "";
610
+ if (hasInline === hasFile) {
611
+ throw new Error("Provide exactly one of --topic-groups or --submit-file.");
612
+ }
613
+ const raw = hasInline ? optionalJson(ctx, "topic-groups") : readJsonFile(ctx.str("submit-file"), 2 * 1024 * 1024);
614
+ const groups = Array.isArray(raw) ? raw : arrayValue(raw?.topic_groups, "--submit-file topic_groups");
615
+ if (groups.length < 1 || groups.length > 100) {
616
+ throw new Error("topic_groups must contain 1 to 100 groups.");
617
+ }
618
+ return groups;
619
+ }
620
+
621
+ // src/commands/project-semantic/candidate/enable.ts
622
+ var projectSemanticCandidateEnable = createProjectSemanticCommand({
623
+ resource: "candidate",
624
+ command: "enable",
625
+ capabilityId: "business_semantics.candidate.enable",
626
+ description: "Enable recommended project semantic candidates. Enabled semantics are immediately used by CLI and Agent.",
627
+ flags: [
628
+ {
629
+ name: "project-id",
630
+ type: "number",
631
+ required: true,
632
+ desc: "Numeric project ID.",
633
+ alias: "p",
634
+ min: 1
635
+ },
636
+ {
637
+ name: "candidate-ids",
638
+ type: "json",
639
+ required: true,
640
+ desc: "JSON array of candidate IDs to enable."
641
+ },
642
+ { name: "note", type: "string", desc: "Optional enable note." },
643
+ {
644
+ name: "request-id",
645
+ type: "string",
646
+ desc: "Optional idempotency key; generated when omitted.",
647
+ maxLength: 128
648
+ }
649
+ ],
650
+ risk: "high-risk-write",
651
+ validate: (ctx) => candidateIds(ctx),
652
+ buildInput: (ctx) => compactInput({
653
+ project_id: ctx.num("project-id"),
654
+ candidate_ids: candidateIds(ctx),
655
+ publish_note: optionalString(ctx, "note"),
656
+ request_id: optionalString(ctx, "request-id")
657
+ })
658
+ });
659
+ function candidateIds(ctx) {
660
+ const values = arrayValue(
661
+ optionalJson(ctx, "candidate-ids"),
662
+ "--candidate-ids"
663
+ );
664
+ if (values.length < 1 || values.some((value) => typeof value !== "string" || value.trim() === "")) {
665
+ throw new Error("--candidate-ids must be a non-empty JSON string array.");
666
+ }
667
+ return values;
668
+ }
669
+
670
+ // src/commands/project-semantic/candidate/validate.ts
671
+ import { createHash as createHash2 } from "crypto";
672
+ import { existsSync, readFileSync as readFileSync2, statSync } from "fs";
673
+ import { join, resolve as resolve3 } from "path";
674
+ var SEMANTIC_TYPES = /* @__PURE__ */ new Set([
675
+ "business_concept",
676
+ "business_rule",
677
+ "asset_semantics",
678
+ "calculation_convention"
679
+ ]);
680
+ var projectSemanticCandidateValidate = {
681
+ service: "project-semantic",
682
+ resource: "candidate",
683
+ command: "validate",
684
+ description: "Validate deterministic candidate contracts against a certified project-semantic asset package.",
685
+ flags: [
686
+ { name: "asset-package", type: "string", required: true, desc: "Materialized authenticated project asset package directory." },
687
+ { name: "submit-file", type: "string", required: true, desc: "Agent-authored JSON containing topic_groups." }
688
+ ],
689
+ risk: "read",
690
+ execute: async (ctx) => validateCandidateFile(
691
+ loadStructuredPackage(ctx.str("asset-package")),
692
+ readJsonFile(ctx.str("submit-file"), 4 * 1024 * 1024)
693
+ )
694
+ };
695
+ function validateCandidateFile(assetPackage, submitFile) {
696
+ const submitRecord = recordValue(submitFile, "submit file");
697
+ const assets = assetPackage.assets;
698
+ const groups = arrayValue(submitRecord.topic_groups, "submit file topic_groups").map((item) => recordValue(item, "topic group"));
699
+ const assetKeys = new Set(assets.flatMap(assetIdentityKeys));
700
+ const assetByIdentityKey = /* @__PURE__ */ new Map();
701
+ assets.forEach((asset) => {
702
+ assetIdentityKeys(asset).forEach((key) => assetByIdentityKey.set(key, asset));
703
+ });
704
+ const candidates = groups.flatMap(
705
+ (group) => arrayValue(group.candidates, "topic group candidates").map((item) => ({
706
+ group,
707
+ candidate: recordValue(item, "candidate")
708
+ }))
709
+ );
710
+ const errors = [];
711
+ const warnings = [];
712
+ const titles = /* @__PURE__ */ new Map();
713
+ const bodies = /* @__PURE__ */ new Map();
714
+ const blockingCatalog = assetPackage.catalogEntries.filter((entry) => entry.catalog_kind !== "rejected");
715
+ const rejectedCatalog = assetPackage.catalogEntries.filter((entry) => entry.catalog_kind === "rejected");
716
+ let unresolvedResourceRefCount = 0;
717
+ if (groups.length < 1 || groups.length > 100) {
718
+ errors.push("topic_groups must contain 1 to 100 groups.");
719
+ }
720
+ if (candidates.length < 1 || candidates.length > 200) {
721
+ errors.push("The candidate batch must contain 1 to 200 candidates.");
722
+ }
723
+ groups.forEach((group, groupIndex) => {
724
+ const groupLabel = `topic_groups[${groupIndex}]`;
725
+ requireText(group, "topic_domain_key", groupLabel, errors);
726
+ requireText(group, "topic_domain_title", groupLabel, errors);
727
+ requireText(group, "topic_group_key", groupLabel, errors);
728
+ requireText(group, "topic_group_title", groupLabel, errors);
729
+ requireText(group, "topic_group_reason", groupLabel, errors);
730
+ });
731
+ candidates.forEach(({ candidate }, index) => {
732
+ const label = `candidate[${index}]`;
733
+ const semanticType = requireText(candidate, "semantic_type", label, errors).toLowerCase();
734
+ const title = requireText(candidate, "title", label, errors);
735
+ requireText(candidate, "summary", label, errors);
736
+ const content = requireText(candidate, "content", label, errors);
737
+ requireText(candidate, "recommendation_reason", label, errors);
738
+ if (!SEMANTIC_TYPES.has(semanticType)) {
739
+ errors.push(`${label}.semantic_type is unsupported.`);
740
+ }
741
+ increment(titles, normalize(title));
742
+ increment(bodies, normalize(content));
743
+ const semanticTypeAndBody = semanticContentFingerprint(semanticType, content);
744
+ const duplicateEntry = blockingCatalog.find((entry) => normalize(textValue(entry.title)) === normalize(title) || textValue(entry.content_fingerprint) === semanticTypeAndBody);
745
+ if (duplicateEntry) {
746
+ errors.push(`${label} duplicates an existing ${catalogLabel(duplicateEntry)} semantic: ${textValue(duplicateEntry.title)}.`);
747
+ }
748
+ const rejectedEntry = rejectedCatalog.find((entry) => normalize(textValue(entry.title)) === normalize(title) || textValue(entry.content_fingerprint) === semanticTypeAndBody);
749
+ if (rejectedEntry && !hasMaterialChange(candidate)) {
750
+ warnings.push(`${label} matches rejected candidate ${textValue(rejectedEntry.candidate_id)}; provide change_kind and target_candidate_id for a material revision.`);
751
+ }
752
+ const refs = arrayValue(candidate.resource_refs, `${label}.resource_refs`).map((item) => recordValue(item, "resource ref"));
753
+ if (refs.length === 0) {
754
+ errors.push(`${label}.resource_refs must bind certified evidence from the asset package.`);
755
+ }
756
+ refs.forEach((ref) => {
757
+ if (!resourceIdentityKeys(ref).some((key) => assetKeys.has(key))) {
758
+ unresolvedResourceRefCount += 1;
759
+ }
760
+ });
761
+ });
762
+ const duplicateTitles = duplicateCount(titles);
763
+ const duplicateBodies = duplicateCount(bodies);
764
+ if (duplicateTitles > 0) {
765
+ errors.push(`${duplicateTitles} duplicate candidate titles were generated.`);
766
+ }
767
+ if (duplicateBodies > 0) {
768
+ errors.push(`${duplicateBodies} duplicate semantic bodies were generated.`);
769
+ }
770
+ if (unresolvedResourceRefCount > 0) {
771
+ errors.push(`${unresolvedResourceRefCount} resource_refs do not resolve to the authenticated asset package.`);
772
+ }
773
+ const oneCandidatePerAsset = candidates.length > 1 && candidates.every(
774
+ ({ candidate }) => Array.isArray(candidate.resource_refs) && candidate.resource_refs.length === 1
775
+ );
776
+ return {
777
+ passed: errors.length === 0 && warnings.length === 0,
778
+ topic_domain_count: groups.length,
779
+ candidate_count: candidates.length,
780
+ authenticated_asset_count: assets.length,
781
+ unresolved_resource_ref_count: unresolvedResourceRefCount,
782
+ duplicate_title_count: duplicateTitles,
783
+ duplicate_body_count: duplicateBodies,
784
+ one_candidate_per_asset: oneCandidatePerAsset,
785
+ catalog_entry_count: assetPackage.catalogEntries.length,
786
+ package_kind: "structured_directory",
787
+ snapshot_hash: assetPackage.snapshotHash,
788
+ topic_groups: topicGroupSummaries(groups, assetByIdentityKey),
789
+ errors,
790
+ warnings
791
+ };
792
+ }
793
+ function topicGroupSummaries(groups, assetByIdentityKey) {
794
+ return groups.map((group) => {
795
+ const candidates = arrayValue(group.candidates, "topic group candidates").map((item) => recordValue(item, "candidate"));
796
+ return {
797
+ topic_domain_key: textValue(group.topic_domain_key),
798
+ topic_domain_title: textValue(group.topic_domain_title),
799
+ topic_group_key: textValue(group.topic_group_key),
800
+ topic_group_title: textValue(group.topic_group_title),
801
+ candidate_count: candidates.length,
802
+ topic_group_reason: textValue(group.topic_group_reason),
803
+ candidates: candidates.map((candidate, index) => candidateSummary(candidate, index, assetByIdentityKey))
804
+ };
805
+ });
806
+ }
807
+ function candidateSummary(candidate, index, assetByIdentityKey) {
808
+ const refs = Array.isArray(candidate.resource_refs) ? candidate.resource_refs.map((item) => recordValue(item, "resource ref")) : [];
809
+ return {
810
+ index: index + 1,
811
+ semantic_type: textValue(candidate.semantic_type).toLowerCase(),
812
+ title: textValue(candidate.title),
813
+ summary: textValue(candidate.summary),
814
+ resource_ref_count: refs.length,
815
+ evidence_assets: refs.map((ref) => resourceRefSummary(ref, assetByIdentityKey))
816
+ };
817
+ }
818
+ function resourceRefSummary(ref, assetByIdentityKey) {
819
+ const matchedAsset = resourceIdentityKeys(ref).map((key) => assetByIdentityKey.get(key)).find(Boolean);
820
+ return {
821
+ resource_type: textValue(ref.asset_type || ref.resource_type || ref.type).toLowerCase(),
822
+ resource_key: textValue(ref.resource_key || ref.asset_id || ref.id || ref.evidence_id || ref.name),
823
+ title: textValue(ref.title || ref.display_name || matchedAsset?.title || matchedAsset?.display_name || matchedAsset?.name)
824
+ };
825
+ }
826
+ function loadStructuredPackage(path) {
827
+ const packagePath = resolve3(path);
828
+ const stats = statSync(packagePath);
829
+ if (!stats.isDirectory()) {
830
+ throw new Error("asset-package must be a materialized structured package directory.");
831
+ }
832
+ recordValue(readJsonFile(join(packagePath, "manifest.json"), 4 * 1024 * 1024), "asset package manifest");
833
+ const descriptor = recordValue(readJsonFile(join(packagePath, ".asset-package.json"), 64 * 1024), "asset package descriptor");
834
+ const snapshotHash = textValue(descriptor.snapshot_hash);
835
+ if (!snapshotHash) {
836
+ throw new Error("asset package descriptor must contain snapshot_hash.");
837
+ }
838
+ const assets = readJsonlFile(join(packagePath, "indexes", "asset-directory.jsonl"), "asset directory").filter((row) => row.record_type !== "header");
839
+ if (assets.length === 0) {
840
+ throw new Error("asset directory must contain at least one asset.");
841
+ }
842
+ return {
843
+ assets,
844
+ catalogEntries: loadCatalogEntries(packagePath),
845
+ snapshotHash
846
+ };
847
+ }
848
+ function loadCatalogEntries(packagePath) {
849
+ return [
850
+ ["published", join(packagePath, "catalog", "published.jsonl")],
851
+ ["disabled", join(packagePath, "catalog", "disabled.jsonl")],
852
+ ["active", join(packagePath, "catalog", "active-candidates.jsonl")],
853
+ ["rejected", join(packagePath, "catalog", "rejected-candidates.jsonl")]
854
+ ].flatMap(([kind, file]) => {
855
+ if (!existsSync(file)) {
856
+ return [];
857
+ }
858
+ return readJsonlFile(file, `${kind} semantic catalog`).filter((row) => row.record_type !== "header").map((row) => ({ ...row, catalog_kind: kind }));
859
+ });
860
+ }
861
+ function semanticContentFingerprint(semanticType, content) {
862
+ const normalized = `${semanticType.trim().toLowerCase()}
863
+ ${normalizeSemanticText(content)}`;
864
+ return createHash2("sha256").update(normalized).digest("hex");
865
+ }
866
+ function normalizeSemanticText(value) {
867
+ return value.toLowerCase().replace(/\s+/g, "").replace(/[,。;:、,.!?!?:;]/g, "");
868
+ }
869
+ function catalogLabel(entry) {
870
+ if (entry.catalog_kind === "published") {
871
+ return "published";
872
+ }
873
+ return entry.catalog_kind === "disabled" ? "disabled" : "active candidate";
874
+ }
875
+ function hasMaterialChange(candidate) {
876
+ return textValue(candidate.change_kind) !== "" && textValue(candidate.target_candidate_id) !== "";
877
+ }
878
+ function readJsonlFile(file, label) {
879
+ const text = readFileSync2(file, "utf8");
880
+ const rows = [];
881
+ for (const [index, line] of text.split(/\r?\n/).entries()) {
882
+ if (!line.trim()) {
883
+ continue;
884
+ }
885
+ rows.push(recordValue(JSON.parse(line), `${label} line ${index + 1}`));
886
+ }
887
+ return rows;
888
+ }
889
+ function assetIdentityKeys(asset) {
890
+ const type = textValue(asset.asset_type || asset.resource_type || asset.type).toLowerCase();
891
+ return [asset.asset_id, asset.asset_name, asset.name, asset.resource_key, asset.id].concat(asset.evidence_id).flatMap((value) => identityValueKeys(type, value));
892
+ }
893
+ function resourceIdentityKeys(ref) {
894
+ const type = textValue(ref.asset_type || ref.resource_type || ref.type).toLowerCase();
895
+ return [ref.asset_id, ref.asset_name, ref.name, ref.resource_key, ref.id].concat(ref.evidence_id).flatMap((value) => identityValueKeys(type, value));
896
+ }
897
+ function identityValueKeys(type, value) {
898
+ const key = textValue(value);
899
+ if (!type || !key) {
900
+ return [];
901
+ }
902
+ const variants = /* @__PURE__ */ new Set([key]);
903
+ const typedPrefix = `${type}_`;
904
+ if (key.startsWith(typedPrefix) && key.length > typedPrefix.length) {
905
+ variants.add(key.slice(typedPrefix.length));
906
+ }
907
+ const lastColon = key.lastIndexOf(":");
908
+ if (lastColon >= 0 && lastColon < key.length - 1) {
909
+ variants.add(key.slice(lastColon + 1));
910
+ }
911
+ return Array.from(variants).map((item) => `${type}:${item}`);
912
+ }
913
+ function recordValue(value, label) {
914
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
915
+ throw new Error(`${label} must be a JSON object.`);
916
+ }
917
+ return value;
918
+ }
919
+ function requireText(record, field, label, errors) {
920
+ const value = textValue(record[field]);
921
+ if (!value) {
922
+ errors.push(`${label}.${field} is required.`);
923
+ }
924
+ return value;
925
+ }
926
+ function textValue(value) {
927
+ return typeof value === "string" ? value.trim() : typeof value === "number" ? String(value) : "";
928
+ }
929
+ function normalize(value) {
930
+ return value.toLowerCase().replace(/\s+/g, " ").trim();
931
+ }
932
+ function increment(values, key) {
933
+ if (key) {
934
+ values.set(key, (values.get(key) || 0) + 1);
935
+ }
936
+ }
937
+ function duplicateCount(values) {
938
+ return Array.from(values.values()).reduce((sum, count) => sum + Math.max(0, count - 1), 0);
939
+ }
940
+
941
+ // src/commands/project-semantic/candidate/list.ts
942
+ var projectSemanticCandidateList = createProjectSemanticCommand({
943
+ resource: "candidate",
944
+ command: "list",
945
+ capabilityId: "business_semantics.candidate.list",
946
+ description: "List Agent recommendations grouped by topic domain.",
947
+ flags: [
948
+ { name: "project-id", type: "number", required: true, desc: "Numeric project ID.", alias: "p", min: 1 },
949
+ { name: "status", type: "string", desc: "Internal recommendation status filter." },
950
+ { name: "topic-group-id", type: "string", desc: "Optional exact topic group ID." },
951
+ { name: "limit", type: "number", desc: "Directory page size.", min: 1, max: 200 },
952
+ { name: "offset", type: "number", desc: "Zero-based directory page offset.", min: 0 }
953
+ ],
954
+ risk: "read",
955
+ buildInput: (ctx) => compactInput({
956
+ project_id: ctx.num("project-id"),
957
+ status: optionalString(ctx, "status"),
958
+ topic_group_id: optionalString(ctx, "topic-group-id"),
959
+ limit: optionalNumber(ctx, "limit"),
960
+ offset: optionalNumber(ctx, "offset")
961
+ })
962
+ });
963
+
964
+ // src/commands/project-semantic/candidate/get.ts
965
+ var projectSemanticCandidateGet = createProjectSemanticCommand({
966
+ resource: "candidate",
967
+ command: "get",
968
+ capabilityId: "business_semantics.candidate.get",
969
+ description: "Get one project semantic candidate with evidence and structured asset bindings.",
970
+ flags: [
971
+ { name: "project-id", type: "number", required: true, desc: "Numeric project ID.", alias: "p", min: 1 },
972
+ { name: "candidate-id", type: "string", required: true, desc: "Exact candidate ID." }
973
+ ],
974
+ risk: "read",
975
+ buildInput: (ctx) => ({
976
+ project_id: ctx.num("project-id"),
977
+ candidate_id: ctx.str("candidate-id")
978
+ })
979
+ });
980
+
981
+ // src/commands/project-semantic/candidate/edit.ts
982
+ var projectSemanticCandidateEdit = createProjectSemanticCommand({
983
+ resource: "candidate",
984
+ command: "edit",
985
+ capabilityId: "business_semantics.candidate.edit",
986
+ description: "Edit one recommendation before enabling it.",
987
+ flags: [
988
+ {
989
+ name: "project-id",
990
+ type: "number",
991
+ required: true,
992
+ desc: "Numeric project ID.",
993
+ alias: "p",
994
+ min: 1
995
+ },
996
+ {
997
+ name: "candidate-id",
998
+ type: "string",
999
+ required: true,
1000
+ desc: "Exact candidate ID."
1001
+ },
1002
+ {
1003
+ name: "expected-version",
1004
+ type: "number",
1005
+ required: true,
1006
+ desc: "Latest optimistic-lock version.",
1007
+ min: 1
1008
+ },
1009
+ {
1010
+ name: "semantic-type",
1011
+ type: "string",
1012
+ desc: "business_concept, business_rule, asset_semantics, or calculation_convention."
1013
+ },
1014
+ { name: "title", type: "string", desc: "Edited title." },
1015
+ { name: "summary", type: "string", desc: "Edited summary." },
1016
+ { name: "content", type: "string", desc: "Edited content." },
1017
+ { name: "keywords", type: "json", desc: "Edited keyword array." },
1018
+ {
1019
+ name: "resource-refs",
1020
+ type: "json",
1021
+ desc: "Edited structured asset binding array."
1022
+ },
1023
+ {
1024
+ name: "request-id",
1025
+ type: "string",
1026
+ desc: "Optional idempotency key; generated when omitted.",
1027
+ maxLength: 128
1028
+ }
1029
+ ],
1030
+ risk: "write",
1031
+ buildInput: (ctx) => compactInput({
1032
+ project_id: ctx.num("project-id"),
1033
+ candidate_id: ctx.str("candidate-id"),
1034
+ expected_version: ctx.num("expected-version"),
1035
+ semantic_type: optionalString(ctx, "semantic-type"),
1036
+ title: optionalString(ctx, "title"),
1037
+ summary: optionalString(ctx, "summary"),
1038
+ content: optionalString(ctx, "content"),
1039
+ keywords: optionalJson(ctx, "keywords"),
1040
+ resource_refs: optionalJson(ctx, "resource-refs"),
1041
+ request_id: optionalString(ctx, "request-id")
1042
+ })
1043
+ });
1044
+
1045
+ // src/commands/project-semantic/release/list.ts
1046
+ var projectSemanticReleaseList = createProjectSemanticCommand({
1047
+ resource: "release",
1048
+ command: "list",
1049
+ capabilityId: "business_semantics.release.list",
1050
+ description: "List project semantic releases and the current release version.",
1051
+ flags: [
1052
+ { name: "project-id", type: "number", required: true, desc: "Numeric project ID.", alias: "p", min: 1 }
1053
+ ],
1054
+ risk: "read",
1055
+ buildInput: (ctx) => ({
1056
+ project_id: ctx.num("project-id")
1057
+ })
1058
+ });
1059
+
1060
+ // src/commands/project-semantic/release/publish.ts
1061
+ var projectSemanticReleasePublish = createProjectSemanticCommand({
1062
+ resource: "release",
1063
+ command: "publish",
1064
+ capabilityId: "business_semantics.release.publish",
1065
+ description: "Publish explicitly approved candidates into the project semantic catalog.",
1066
+ flags: [
1067
+ { name: "project-id", type: "number", required: true, desc: "Numeric project ID.", alias: "p", min: 1 },
1068
+ { name: "candidate-ids", type: "json", required: true, desc: "JSON array of approved candidate IDs." },
1069
+ { name: "expected-release-version", type: "number", required: true, desc: "Current release version, or 0 when no release exists.", min: 0 },
1070
+ { name: "publish-note", type: "string", desc: "Optional publication note." },
1071
+ { name: "request-id", type: "string", desc: "Optional idempotency key; generated when omitted.", maxLength: 128 }
1072
+ ],
1073
+ risk: "high-risk-write",
1074
+ validate: (ctx) => candidateIds2(ctx),
1075
+ buildInput: (ctx) => compactInput({
1076
+ project_id: ctx.num("project-id"),
1077
+ candidate_ids: candidateIds2(ctx),
1078
+ expected_release_version: ctx.num("expected-release-version"),
1079
+ publish_note: optionalString(ctx, "publish-note"),
1080
+ request_id: optionalString(ctx, "request-id")
1081
+ })
1082
+ });
1083
+ function candidateIds2(ctx) {
1084
+ const values = arrayValue(optionalJson(ctx, "candidate-ids"), "--candidate-ids");
1085
+ if (values.length < 1 || values.some((value) => typeof value !== "string" || value.trim() === "")) {
1086
+ throw new Error("--candidate-ids must be a non-empty JSON string array.");
1087
+ }
1088
+ return values;
1089
+ }
1090
+
1091
+ // src/commands/project-semantic/index.ts
1092
+ registerCapabilityGatewayRoute("project-semantic", {
1093
+ gatewayDomain: "analysis"
1094
+ });
1095
+ var commands = [
1096
+ projectSemanticList,
1097
+ projectSemanticGet,
1098
+ projectSemanticEnable,
1099
+ projectSemanticDisable,
1100
+ projectSemanticDeleteImpact,
1101
+ projectSemanticDelete,
1102
+ projectSemanticAssetPackageExport,
1103
+ projectSemanticCandidateValidate,
1104
+ projectSemanticCandidateSubmit,
1105
+ projectSemanticCandidateEnable,
1106
+ projectSemanticCandidateList,
1107
+ projectSemanticCandidateGet,
1108
+ projectSemanticCandidateEdit,
1109
+ projectSemanticReleaseList,
1110
+ projectSemanticReleasePublish
1111
+ ];
1112
+ var project_semantic_default = commands;
1113
+ export {
1114
+ project_semantic_default as default
1115
+ };