@thinkingai/ae-cli 6.0.52 → 6.0.54

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 (185) hide show
  1. package/README.md +35 -10
  2. package/README.zh.md +32 -10
  3. package/bin/ae-cli.js +6 -1
  4. package/cli-installation-guide.md +91 -0
  5. package/dist/{auth-XZNXFRJS.js → auth-MBWRZTB6.js} +171 -13
  6. package/dist/automation-NWWVLWG2.js +459 -0
  7. package/dist/{capability-RJZ4KRGP.js → capability-7SSN6PNZ.js} +11 -6
  8. package/dist/chunk-4655PUNX.js +43 -0
  9. package/dist/{chunk-4NRCTUZJ.js → chunk-5XJYLEVC.js} +4 -4
  10. package/dist/{chunk-JOCDD4ON.js → chunk-7QXISROD.js} +1 -1
  11. package/dist/{chunk-EQ255HKO.js → chunk-AP7YP2NX.js} +2 -2
  12. package/dist/{chunk-DVMLWQD4.js → chunk-CT7QDJS6.js} +2 -2
  13. package/dist/chunk-D6ACFILC.js +56 -0
  14. package/dist/{chunk-HFGZGYCG.js → chunk-EOYSKMXN.js} +264 -10
  15. package/dist/{chunk-57RRFUEZ.js → chunk-FMNNGNYO.js} +43 -8
  16. package/dist/{chunk-7XGFSUOM.js → chunk-GIK6EDUG.js} +291 -84
  17. package/dist/{chunk-WEPZ5M3Z.js → chunk-HBLK3ZHW.js} +7 -4
  18. package/dist/chunk-HVHR4SCP.js +133 -0
  19. package/dist/{chunk-DX5CDO34.js → chunk-KFNMQTZI.js} +580 -214
  20. package/dist/{chunk-HBGADCKA.js → chunk-PLE722AJ.js} +28 -11
  21. package/dist/chunk-RK6GLDGI.js +27 -0
  22. package/dist/{chunk-V2NUHPXF.js → chunk-S6M42KND.js} +1 -1
  23. package/dist/{chunk-7FTTULED.js → chunk-UQ77JXYH.js} +7 -3
  24. package/dist/{chunk-MAPZ7VB6.js → chunk-WNGFSIOB.js} +20 -1
  25. package/dist/{chunk-L2QUIZTS.js → chunk-ZIQWCZTS.js} +3 -3
  26. package/dist/{community-report-client-CU22W53K.js → community-report-client-PEERQCX2.js} +1 -1
  27. package/dist/{config-XO3LI3SA.js → config-FF6YVJKI.js} +29 -10
  28. package/dist/context-YAE3QXP3.js +136 -0
  29. package/dist/{data-integration-HNGUKFIC.js → data-integration-HESZET7E.js} +6 -6
  30. package/dist/index.js +169 -55
  31. package/dist/{local-data-upload-client-GTRIT64F.js → local-data-upload-client-TWMHFLUA.js} +1 -1
  32. package/dist/memory-62BJOULV.js +580 -0
  33. package/dist/{metadata-JAQW7KGZ.js → metadata-7CUMWIB4.js} +7 -7
  34. package/dist/{model-RNPQXIBI.js → model-SBV2JFJI.js} +9 -5
  35. package/dist/{personal-semantic-preference-QCZ2IZTK.js → personal-semantic-preference-6SRCYPGE.js} +119 -11
  36. package/dist/{project-semantic-64JURXKF.js → project-semantic-YYEM4OSU.js} +7 -7
  37. package/dist/{sync-O45NXEQY.js → sync-SU33KYX7.js} +12 -8
  38. package/dist/{te-agent-K5MSPNHJ.js → te-agent-F5QBZSQA.js} +423 -494
  39. package/dist/{te-analysis-KQKCAI5H.js → te-analysis-U4I2W2WC.js} +1090 -67
  40. package/dist/{te-community-4OYU3BDA.js → te-community-PFLDLPP4.js} +3 -3
  41. package/dist/{te-dataops-NFIPB6FX.js → te-dataops-FOQSRIAZ.js} +644 -276
  42. package/dist/{te-engage-HSVSRW22.js → te-engage-ZX76CNAB.js} +6 -6
  43. package/dist/{te-kb-3TS73NO6.js → te-kb-MHDOST62.js} +666 -244
  44. package/dist/{te-system-STMHLS5J.js → te-system-J2FQF5ER.js} +6 -6
  45. package/dist/{te-team-3I5AOX3N.js → te-team-5UOZPTU3.js} +6 -6
  46. package/dist/things-VPPXXLHB.js +1091 -0
  47. package/dist/{update-RZXLPCRH.js → update-EEUTEI6R.js} +59 -51
  48. package/dist/workspace-O3EEIYQM.js +554 -0
  49. package/package.json +30 -11
  50. package/skills/ae-agent/SKILL.md +95 -140
  51. package/skills/ae-agent/references/add-model.md +1 -1
  52. package/skills/ae-agent/references/create-agent.md +1 -1
  53. package/skills/ae-agent/references/find-archived-conversations.md +12 -5
  54. package/skills/ae-agent/references/get-agent.md +1 -1
  55. package/skills/ae-agent/references/list-agents.md +2 -2
  56. package/skills/ae-agent/references/list-models.md +2 -2
  57. package/skills/ae-agent/references/notification.md +40 -0
  58. package/skills/ae-agent/references/restore-conversation.md +3 -1
  59. package/skills/ae-analysis/SKILL.md +76 -15
  60. package/skills/ae-analysis/references/agent_review_submit_to_page.md +2 -0
  61. package/skills/ae-analysis/references/ai_models/event.md +6 -1
  62. package/skills/ae-analysis/references/ai_models/funnel.md +12 -4
  63. package/skills/ae-analysis/references/ai_models/heat_map.md +23 -0
  64. package/skills/ae-analysis/references/ai_models/interval.md +24 -0
  65. package/skills/ae-analysis/references/ai_models/path.md +20 -0
  66. package/skills/ae-analysis/references/ai_models/prop_analysis.md +2 -0
  67. package/skills/ae-analysis/references/ai_models/rank_list.md +30 -0
  68. package/skills/ae-analysis/references/ai_models/retention.md +45 -1
  69. package/skills/ae-analysis/references/ai_models/revenue.md +20 -2
  70. package/skills/ae-analysis/references/ai_models/tag.md +2 -0
  71. package/skills/ae-analysis/references/ai_models.md +96 -0
  72. package/skills/ae-analysis/references/analysis_data_retrieval.md +4 -0
  73. package/skills/ae-analysis/references/asset_batch_info_export.md +10 -0
  74. package/skills/ae-analysis/references/asset_batch_sql_export.md +13 -1
  75. package/skills/ae-analysis/references/asset_export.md +12 -1
  76. package/skills/ae-analysis/references/asset_list.md +1 -0
  77. package/skills/ae-analysis/references/asset_search.md +11 -5
  78. package/skills/ae-analysis/references/bi_panel_list.md +1 -1
  79. package/skills/ae-analysis/references/catalog_list.md +1 -1
  80. package/skills/ae-analysis/references/collaboration.md +48 -0
  81. package/skills/ae-analysis/references/command_index.md +26 -17
  82. package/skills/ae-analysis/references/dashboard_list.md +4 -4
  83. package/skills/ae-analysis/references/dashboard_move.md +21 -0
  84. package/skills/ae-analysis/references/dashboard_report_add.md +2 -0
  85. package/skills/ae-analysis/references/dashboard_report_data_export.md +2 -0
  86. package/skills/ae-analysis/references/dashboard_report_get.md +19 -0
  87. package/skills/ae-analysis/references/dashboard_report_update.md +27 -0
  88. package/skills/ae-analysis/references/dashboard_update.md +1 -1
  89. package/skills/ae-analysis/references/event_export.md +3 -1
  90. package/skills/ae-analysis/references/event_report_presentation.md +76 -0
  91. package/skills/ae-analysis/references/feedback_submit.md +37 -0
  92. package/skills/ae-analysis/references/governance_recommendation_auto_review.md +71 -0
  93. package/skills/ae-analysis/references/governance_recommendation_export.md +11 -0
  94. package/skills/ae-analysis/references/metadata_resolution.md +18 -3
  95. package/skills/ae-analysis/references/metric_export.md +3 -1
  96. package/skills/ae-analysis/references/metric_list.md +1 -1
  97. package/skills/ae-analysis/references/operation_record_export.md +10 -0
  98. package/skills/ae-analysis/references/personal_semantic_preference_add.md +2 -2
  99. package/skills/ae-analysis/references/personal_semantic_preference_get.md +6 -4
  100. package/skills/ae-analysis/references/personal_semantic_preference_list.md +5 -3
  101. package/skills/ae-analysis/references/personal_semantic_preference_review.md +9 -0
  102. package/skills/ae-analysis/references/personal_semantic_preference_review_list.md +7 -0
  103. package/skills/ae-analysis/references/personal_semantic_preference_submit.md +7 -0
  104. package/skills/ae-analysis/references/project_semantic_knowledge_wiki.md +91 -32
  105. package/skills/ae-analysis/references/project_semantic_knowledge_wiki_plan_schema.md +99 -1
  106. package/skills/ae-analysis/references/property_export.md +3 -1
  107. package/skills/ae-analysis/references/report_create.md +17 -3
  108. package/skills/ae-analysis/references/report_data_export.md +6 -0
  109. package/skills/ae-analysis/references/report_get.md +7 -1
  110. package/skills/ae-analysis/references/report_list.md +5 -5
  111. package/skills/ae-analysis/references/report_update.md +20 -3
  112. package/skills/ae-analysis/references/sql_table_columns.md +4 -4
  113. package/skills/ae-analysis/references/sql_table_list.md +5 -5
  114. package/skills/ae-analysis/references/system_query_monitor_overview.md +2 -0
  115. package/skills/ae-analysis/references/system_query_task_cancel.md +2 -0
  116. package/skills/ae-analysis/references/system_query_task_export.md +6 -2
  117. package/skills/ae-analysis/references/system_query_task_get.md +2 -0
  118. package/skills/ae-analysis/references/system_query_task_list.md +7 -3
  119. package/skills/ae-analysis/references/system_query_task_options.md +2 -2
  120. package/skills/ae-analysis/references/system_query_task_realtime_list.md +15 -0
  121. package/skills/ae-analysis/references/user_cluster_models.md +8 -0
  122. package/skills/ae-analysis/references/user_tag_create.md +7 -1
  123. package/skills/ae-analysis/references/user_tag_get.md +1 -1
  124. package/skills/ae-analysis/references/user_tag_models.md +20 -2
  125. package/skills/ae-analysis/references/user_tag_refresh.md +1 -1
  126. package/skills/ae-analysis/references/user_tag_update.md +2 -2
  127. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/build-empty-skeleton.mjs +105 -0
  128. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/build-project-semantic-wiki.mjs +669 -29
  129. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/company-kb.mjs +21 -8
  130. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/default-compile-rules.md +28 -10
  131. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/default-compile-schema.md +66 -0
  132. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/generate-build-ir.mjs +285 -24
  133. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/package-wiki-source-zip.mjs +262 -30
  134. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/plan-kb-source-sync.mjs +1 -1
  135. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/precompiled-source.mjs +46 -2
  136. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/prepare-compile-schema.mjs +64 -0
  137. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/refresh-state-parts.mjs +91 -0
  138. package/skills/ae-automation/SKILL.md +16 -0
  139. package/skills/ae-automation/references/cli.md +53 -0
  140. package/skills/ae-automation/references/command_index.md +17 -0
  141. package/skills/ae-capability/SKILL.md +73 -2
  142. package/skills/ae-capability/references/collaboration.md +48 -0
  143. package/skills/ae-community/SKILL.md +5 -1
  144. package/skills/ae-community/references/collaboration.md +48 -0
  145. package/skills/ae-current-context/SKILL.md +3 -2
  146. package/skills/ae-data-integration/SKILL.md +4 -0
  147. package/skills/ae-data-integration/references/collaboration.md +48 -0
  148. package/skills/ae-dataops/SKILL.md +54 -74
  149. package/skills/ae-dataops/references/collaboration.md +48 -0
  150. package/skills/ae-dataops/references/dataops-backfill.md +23 -18
  151. package/skills/ae-dataops/references/dataops-flow-create.md +74 -23
  152. package/skills/ae-dataops/references/dataops-flow-monitor.md +45 -13
  153. package/skills/ae-dataops/references/dataops-integration.md +57 -30
  154. package/skills/ae-dataops/references/dataops-query.md +21 -4
  155. package/skills/ae-dataops/references/dataops-table.md +143 -11
  156. package/skills/ae-engage/SKILL.md +21 -6
  157. package/skills/ae-engage/references/channel-mgmt.md +3 -3
  158. package/skills/ae-engage/references/collaboration.md +48 -0
  159. package/skills/ae-engage/references/scene-config-channel.md +4 -4
  160. package/skills/ae-generate-tracking-plan/SKILL.md +4 -0
  161. package/skills/ae-generate-tracking-plan/references/collaboration.md +48 -0
  162. package/skills/ae-kb/SKILL.md +70 -12
  163. package/skills/ae-kb/references/analysis-workflow.md +73 -36
  164. package/skills/ae-kb/references/collaboration.md +48 -0
  165. package/skills/ae-kb/references/query-workflow.md +67 -33
  166. package/skills/ae-kb/references/schema-import.md +32 -0
  167. package/skills/ae-kb/references/source-mutations.md +6 -4
  168. package/skills/ae-kb/references/text-sources.md +53 -0
  169. package/skills/ae-kb-discovery/SKILL.md +8 -3
  170. package/skills/ae-kb-discovery/references/collaboration.md +48 -0
  171. package/skills/ae-metadata/SKILL.md +20 -12
  172. package/skills/ae-metadata/references/collaboration.md +48 -0
  173. package/skills/ae-team/SKILL.md +23 -17
  174. package/skills/ae-things/SKILL.md +85 -0
  175. package/skills/ae-things/references/cli.md +103 -0
  176. package/skills/ae-things-progress/SKILL.md +43 -0
  177. package/skills/ae-things-review/SKILL.md +42 -0
  178. package/skills/ae-workspace/SKILL.md +43 -0
  179. package/skills/ae-workspace/references/commands.md +51 -0
  180. package/dist/chunk-E2JKXMVO.js +0 -29
  181. package/dist/context-IFJI3LIT.js +0 -46
  182. package/dist/memory-QGPSNCQS.js +0 -892
  183. package/skills/ae-agent/references/create-automation.md +0 -125
  184. package/skills/ae-agent/references/list-automations.md +0 -56
  185. package/skills/ae-agent/references/update-automation.md +0 -107
@@ -7,12 +7,12 @@ import {
7
7
  waitForAnalysisRun,
8
8
  withAsyncArtifactLifecycle,
9
9
  withInterruptSignal
10
- } from "./chunk-WEPZ5M3Z.js";
10
+ } from "./chunk-HBLK3ZHW.js";
11
11
  import {
12
12
  createCapabilityCommand,
13
13
  definitionIntentSnapshotFlag,
14
14
  modelDefinitionIntentSnapshotFlag
15
- } from "./chunk-L2QUIZTS.js";
15
+ } from "./chunk-ZIQWCZTS.js";
16
16
  import {
17
17
  registerCapabilityGatewayRoute,
18
18
  resolveGatewayDomain
@@ -23,22 +23,25 @@ import {
23
23
  dryRunCapability,
24
24
  executeCapability,
25
25
  executeCapabilityWithEnvelope,
26
+ readCliAgentContext,
26
27
  requestCapabilityGateway,
27
28
  requestCapabilityGatewayWithEnvelope,
29
+ runWithCliAgentContext,
28
30
  uploadInputFile,
29
- validateCapability
30
- } from "./chunk-HFGZGYCG.js";
31
+ validateCapability,
32
+ validateCapabilityWithEnvelope
33
+ } from "./chunk-EOYSKMXN.js";
31
34
  import {
32
35
  withOutputMetadata
33
- } from "./chunk-DX5CDO34.js";
36
+ } from "./chunk-KFNMQTZI.js";
34
37
  import "./chunk-Y74WTIKJ.js";
35
38
  import {
36
39
  getCliToken
37
- } from "./chunk-7XGFSUOM.js";
38
- import "./chunk-7FTTULED.js";
40
+ } from "./chunk-GIK6EDUG.js";
41
+ import "./chunk-UQ77JXYH.js";
39
42
  import {
40
43
  CliValidationError
41
- } from "./chunk-MAPZ7VB6.js";
44
+ } from "./chunk-WNGFSIOB.js";
42
45
 
43
46
  // src/commands/te-analysis/capability-shared.ts
44
47
  var ANALYSIS_GATEWAY_CLI_SERVICES = /* @__PURE__ */ new Set(["project", "system"]);
@@ -148,7 +151,7 @@ var sqlTableUsageFlag = {
148
151
  name: "usage",
149
152
  type: "string",
150
153
  required: false,
151
- desc: "Authorized table set: analysis (default) or tag_cluster. Use tag_cluster before creating SQL tags or clusters."
154
+ desc: "Authorized table set: analysis (default), tag_cluster for SQL tags/clusters, or sql_datatable for SQL-built data tables. Use the same usage for list and columns."
152
155
  };
153
156
  var reportListLimitFlag = {
154
157
  name: "limit",
@@ -288,7 +291,7 @@ function certificationScopeInput(ctx) {
288
291
  }
289
292
  return value;
290
293
  }
291
- function dashboardReportDataInput(ctx) {
294
+ function dashboardReportDataInput(ctx, includeCache = true) {
292
295
  return compactInput({
293
296
  ...projectInput(ctx),
294
297
  dashboard_id: ctx.num("dashboard-id"),
@@ -299,7 +302,7 @@ function dashboardReportDataInput(ctx) {
299
302
  cluster_query_scope: optionalString(ctx, "cluster-query-scope"),
300
303
  slave_cluster_id: optionalString(ctx, "slave-cluster-id"),
301
304
  zone_offset: optionalNumber(ctx, "zone-offset"),
302
- use_cache: optionalBoolean(ctx, "use-cache"),
305
+ ...includeCache ? { use_cache: optionalBoolean(ctx, "use-cache") } : {},
303
306
  request_id: optionalString(ctx, "request-id"),
304
307
  preview_rows: optionalNumber(ctx, "preview-rows"),
305
308
  timeout_seconds: optionalNumber(ctx, "timeout-seconds"),
@@ -756,6 +759,7 @@ var metadataEventExport = createAnalysisMetaCapabilityCommand({
756
759
  queriesFlag,
757
760
  fieldsFlag,
758
761
  { name: "authenticated-only", type: "boolean", required: false, desc: "When true, export only authenticated events." },
762
+ certificationScopeFlag,
759
763
  metadataExportOutputFlag
760
764
  ],
761
765
  risk: "read",
@@ -764,7 +768,8 @@ var metadataEventExport = createAnalysisMetaCapabilityCommand({
764
768
  ...projectInput(ctx),
765
769
  queries: optionalQueries(ctx),
766
770
  fields: optionalJson(ctx, "fields"),
767
- authenticated_only: optionalBoolean(ctx, "authenticated-only")
771
+ authenticated_only: optionalBoolean(ctx, "authenticated-only"),
772
+ certification_scope: certificationScopeInput(ctx)
768
773
  }),
769
774
  postProcess: metadataExportPostProcess("event", "events")
770
775
  });
@@ -947,6 +952,7 @@ var metadataPropertyExport = createAnalysisMetaCapabilityCommand({
947
952
  queriesFlag,
948
953
  fieldsFlag,
949
954
  { name: "authenticated-only", type: "boolean", required: false, desc: "When true, export only authenticated properties." },
955
+ certificationScopeFlag,
950
956
  metadataExportOutputFlag
951
957
  ],
952
958
  risk: "read",
@@ -958,7 +964,8 @@ var metadataPropertyExport = createAnalysisMetaCapabilityCommand({
958
964
  event_name: optionalString(ctx, "event-name"),
959
965
  queries: optionalQueries(ctx),
960
966
  fields: optionalJson(ctx, "fields"),
961
- authenticated_only: optionalBoolean(ctx, "authenticated-only")
967
+ authenticated_only: optionalBoolean(ctx, "authenticated-only"),
968
+ certification_scope: certificationScopeInput(ctx)
962
969
  }),
963
970
  postProcess: metadataExportPostProcess("property", "properties")
964
971
  });
@@ -1350,6 +1357,7 @@ var metadataMetricExport = createAnalysisMetaCapabilityCommand({
1350
1357
  queriesFlag,
1351
1358
  fieldsFlag,
1352
1359
  { name: "authenticated-only", type: "boolean", required: false, desc: "When true, export only authenticated metrics." },
1360
+ certificationScopeFlag,
1353
1361
  metadataExportOutputFlag
1354
1362
  ],
1355
1363
  risk: "read",
@@ -1359,7 +1367,8 @@ var metadataMetricExport = createAnalysisMetaCapabilityCommand({
1359
1367
  ignore_authentication: optionalBoolean(ctx, "ignore-authentication"),
1360
1368
  queries: optionalQueries(ctx),
1361
1369
  fields: optionalJson(ctx, "fields"),
1362
- authenticated_only: optionalBoolean(ctx, "authenticated-only")
1370
+ authenticated_only: optionalBoolean(ctx, "authenticated-only"),
1371
+ certification_scope: certificationScopeInput(ctx)
1363
1372
  }),
1364
1373
  postProcess: metadataExportPostProcess("metric", "metrics")
1365
1374
  });
@@ -1500,13 +1509,13 @@ var ownTypesFlag = {
1500
1509
  var requiredQueriesFlag = {
1501
1510
  ...queriesFlag,
1502
1511
  required: true,
1503
- desc: "Required JSON array of 1 to 20 keyword filters. For first-pass asset discovery, use one broad search without --asset-types so results can include both dashboards and reports."
1512
+ desc: "Required JSON array of 1 to 20 keyword filters. For first-pass asset discovery, use one broad search without --asset-types and request a large page; when has_more is true and no strong candidate is present, continue with next_offset before narrowing or rewriting keywords."
1504
1513
  };
1505
1514
  var analysisAssetSearch = createAnalysisCapabilityCommand({
1506
1515
  resource: "asset",
1507
1516
  command: "search",
1508
1517
  capabilityId: "analysis.asset.search",
1509
- description: "Search visible saved analysis assets by keyword. Default first-pass search should omit --asset-types to cover both dashboards and reports.",
1518
+ description: "Search readable saved analysis assets by keyword, including shared read-only and editable dashboards and reports. Results are ranked before pagination by match quality, certification, recent heat/users, and governance impact. Omit --asset-types for first-pass discovery.",
1510
1519
  flags: [
1511
1520
  projectIdFlag,
1512
1521
  requiredQueriesFlag,
@@ -1635,7 +1644,16 @@ var statusFlag = { name: "status", type: "json", required: false, desc: "Operati
1635
1644
  var sortFieldFlag = { name: "sort-field", type: "string", required: false, desc: "Sort field." };
1636
1645
  var sortOrderFlag = { name: "sort-order", type: "string", required: false, desc: "Sort order: asc or desc." };
1637
1646
  var recordIdFlag = { name: "record-id", type: "number", required: false, desc: "Operation record ID." };
1647
+ var governanceExportFlags = (format) => [
1648
+ requestIdFlag,
1649
+ { ...artifactFormatFlag, desc: `Artifact format: ${format}. This capability supports only ${format}.` },
1650
+ { ...asyncTimeoutSecondsFlag, max: 7200, desc: "Async export runtime in seconds. Default: 3600, max: 7200." }
1651
+ ];
1652
+ var governanceExportFields = ["request_id", "format", "timeout_seconds"];
1638
1653
  var readers = {
1654
+ request_id: (ctx) => optionalString(ctx, "request-id"),
1655
+ format: (ctx) => optionalString(ctx, "artifact-format"),
1656
+ timeout_seconds: (ctx) => optionalNumber(ctx, "timeout-seconds"),
1639
1657
  node_id: (ctx) => optionalString(ctx, "node-id"),
1640
1658
  resource_id: (ctx) => optionalString(ctx, "resource-id"),
1641
1659
  resource_type: (ctx) => optionalString(ctx, "resource-type"),
@@ -2238,6 +2256,722 @@ var metadataGovernanceRecommendationSubmit = createAnalysisMetaCapabilityCommand
2238
2256
  })
2239
2257
  });
2240
2258
 
2259
+ // src/commands/te-analysis/meta/governance-recommendation/auto-review.ts
2260
+ import { randomUUID } from "crypto";
2261
+ var windowDaysFlag3 = {
2262
+ name: "window-days",
2263
+ type: "number",
2264
+ required: false,
2265
+ min: 1,
2266
+ max: 365,
2267
+ desc: "Usage window in days for the recommendation batch. Default: 90."
2268
+ };
2269
+ var limitFlag4 = {
2270
+ name: "limit",
2271
+ type: "number",
2272
+ required: false,
2273
+ min: 1,
2274
+ max: 100,
2275
+ desc: "Maximum hot dashboard evidence packages selected before automatic asset review. Omit for CLI bounded expansion over top-20/top-50/top-100; pass explicitly for a fixed diagnostic scope."
2276
+ };
2277
+ var GOVERNANCE_RECOMMENDATION_AUTO_REVIEW_HELP = [
2278
+ "Automatic asset certification contract:",
2279
+ "- Use this command only when the user explicitly asks to automatically review or automatically certify recommended assets.",
2280
+ "- Do not call this command for a plain recommendation request.",
2281
+ "- Do not call this command when the user asks to submit recommendations to the review page.",
2282
+ "- The command first validates project config agent_auto_asset_certification_enabled and project_semantic_enable. If disabled, report the returned config error and stop before collecting recommendations.",
2283
+ "- When --limit is omitted, the CLI performs the same bounded expansion used by recurring page-review jobs: inspect top-20 pending material, then top-50/top-100 only when pending assets or pending dashboard branches are insufficient.",
2284
+ "- Expansion is read-only. The CLI Agent builds automatic decisions once from the final selected material, then submits those decisions for execution and audit.",
2285
+ "- When --limit is explicitly provided, respect that scope and do not expand it.",
2286
+ "- Automatic review only certifies eligible asset candidates from the current recommendation batch. It does not create recommended metrics.",
2287
+ "- CLI Agent blocks semantic duplicates, copy-like assets, synonym properties and ambiguous close definitions; every duplicate skip must name the conflicting asset targets.",
2288
+ "- The result includes manual_review_handoff for assets still uncertified after automatic review. Use it only when the user later asks to submit those assets to the review page.",
2289
+ "- For that later page submission, build the review packet from manual_review_handoff.page_review_items and relations so skipped assets keep their dashboard/report parent context; manual_review_handoff.items remains the exact unapproved review workload.",
2290
+ "- Automatic decisions are recorded for audit. Page-visible reasons must be reviewer-readable Chinese; keep raw source/rule codes only in debug exports.",
2291
+ "- Returned SKIP decisions mean the asset remains for manual review; do not describe skipped items as certified."
2292
+ ].join("\n");
2293
+ var AUTO_REVIEW_CAPABILITY_ID = "metadata.governance_recommendation.auto_review";
2294
+ var EXPORT_CAPABILITY_ID = "metadata.governance_recommendation.export";
2295
+ var SUBMIT_CAPABILITY_ID = "metadata.governance_recommendation.submit";
2296
+ var DEFAULT_LIMIT = 20;
2297
+ var EXPANSION_LIMITS = [20, 50, 100];
2298
+ var MIN_PENDING_ASSETS = 10;
2299
+ var MIN_PENDING_WORK_UNITS = 3;
2300
+ var AUTO_REVIEW_DECISION_LIMIT = 100;
2301
+ var AUTO_REVIEW_MIN_HEAT = 50;
2302
+ var AUTO_REVIEW_MIN_USERS = 5;
2303
+ var AUTO_REVIEW_MIN_IMPACT = 2;
2304
+ var metadataGovernanceRecommendationAutoReview = {
2305
+ service: "analysis-meta",
2306
+ resource: "governance-recommendation",
2307
+ command: "auto-review",
2308
+ capabilityId: AUTO_REVIEW_CAPABILITY_ID,
2309
+ description: "Automatically review and certify eligible recommended assets when the project switch is enabled.",
2310
+ helpText: GOVERNANCE_RECOMMENDATION_AUTO_REVIEW_HELP,
2311
+ flags: [projectIdFlag, windowDaysFlag3, limitFlag4],
2312
+ risk: "write",
2313
+ preflight: (ctx) => {
2314
+ autoReviewInput(ctx);
2315
+ },
2316
+ validateInput: async (ctx) => validateCapability(
2317
+ ctx.host(),
2318
+ gatewayDomain(),
2319
+ AUTO_REVIEW_CAPABILITY_ID,
2320
+ autoReviewInput(ctx)
2321
+ ),
2322
+ dryRun: async (ctx) => dryRunCapability(
2323
+ ctx.host(),
2324
+ gatewayDomain(),
2325
+ AUTO_REVIEW_CAPABILITY_ID,
2326
+ autoReviewInput(ctx)
2327
+ ),
2328
+ execute: async (ctx) => withAutoReviewAgentContext(async () => {
2329
+ const input = autoReviewInput(ctx);
2330
+ if (hasExplicitLimit(ctx)) {
2331
+ await validateCapabilityWithEnvelope(ctx.host(), gatewayDomain(), AUTO_REVIEW_CAPABILITY_ID, input);
2332
+ const finalExport = await exportRecommendationMaterial(ctx, input, numberValue(input.limit) || DEFAULT_LIMIT);
2333
+ const result2 = await executeCliAgentAutoReview(ctx, input, finalExport.data);
2334
+ return withOutputMetadata({
2335
+ ...record(result2.data),
2336
+ manual_review_handoff: buildManualReviewHandoff(result2.data, finalExport.data)
2337
+ }, result2.meta);
2338
+ }
2339
+ const plan = await planBoundedExpansion(ctx, input);
2340
+ const expansion = plan.expansion;
2341
+ const finalInput = { ...input, limit: expansion.final_limit };
2342
+ const result = await executeCliAgentAutoReview(ctx, finalInput, plan.finalExport);
2343
+ if (result.data && typeof result.data === "object" && !Array.isArray(result.data)) {
2344
+ return withOutputMetadata({
2345
+ ...result.data,
2346
+ auto_review_expansion: expansion,
2347
+ manual_review_handoff: buildManualReviewHandoff(result.data, plan.finalExport)
2348
+ }, result.meta);
2349
+ }
2350
+ return withOutputMetadata(result.data, result.meta);
2351
+ })
2352
+ };
2353
+ async function withAutoReviewAgentContext(run) {
2354
+ const inherited = readCliAgentContext();
2355
+ return runWithCliAgentContext({
2356
+ agent_session_id: inherited.agent_session_id || randomUUID(),
2357
+ agent_turn_id: inherited.agent_turn_id || randomUUID()
2358
+ }, run);
2359
+ }
2360
+ function autoReviewInput(ctx) {
2361
+ return compactInput({
2362
+ ...projectInput(ctx),
2363
+ window_days: optionalNumber(ctx, "window-days"),
2364
+ limit: optionalNumber(ctx, "limit")
2365
+ });
2366
+ }
2367
+ function gatewayDomain() {
2368
+ return resolveGatewayDomain("analysis-meta", "analysis");
2369
+ }
2370
+ function hasExplicitLimit(ctx) {
2371
+ return typeof ctx.has === "function" ? ctx.has("limit") : ctx.str("limit") !== "";
2372
+ }
2373
+ async function executeCliAgentAutoReview(ctx, input, exportResult) {
2374
+ const review = buildCliAgentAutoReview(input, exportResult);
2375
+ if (review.decisions.length === 0) {
2376
+ return {
2377
+ data: {
2378
+ ...review.base,
2379
+ total: 0,
2380
+ applied: 0,
2381
+ recorded: 0,
2382
+ failed: 0,
2383
+ items: []
2384
+ },
2385
+ meta: {}
2386
+ };
2387
+ }
2388
+ const submitted = await executeCapabilityWithEnvelope(ctx.host(), gatewayDomain(), SUBMIT_CAPABILITY_ID, {
2389
+ ...input,
2390
+ run_id: review.runId,
2391
+ snapshot_hash: review.snapshotHash,
2392
+ topic_id: "agent_auto_asset_certification",
2393
+ topic_name: "Agent \u81EA\u52A8\u8BA4\u8BC1\u8D44\u4EA7",
2394
+ decisions: review.decisions
2395
+ });
2396
+ const submittedData = record(submitted.data);
2397
+ return {
2398
+ data: {
2399
+ ...review.base,
2400
+ total: submittedData.total,
2401
+ applied: submittedData.applied,
2402
+ recorded: submittedData.recorded,
2403
+ failed: submittedData.failed,
2404
+ items: autoReviewItemsWithDisplayReason(submittedData.items)
2405
+ },
2406
+ meta: submitted.meta
2407
+ };
2408
+ }
2409
+ async function planBoundedExpansion(ctx, input) {
2410
+ await validateCapabilityWithEnvelope(ctx.host(), gatewayDomain(), AUTO_REVIEW_CAPABILITY_ID, {
2411
+ ...input,
2412
+ limit: DEFAULT_LIMIT
2413
+ });
2414
+ const attempts = [];
2415
+ let finalExport = {};
2416
+ let finalLimit = DEFAULT_LIMIT;
2417
+ let stopReason = "top_100_inspected";
2418
+ for (const limit of EXPANSION_LIMITS) {
2419
+ const exported = await exportRecommendationMaterial(ctx, input, limit);
2420
+ finalExport = exported.data;
2421
+ const summary = summarizeExport(exported.data, limit);
2422
+ attempts.push(summary);
2423
+ finalLimit = limit;
2424
+ const pendingAssets = numberValue(summary.pending_asset_candidates);
2425
+ const pendingWorkUnits = numberValue(summary.pending_work_units);
2426
+ const hasMore = summary.has_more === true;
2427
+ if (pendingAssets >= MIN_PENDING_ASSETS && pendingWorkUnits >= MIN_PENDING_WORK_UNITS) {
2428
+ stopReason = "sufficient_pending_scope";
2429
+ break;
2430
+ }
2431
+ if (!hasMore) {
2432
+ stopReason = "dashboard_pool_exhausted";
2433
+ break;
2434
+ }
2435
+ }
2436
+ return {
2437
+ expansion: {
2438
+ strategy: "bounded_hot_dashboard_expansion",
2439
+ initial_limit: DEFAULT_LIMIT,
2440
+ final_limit: finalLimit,
2441
+ inspected_limits: attempts.map((attempt) => attempt.dashboard_limit),
2442
+ min_pending_asset_candidates: MIN_PENDING_ASSETS,
2443
+ min_pending_work_units: MIN_PENDING_WORK_UNITS,
2444
+ attempts,
2445
+ stop_reason: stopReason,
2446
+ write_policy: "single_auto_review_execute_after_read_only_expansion"
2447
+ },
2448
+ finalExport
2449
+ };
2450
+ }
2451
+ function exportRecommendationMaterial(ctx, input, limit) {
2452
+ return executeCapabilityWithEnvelope(
2453
+ ctx.host(),
2454
+ gatewayDomain(),
2455
+ EXPORT_CAPABILITY_ID,
2456
+ compactInput({ ...input, limit, include_completed: false })
2457
+ );
2458
+ }
2459
+ function summarizeExport(result, requestedLimit) {
2460
+ const data = record(result);
2461
+ const workUnits = array(data.work_units);
2462
+ const coverage = record(data.coverage);
2463
+ const pendingAssetCandidates = countPendingAssetCandidates(workUnits);
2464
+ return {
2465
+ dashboard_limit: numberValue(data.dashboard_limit) || requestedLimit,
2466
+ run_id: stringValue(data.run_id),
2467
+ snapshot_hash: stringValue(data.snapshot_hash),
2468
+ selected_dashboards: numberValue(coverage.selected_dashboards),
2469
+ returned_work_units: workUnits.length,
2470
+ pending_work_units: workUnits.filter((unit) => numberValue(record(unit).actionable_count) > 0).length,
2471
+ pending_asset_candidates: pendingAssetCandidates,
2472
+ has_more: coverage.has_more === true
2473
+ };
2474
+ }
2475
+ function countPendingAssetCandidates(workUnits) {
2476
+ const seen = /* @__PURE__ */ new Set();
2477
+ for (const unit of workUnits) {
2478
+ for (const candidate of array(record(unit).asset_candidates)) {
2479
+ const item = record(candidate);
2480
+ if (item.actionable !== true || item.action_state !== "PENDING") {
2481
+ continue;
2482
+ }
2483
+ const type = stringValue(item.resource_type);
2484
+ const key = stringValue(item.resource_key);
2485
+ if (type && key) {
2486
+ seen.add(`${type}|${key}`);
2487
+ }
2488
+ }
2489
+ }
2490
+ return seen.size;
2491
+ }
2492
+ function buildCliAgentAutoReview(input, exportResult) {
2493
+ const exported = record(exportResult);
2494
+ const material = record(exported.review_material_package);
2495
+ const candidates = array(material.candidate_assets).map(record);
2496
+ const runId = `rec_auto_${randomUUID().replace(/-/g, "")}`;
2497
+ const snapshotHash = stringValue(exported.snapshot_hash);
2498
+ const semanticConflicts = semanticDuplicateConflicts(candidates);
2499
+ const decisions = [];
2500
+ let approved = 0;
2501
+ let skipped = 0;
2502
+ let overflow = 0;
2503
+ const seen = /* @__PURE__ */ new Set();
2504
+ for (const candidate of candidates) {
2505
+ const target = record(candidate.target_ref);
2506
+ const type = stringValue(target.type);
2507
+ const key = stringValue(target.key);
2508
+ if (!type || !key || !seen.add(`${type}|${key}`)) continue;
2509
+ if (candidate.actionable !== true || candidate.action_state !== "PENDING") continue;
2510
+ if (decisions.length >= AUTO_REVIEW_DECISION_LIMIT) {
2511
+ overflow++;
2512
+ continue;
2513
+ }
2514
+ const verdict = cliAgentAutoReviewVerdict(candidate, semanticConflicts.get(`${type}|${key}`));
2515
+ if (verdict.decision === "APPROVE") approved++;
2516
+ else skipped++;
2517
+ decisions.push({
2518
+ item_type: "asset",
2519
+ decision: verdict.decision,
2520
+ resource_type: type,
2521
+ resource_key: key,
2522
+ evidence_hash: candidate.evidence_hash,
2523
+ reason: verdict.reason
2524
+ });
2525
+ }
2526
+ return {
2527
+ runId,
2528
+ snapshotHash,
2529
+ decisions,
2530
+ base: {
2531
+ schema_version: "1.0",
2532
+ run_id: runId,
2533
+ project_id: input.project_id ?? exported.project_id,
2534
+ window_days: input.window_days ?? exported.window_days,
2535
+ dashboard_limit: input.limit ?? exported.dashboard_limit,
2536
+ snapshot_hash: snapshotHash,
2537
+ rule_version: "agent_auto_asset_certification_v1",
2538
+ config_key: "agent_auto_asset_certification_enabled",
2539
+ semantic_config_key: "project_semantic_enable",
2540
+ auto_approved: approved,
2541
+ skipped,
2542
+ overflow
2543
+ }
2544
+ };
2545
+ }
2546
+ function cliAgentAutoReviewVerdict(candidate, semanticConflict) {
2547
+ if (semanticConflict) {
2548
+ return {
2549
+ decision: "SKIP",
2550
+ reason: autoReviewReason(`semantic_duplicate_targets=${encodeReasonPayload(semanticConflict)}`)
2551
+ };
2552
+ }
2553
+ if (listIncludes(candidate.conflict_risks, "same_evidence_rejected_before")) {
2554
+ return {
2555
+ decision: "SKIP",
2556
+ reason: autoReviewReason("same_evidence_rejected_before")
2557
+ };
2558
+ }
2559
+ if (array(candidate.source_evidence).length === 0 && candidate.recommendation_role !== "source_dashboard") {
2560
+ return {
2561
+ decision: "SKIP",
2562
+ reason: autoReviewReason("source_evidence_missing")
2563
+ };
2564
+ }
2565
+ const heat = numberValue(candidate.heat_count90d);
2566
+ const users = numberValue(candidate.user_count90d);
2567
+ const impact = numberValue(candidate.impact_degree);
2568
+ const matched = [];
2569
+ if (heat >= AUTO_REVIEW_MIN_HEAT) matched.push(`heat_count90d>=${AUTO_REVIEW_MIN_HEAT}`);
2570
+ if (users >= AUTO_REVIEW_MIN_USERS) matched.push(`user_count90d>=${AUTO_REVIEW_MIN_USERS}`);
2571
+ if (impact > AUTO_REVIEW_MIN_IMPACT) matched.push(`impact_degree>${AUTO_REVIEW_MIN_IMPACT}.0`);
2572
+ if (matched.length === 0) {
2573
+ return {
2574
+ decision: "SKIP",
2575
+ reason: autoReviewReason(`signals_below_threshold: heat_count90d=${heat}, user_count90d=${users}, impact_degree=${impact}`)
2576
+ };
2577
+ }
2578
+ return {
2579
+ decision: "APPROVE",
2580
+ reason: autoReviewReason(`matched=${matched.join(",")}; role=${stringValue(candidate.recommendation_role) ?? "asset"}`)
2581
+ };
2582
+ }
2583
+ function autoReviewReason(reason) {
2584
+ return `source=AGENT_AUTO_REVIEW; rule_version=agent_auto_asset_certification_v1; ${reason}`;
2585
+ }
2586
+ function autoReviewItemsWithDisplayReason(items) {
2587
+ return array(items).map((value) => {
2588
+ const item = record(value);
2589
+ const copy = {
2590
+ ...item,
2591
+ semantic_duplicate_targets: semanticDuplicateTargetsFromReason(stringValue(item.reason) ?? "")
2592
+ };
2593
+ if (item.decision !== "APPROVE") {
2594
+ copy.display_reason = autoReviewDisplayReason(item);
2595
+ }
2596
+ return copy;
2597
+ });
2598
+ }
2599
+ function semanticDuplicateConflicts(candidates) {
2600
+ const result = /* @__PURE__ */ new Map();
2601
+ const comparable = candidates.map((candidate) => comparableAsset(candidate)).filter((candidate) => !!candidate);
2602
+ for (const candidate of comparable) {
2603
+ if (candidate.actionable !== true || candidate.actionState !== "PENDING") continue;
2604
+ const matches = [];
2605
+ for (const other of comparable) {
2606
+ if (candidate.assetKey === other.assetKey) continue;
2607
+ const basis = semanticDuplicateBasis(candidate, other);
2608
+ if (basis) matches.push({ asset: other, basis });
2609
+ }
2610
+ if (!matches.length) continue;
2611
+ matches.sort((left, right) => duplicateRank(right.asset) - duplicateRank(left.asset));
2612
+ const targets = matches.slice(0, 3).map(({ asset, basis }) => ({
2613
+ target_ref: { type: asset.type, key: asset.key },
2614
+ display_name: asset.displayName,
2615
+ resource_type: asset.type,
2616
+ resource_key: asset.key,
2617
+ authentication_status: asset.authenticationStatus,
2618
+ action_state: asset.actionState,
2619
+ reason: duplicateBasisText(basis)
2620
+ }));
2621
+ result.set(candidate.assetKey, {
2622
+ targets,
2623
+ basis: Array.from(new Set(matches.map((match) => match.basis))).map(duplicateBasisText)
2624
+ });
2625
+ }
2626
+ return result;
2627
+ }
2628
+ function comparableAsset(candidate) {
2629
+ const target = record(candidate.target_ref);
2630
+ const type = stringValue(target.type);
2631
+ const key = stringValue(target.key);
2632
+ if (!type || !key) return void 0;
2633
+ const displayName = stringValue(candidate.display_name) ?? key;
2634
+ const evidence = record(candidate.evidence_snapshot);
2635
+ const evidenceAsset = record(evidence.asset);
2636
+ const description = stringValue(record(candidate.evidence_snapshot).description) ?? stringValue(evidenceAsset.description) ?? stringValue(candidate.description) ?? "";
2637
+ return {
2638
+ assetKey: `${type}|${key}`,
2639
+ type,
2640
+ key,
2641
+ displayName,
2642
+ description,
2643
+ authenticationStatus: numberValue(evidenceAsset.authentication_status ?? candidate.authentication_status),
2644
+ actionState: stringValue(candidate.action_state) ?? "",
2645
+ actionable: candidate.actionable === true,
2646
+ normalizedName: normalizeSemanticText(displayName || key),
2647
+ canonicalName: canonicalDuplicateText(displayName || key),
2648
+ aliasName: aliasDuplicateText(displayName || key),
2649
+ normalizedDescription: normalizeSemanticText(description),
2650
+ heat: numberValue(candidate.heat_count90d),
2651
+ users: numberValue(candidate.user_count90d),
2652
+ impact: numberValue(candidate.impact_degree)
2653
+ };
2654
+ }
2655
+ function semanticDuplicateBasis(left, right) {
2656
+ if (!left.normalizedName || !right.normalizedName) return void 0;
2657
+ if (left.normalizedName.length >= 3 && left.normalizedName === right.normalizedName) return "same_display_name";
2658
+ if (left.canonicalName.length >= 3 && left.canonicalName === right.canonicalName) return "copy_or_suffix_variant";
2659
+ if (left.aliasName.length >= 3 && left.aliasName === right.aliasName && relatedAssetTypes(left.type, right.type)) {
2660
+ return "business_alias_equivalent";
2661
+ }
2662
+ if (left.normalizedDescription.length >= 6 && left.normalizedDescription === right.normalizedDescription) {
2663
+ return "same_description";
2664
+ }
2665
+ return void 0;
2666
+ }
2667
+ function relatedAssetTypes(left, right) {
2668
+ if (left === right) return true;
2669
+ return left.endsWith("_prop") && right.endsWith("_prop");
2670
+ }
2671
+ function duplicateRank(asset) {
2672
+ return (asset.authenticationStatus === 1 ? 1e5 : 0) + (asset.actionState === "AUTHENTICATED" ? 5e4 : 0) + asset.heat + asset.users * 10 + asset.impact * 100;
2673
+ }
2674
+ function normalizeSemanticText(value) {
2675
+ return value.toLowerCase().replace(/[\s_\-—–/\\|::,,.。"'`【】\[\]()(){}<>《》]/g, "").trim();
2676
+ }
2677
+ function canonicalDuplicateText(value) {
2678
+ return normalizeSemanticText(value).replace(/(副本|复制|拷贝|备份|copy|backup|bak|test|测试|临时|tmp)+$/g, "").replace(/v\d+$/g, "").replace(/\d+$/g, "");
2679
+ }
2680
+ function aliasDuplicateText(value) {
2681
+ return canonicalDuplicateText(value).replace(/(公司|企业|客户|客戶|client|customer|company|account)/g, "\u5BA2\u6237").replace(/(项目|工程|project)/g, "\u9879\u76EE").replace(/(用户|玩家|会员|user|player|member)/g, "\u7528\u6237");
2682
+ }
2683
+ function duplicateBasisText(value) {
2684
+ switch (value) {
2685
+ case "same_display_name":
2686
+ return "\u8D44\u4EA7\u540D\u79F0\u4E00\u81F4";
2687
+ case "copy_or_suffix_variant":
2688
+ return "\u540D\u79F0\u4EC5\u5B58\u5728\u526F\u672C\u3001\u7248\u672C\u6216\u4E34\u65F6\u540E\u7F00\u5DEE\u5F02";
2689
+ case "business_alias_equivalent":
2690
+ return "\u4E1A\u52A1\u5BF9\u8C61\u8868\u8FF0\u76F8\u8FD1\uFF0C\u53EF\u80FD\u662F\u540C\u4E49\u5C5E\u6027\u6216\u76F8\u8FD1\u53E3\u5F84";
2691
+ case "same_description":
2692
+ return "\u8D44\u4EA7\u63CF\u8FF0\u4E00\u81F4";
2693
+ default:
2694
+ return value;
2695
+ }
2696
+ }
2697
+ function encodeReasonPayload(value) {
2698
+ return Buffer.from(JSON.stringify(value), "utf8").toString("base64url");
2699
+ }
2700
+ function decodeReasonPayload(value) {
2701
+ try {
2702
+ return record(JSON.parse(Buffer.from(value, "base64url").toString("utf8")));
2703
+ } catch {
2704
+ return {};
2705
+ }
2706
+ }
2707
+ function semanticDuplicateTargetsFromReason(reason) {
2708
+ const encoded = /semantic_duplicate_targets=([A-Za-z0-9_-]+)/.exec(reason)?.[1];
2709
+ if (!encoded) return [];
2710
+ return array(decodeReasonPayload(encoded).targets);
2711
+ }
2712
+ function listIncludes(value, expected) {
2713
+ return array(value).some((item) => item === expected);
2714
+ }
2715
+ function buildManualReviewHandoff(autoReviewResult, exportResult) {
2716
+ const result = record(autoReviewResult);
2717
+ const exported = record(exportResult);
2718
+ const material = record(exported.review_material_package);
2719
+ const decisions = decisionsByAsset(result.items);
2720
+ const candidates = array(material.candidate_assets);
2721
+ const relations = array(material.relations).map(record);
2722
+ const handoffItems = [];
2723
+ const approved = /* @__PURE__ */ new Set();
2724
+ for (const decision of decisions.values()) {
2725
+ if (decision.decision === "APPROVE" && decision.landing_status === "APPLIED") {
2726
+ approved.add(decision.assetKey);
2727
+ }
2728
+ }
2729
+ const autoCertifiedItems = buildAutoCertifiedItems(decisions, candidates);
2730
+ for (const value of candidates) {
2731
+ const candidate = record(value);
2732
+ const target = record(candidate.target_ref);
2733
+ const type = stringValue(target.type);
2734
+ const key = stringValue(target.key);
2735
+ if (!type || !key) {
2736
+ continue;
2737
+ }
2738
+ const assetKey = `${type}|${key}`;
2739
+ if (approved.has(assetKey)) {
2740
+ continue;
2741
+ }
2742
+ const decision = decisions.get(assetKey);
2743
+ const actionable = candidate.actionable === true;
2744
+ if (!decision && !actionable) {
2745
+ continue;
2746
+ }
2747
+ const reviewReason = decision ? manualReviewReason(decision, candidate) : "\u672C\u6B21\u81EA\u52A8\u8BA4\u8BC1\u672A\u4EA7\u751F\u660E\u786E\u7ED3\u8BBA\uFF0C\u53EF\u80FD\u662F\u5019\u9009\u8D44\u4EA7\u8D85\u51FA\u672C\u6B21\u81EA\u52A8\u8BA4\u8BC1\u5904\u7406\u4E0A\u9650\u6216\u88AB\u53BB\u91CD\uFF0C\u8BF7\u4EBA\u5DE5\u786E\u8BA4\u3002";
2748
+ handoffItems.push({
2749
+ ...candidate,
2750
+ auto_review_decision: decision ? decision.raw : {
2751
+ decision: "NOT_REVIEWED",
2752
+ reason: reviewReason
2753
+ },
2754
+ semantic_duplicate_targets: decision ? array(decision.raw.semantic_duplicate_targets) : [],
2755
+ manual_review_reason: reviewReason
2756
+ });
2757
+ }
2758
+ const pageReviewItems = buildPageReviewItems(handoffItems, candidates, relations, decisions);
2759
+ const pageReviewIds = new Set(pageReviewItems.map((item) => stringValue(item.client_item_id)).filter(Boolean));
2760
+ return {
2761
+ schema_version: "1.0",
2762
+ handoff_type: "auto_review_uncertified_assets_to_page_review",
2763
+ project_id: result.project_id ?? exported.project_id,
2764
+ source_auto_review_run_id: result.run_id,
2765
+ source_export_run_id: exported.run_id,
2766
+ snapshot_hash: exported.snapshot_hash ?? result.snapshot_hash,
2767
+ dashboard_limit: exported.dashboard_limit ?? result.dashboard_limit,
2768
+ auto_review_trace: {
2769
+ run_id: result.run_id,
2770
+ rule_version: result.rule_version,
2771
+ auto_approved: result.auto_approved,
2772
+ skipped: result.skipped,
2773
+ overflow: result.overflow,
2774
+ approved_items: autoCertifiedItems,
2775
+ skipped_items: handoffItems.map((item) => ({
2776
+ target_ref: record(item.target_ref),
2777
+ display_name: item.display_name,
2778
+ manual_review_reason: item.manual_review_reason
2779
+ }))
2780
+ },
2781
+ auto_certified_items: autoCertifiedItems,
2782
+ candidate_count: handoffItems.length,
2783
+ items: handoffItems,
2784
+ page_review_items: pageReviewItems,
2785
+ page_review_context_count: pageReviewItems.length - handoffItems.length,
2786
+ relations: relations.filter((edge) => pageReviewIds.has(stringValue(edge.parent)) && pageReviewIds.has(stringValue(edge.child))),
2787
+ source_index: array(material.source_index).map(record).filter((source) => pageReviewIds.has(stringValue(source.client_item_id))),
2788
+ quality_gates: array(material.quality_gates),
2789
+ definition_policy: record(material.definition_policy),
2790
+ submit_to_page_policy: {
2791
+ command: "analysis-meta agent-review submit-to-page",
2792
+ scope: "Submit page_review_items so unapproved assets keep dashboard/report parent context; only items without manual_review_context require human certification decisions.",
2793
+ reason_field: "manual_review_reason",
2794
+ source_metadata: "When submitting leftovers, copy manual_review_handoff.auto_review_trace to submit-to-page source_metadata.auto_review_trace so the page audit records show the assets Agent already certified.",
2795
+ requires_user_submission_intent: true
2796
+ }
2797
+ };
2798
+ }
2799
+ function buildPageReviewItems(handoffItems, candidates, relations, decisions) {
2800
+ const byId = /* @__PURE__ */ new Map();
2801
+ const requiredIds = /* @__PURE__ */ new Set();
2802
+ for (const value of candidates) {
2803
+ const candidate = record(value);
2804
+ const id = stringValue(candidate.client_item_id);
2805
+ if (id) byId.set(id, candidate);
2806
+ }
2807
+ for (const item of handoffItems) {
2808
+ const id = stringValue(item.client_item_id);
2809
+ if (id) requiredIds.add(id);
2810
+ }
2811
+ let changed = true;
2812
+ while (changed) {
2813
+ changed = false;
2814
+ for (const edge of relations) {
2815
+ const parent = stringValue(edge.parent);
2816
+ const child = stringValue(edge.child);
2817
+ if (parent && child && requiredIds.has(child) && !requiredIds.has(parent) && byId.has(parent)) {
2818
+ requiredIds.add(parent);
2819
+ changed = true;
2820
+ }
2821
+ }
2822
+ }
2823
+ const handoffById = new Map(handoffItems.map((item) => [stringValue(item.client_item_id), item]).filter((entry) => !!entry[0]));
2824
+ return candidates.map(record).filter((candidate) => {
2825
+ const id = stringValue(candidate.client_item_id);
2826
+ return id !== void 0 && requiredIds.has(id);
2827
+ }).map((candidate) => {
2828
+ const id = stringValue(candidate.client_item_id) ?? "";
2829
+ const handoff = handoffById.get(id);
2830
+ if (handoff) return handoff;
2831
+ const target = record(candidate.target_ref);
2832
+ const type = stringValue(target.type);
2833
+ const key = stringValue(target.key);
2834
+ const decision = type && key ? decisions.get(`${type}|${key}`) : void 0;
2835
+ return markContextCandidate(candidate, decision);
2836
+ });
2837
+ }
2838
+ function markContextCandidate(candidate, decision) {
2839
+ const item = { ...candidate };
2840
+ item.manual_review_context = true;
2841
+ item.manual_review_reason = "\u8BE5\u8D44\u4EA7\u7528\u4E8E\u4FDD\u7559\u81EA\u52A8\u53D1\u73B0\u9875\u9762\u7684\u7236\u5B50\u5C42\u7EA7\u548C\u6765\u6E90\u4E0A\u4E0B\u6587\uFF0C\u4E0D\u4F5C\u4E3A\u672C\u6B21\u4EBA\u5DE5\u5BA1\u6838\u5BF9\u8C61\u3002";
2842
+ if (decision?.decision === "APPROVE" && decision.landing_status === "APPLIED") {
2843
+ item.auto_review_decision = decision.raw;
2844
+ item.auto_review_context_reason = autoReviewDisplayReason(decision.raw, candidate);
2845
+ item.evidence_snapshot = markEvidenceAuthenticated(record(candidate.evidence_snapshot));
2846
+ }
2847
+ return item;
2848
+ }
2849
+ function markEvidenceAuthenticated(evidence) {
2850
+ const snapshot = { ...evidence };
2851
+ const asset = record(snapshot.asset);
2852
+ if (Object.keys(asset).length) {
2853
+ snapshot.asset = { ...asset, authentication_status: 1 };
2854
+ }
2855
+ return snapshot;
2856
+ }
2857
+ function decisionsByAsset(value) {
2858
+ const result = /* @__PURE__ */ new Map();
2859
+ for (const itemValue of array(value)) {
2860
+ const item = record(itemValue);
2861
+ if (item.item_type !== "asset") {
2862
+ continue;
2863
+ }
2864
+ const type = stringValue(item.resource_type);
2865
+ const key = stringValue(item.resource_key);
2866
+ if (!type || !key) {
2867
+ continue;
2868
+ }
2869
+ const assetKey = `${type}|${key}`;
2870
+ result.set(assetKey, {
2871
+ assetKey,
2872
+ decision: stringValue(item.decision) ?? "",
2873
+ landing_status: stringValue(item.landing_status) ?? "",
2874
+ raw: item
2875
+ });
2876
+ }
2877
+ return result;
2878
+ }
2879
+ function buildAutoCertifiedItems(decisions, candidates) {
2880
+ const byAsset = /* @__PURE__ */ new Map();
2881
+ for (const value of candidates) {
2882
+ const candidate = record(value);
2883
+ const target = record(candidate.target_ref);
2884
+ const type = stringValue(target.type);
2885
+ const key = stringValue(target.key);
2886
+ if (type && key) byAsset.set(`${type}|${key}`, candidate);
2887
+ }
2888
+ const items = [];
2889
+ for (const decision of decisions.values()) {
2890
+ if (decision.decision !== "APPROVE" || decision.landing_status !== "APPLIED") continue;
2891
+ const candidate = byAsset.get(decision.assetKey) ?? {};
2892
+ items.push({
2893
+ target_ref: record(candidate.target_ref),
2894
+ display_name: candidate.display_name ?? decision.raw.resource_key,
2895
+ auto_review_reason: autoReviewDisplayReason(decision.raw, candidate),
2896
+ landing_message: decision.raw.landing_message
2897
+ });
2898
+ }
2899
+ return items;
2900
+ }
2901
+ function manualReviewReason(decision, context) {
2902
+ const reason = autoReviewDisplayReason(decision.raw, context);
2903
+ if (decision.decision === "SKIP") {
2904
+ return reason;
2905
+ }
2906
+ if (decision.decision === "APPROVE" && decision.landing_status !== "APPLIED") {
2907
+ const landing = stringValue(decision.raw.landing_message);
2908
+ return landing ? `${reason}; landing_${decision.landing_status.toLowerCase()}: ${landing}` : `${reason}; landing_${decision.landing_status.toLowerCase()}`;
2909
+ }
2910
+ return reason;
2911
+ }
2912
+ function autoReviewDisplayReason(raw, context = {}) {
2913
+ const display = stringValue(raw.display_reason);
2914
+ if (display) return display;
2915
+ const reason = stringValue(raw.reason);
2916
+ if (!reason) return "\u672C\u6B21\u81EA\u52A8\u8BA4\u8BC1\u6CA1\u6709\u8FD4\u56DE\u539F\u56E0\uFF0C\u8BF7\u4EBA\u5DE5\u786E\u8BA4\u3002";
2917
+ return humanizeAutoReviewReason(reason, context);
2918
+ }
2919
+ function humanizeAutoReviewReason(reason, context) {
2920
+ if (reason.includes("semantic_duplicate_targets=")) {
2921
+ const targets = semanticDuplicateTargetsFromReason(reason).map(record).map((target) => {
2922
+ const ref = record(target.target_ref);
2923
+ const label = stringValue(target.display_name) ?? stringValue(target.resource_key) ?? stringValue(ref.key) ?? "\u672A\u77E5\u8D44\u4EA7";
2924
+ const type = stringValue(target.resource_type) ?? stringValue(ref.type) ?? "asset";
2925
+ const key = stringValue(target.resource_key) ?? stringValue(ref.key) ?? "-";
2926
+ const targetReason = stringValue(target.reason);
2927
+ return `${label}\uFF08${type}:${key}${targetReason ? `\uFF0C${targetReason}` : ""}\uFF09`;
2928
+ });
2929
+ const targetText = targets.length ? targets.join("\uFF1B") : "\u76F8\u8FD1\u8D44\u4EA7";
2930
+ return `\u672A\u81EA\u52A8\u8BA4\u8BC1\u539F\u56E0\uFF1A\u7591\u4F3C\u4E0E ${targetText} \u8BED\u4E49\u91CD\u590D\u6216\u53E3\u5F84\u76F8\u8FD1\u3002\u8BF7\u4EBA\u5DE5\u786E\u8BA4\u662F\u5426\u5E94\u4F5C\u4E3A\u72EC\u7ACB\u8D44\u4EA7\u8BA4\u8BC1\uFF1B\u5982\u679C\u53EA\u662F\u526F\u672C\u3001\u540C\u4E49\u5C5E\u6027\u6216\u76F8\u8FD1\u53E3\u5F84\uFF0C\u8BF7\u4F18\u5148\u9009\u62E9\u66F4\u6807\u51C6\u7684\u8D44\u4EA7\u3002`;
2931
+ }
2932
+ if (reason.includes("previous_decision_exists_for_different_evidence")) {
2933
+ return "\u672A\u81EA\u52A8\u8BA4\u8BC1\u539F\u56E0\uFF1A\u68C0\u6D4B\u5230\u8BE5\u8D44\u4EA7\u5B58\u5728\u5386\u53F2\u5904\u7406\u8BB0\u5F55\uFF0C\u4F46\u672C\u6B21\u672A\u8FD4\u56DE\u53EF\u6838\u9A8C\u7684\u91CD\u590D\u5BF9\u8C61\u3002\u8BF7\u6309\u5F53\u524D\u8D44\u4EA7\u5B9A\u4E49\u548C\u6765\u6E90\u8BC1\u636E\u4EBA\u5DE5\u786E\u8BA4\uFF1B\u8FD9\u4E0D\u4EE3\u8868\u7CFB\u7EDF\u53D1\u73B0\u4E86\u91CD\u590D\u8D44\u4EA7\u3002";
2934
+ }
2935
+ if (reason.includes("same_evidence_rejected_before")) {
2936
+ return "\u672A\u81EA\u52A8\u8BA4\u8BC1\u539F\u56E0\uFF1A\u76F8\u540C\u8BA4\u8BC1\u5EFA\u8BAE\u6B64\u524D\u5DF2\u88AB\u4EBA\u5DE5\u9A73\u56DE\uFF0C\u81EA\u52A8\u8BA4\u8BC1\u4E0D\u4F1A\u8986\u76D6\u4EBA\u5DE5\u7ED3\u8BBA\u3002\u5982\u4E1A\u52A1\u53E3\u5F84\u5DF2\u8C03\u6574\uFF0C\u8BF7\u4EBA\u5DE5\u91CD\u65B0\u786E\u8BA4\u662F\u5426\u8BA4\u8BC1\u3002";
2937
+ }
2938
+ if (reason.includes("source_evidence_missing")) {
2939
+ return "\u81EA\u52A8\u8BA4\u8BC1\u672A\u901A\u8FC7\uFF1A\u7F3A\u5C11\u53EF\u6838\u9A8C\u7684\u6765\u6E90\u8D44\u4EA7\u8BC1\u636E\uFF0C\u8BF7\u4EBA\u5DE5\u786E\u8BA4\u8D44\u4EA7\u6765\u6E90\u3001\u5B9A\u4E49\u548C\u4F9D\u8D56\u5173\u7CFB\u540E\u518D\u8BA4\u8BC1\u3002";
2940
+ }
2941
+ if (reason.includes("signals_below_threshold")) {
2942
+ const heat = /heat_count90d=(\d+)/.exec(reason)?.[1];
2943
+ const users = /user_count90d=(\d+)/.exec(reason)?.[1];
2944
+ const impact = /impact_degree=([0-9.]+)/.exec(reason)?.[1];
2945
+ return `\u81EA\u52A8\u8BA4\u8BC1\u672A\u901A\u8FC7\uFF1A\u8BE5\u8D44\u4EA7\u8FD1 90 \u5929\u8BBF\u95EE/\u4F7F\u7528 ${heat ?? "\u672A\u77E5"} \u6B21\u3001\u4F7F\u7528\u4EBA\u6570 ${users ?? "\u672A\u77E5"}\uFF0C\u5F71\u54CD\u5EA6 ${impact ?? "\u672A\u77E5"}\uFF0C\u672A\u8FBE\u5230\u81EA\u52A8\u8BA4\u8BC1\u9608\u503C\uFF0C\u8BF7\u4EBA\u5DE5\u786E\u8BA4\u662F\u5426\u4ECD\u9700\u8981\u8BA4\u8BC1\u3002`;
2946
+ }
2947
+ if (reason.includes("matched=")) {
2948
+ const matched = [];
2949
+ if (reason.includes("heat_count90d>=")) matched.push("\u8BBF\u95EE/\u4F7F\u7528\u6B21\u6570\u8FBE\u5230\u9608\u503C");
2950
+ if (reason.includes("user_count90d>=")) matched.push("\u4F7F\u7528\u4EBA\u6570\u8FBE\u5230\u9608\u503C");
2951
+ if (reason.includes("impact_degree>")) matched.push("\u5F71\u54CD\u5EA6\u8FBE\u5230\u9608\u503C");
2952
+ const matchedText = matched.length ? matched.join("\u3001") : "\u547D\u4E2D\u81EA\u52A8\u8BA4\u8BC1\u89C4\u5219";
2953
+ return `Agent \u81EA\u52A8\u8BA4\u8BC1\u901A\u8FC7\uFF1A\u8BE5\u8D44\u4EA7\u8FD1 90 \u5929\u8BBF\u95EE/\u4F7F\u7528 ${displaySignal(context.heat_count90d)} \u6B21\u3001\u4F7F\u7528\u4EBA\u6570 ${displaySignal(context.user_count90d)}\uFF0C\u5F71\u54CD\u5EA6 ${displaySignal(context.impact_degree)}\uFF1B\u672A\u53D1\u73B0\u8BED\u4E49\u91CD\u590D\u98CE\u9669\uFF0C\u4E14${matchedText}\u3002`;
2954
+ }
2955
+ return reason.replace(/^source=AGENT_AUTO_REVIEW;\s*/, "").replace(/rule_version=[^;]+;\s*/, "").replace(/conflict_risks=\[[^\]]*]/, "\u81EA\u52A8\u8BA4\u8BC1\u672A\u901A\u8FC7\uFF1A\u5B58\u5728\u9700\u8981\u4EBA\u5DE5\u786E\u8BA4\u7684\u5BA1\u6838\u98CE\u9669\u3002").replace(/conflict_risks=/, "\u81EA\u52A8\u8BA4\u8BC1\u672A\u901A\u8FC7\uFF1A\u5B58\u5728\u9700\u8981\u4EBA\u5DE5\u786E\u8BA4\u7684\u5BA1\u6838\u98CE\u9669\u3002");
2956
+ }
2957
+ function displaySignal(value) {
2958
+ if (typeof value === "number" && Number.isFinite(value)) return String(value);
2959
+ if (typeof value === "string" && value.trim()) return value;
2960
+ return "\u672A\u77E5";
2961
+ }
2962
+ function record(value) {
2963
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
2964
+ }
2965
+ function array(value) {
2966
+ return Array.isArray(value) ? value : [];
2967
+ }
2968
+ function numberValue(value) {
2969
+ return typeof value === "number" && Number.isFinite(value) ? value : 0;
2970
+ }
2971
+ function stringValue(value) {
2972
+ return typeof value === "string" && value.trim() ? value : void 0;
2973
+ }
2974
+
2241
2975
  // src/commands/te-analysis/meta/governance-recommendation/decisions.ts
2242
2976
  var runIdFlag2 = {
2243
2977
  name: "run-id",
@@ -2245,7 +2979,7 @@ var runIdFlag2 = {
2245
2979
  required: false,
2246
2980
  desc: "Optional run_id filter."
2247
2981
  };
2248
- var limitFlag4 = {
2982
+ var limitFlag5 = {
2249
2983
  name: "limit",
2250
2984
  type: "number",
2251
2985
  required: false,
@@ -2258,7 +2992,7 @@ var metadataGovernanceRecommendationDecisions = createAnalysisMetaCapabilityComm
2258
2992
  command: "decisions",
2259
2993
  capabilityId: "metadata.governance_recommendation.decisions",
2260
2994
  description: "List recent CLI Agent recommendation approval decisions.",
2261
- flags: [projectIdFlag, runIdFlag2, limitFlag4],
2995
+ flags: [projectIdFlag, runIdFlag2, limitFlag5],
2262
2996
  risk: "read",
2263
2997
  buildInput: (ctx) => compactInput({
2264
2998
  ...projectInput(ctx),
@@ -2271,6 +3005,7 @@ var metadataGovernanceRecommendationDecisions = createAnalysisMetaCapabilityComm
2271
3005
  var commands11 = [
2272
3006
  metadataGovernanceRecommendationExport,
2273
3007
  metadataGovernanceRecommendationSubmit,
3008
+ metadataGovernanceRecommendationAutoReview,
2274
3009
  metadataGovernanceRecommendationDecisions
2275
3010
  ];
2276
3011
  var governance_recommendation_default = commands11;
@@ -2322,7 +3057,7 @@ function object(value, name) {
2322
3057
  }
2323
3058
  return value;
2324
3059
  }
2325
- function array(value, name) {
3060
+ function array2(value, name) {
2326
3061
  if (!Array.isArray(value) || value.length < 1 || value.length > 5e3) {
2327
3062
  throw new Error(`${name} must contain 1 to 5000 items.`);
2328
3063
  }
@@ -2367,6 +3102,7 @@ var SUBMIT_TO_PAGE_HELP = [
2367
3102
  "- relations should let the page render dashboard -> report -> metadata with contains/uses edges. Use an empty relations array only when the package truly has no known parent-child evidence.",
2368
3103
  "- Each submitted item must keep source_link or evidence_links[].url so reviewers can jump to source evidence.",
2369
3104
  "- item.ai_summary.summary is the per-item recommendation reason. It must cite concrete item evidence, not generic review boilerplate. batch ai_summary.summary is only the batch overview.",
3105
+ "- When submitting manual_review_handoff leftovers, copy manual_review_handoff.auto_review_trace into source_metadata.auto_review_trace so page audit records include the assets already certified automatically.",
2370
3106
  "- For reports and SQL reports, item.ai_summary.analysis_explanation must explain reviewer-readable calculations or measures from packaged evidence_snapshot.analysis. A purpose-only summary is incomplete and is rejected locally before dispatch.",
2371
3107
  "- Reviewer-visible text should follow the project-KB source style: one business Chinese Agent summary that explains purpose, calculation caliber, filters, time scope, boundaries, and concrete reviewer questions. Keep raw SQL, parser labels, temporary aliases, parameter placeholders, hashes, and evidence paths in evidence_snapshot only; independent Agent preflight flags visible implementation terms as quality findings.",
2372
3108
  "- The command output includes review_page_url when review_url is present. Return review_page_url to the user; do not prepend the Common/API host to review_url yourself.",
@@ -2378,6 +3114,7 @@ var SUBMIT_TO_PAGE_HELP = [
2378
3114
  ' "title": "<review batch title>",',
2379
3115
  ' "source_run_id": "<export.run_id>",',
2380
3116
  ' "source_task_id": "<optional preauthorized task id>",',
3117
+ ' "source_metadata": { "auto_review_trace": "<optional trace from manual_review_handoff.auto_review_trace>" },',
2381
3118
  ' "ai_summary": { "summary": "<batch overview>" },',
2382
3119
  ' "presentation_snapshot": {',
2383
3120
  ' "project": { "id": 1, "name": "<project name>" },',
@@ -2465,7 +3202,7 @@ var agentReviewSubmitToPage = createAnalysisMetaCapabilityCommand({
2465
3202
  postProcess: (result, _input, ctx) => normalizeSubmitResult(result, resolvePublicWebHost(ctx.host()), ctx.host())
2466
3203
  });
2467
3204
  function validateInput(input) {
2468
- const items = array(input.items, "items").map((value) => {
3205
+ const items = array2(input.items, "items").map((value) => {
2469
3206
  const item = object(value, "items[]");
2470
3207
  fields(item, [
2471
3208
  "client_item_id",
@@ -2512,6 +3249,7 @@ function validateInput(input) {
2512
3249
  "title",
2513
3250
  "source_run_id",
2514
3251
  "source_task_id",
3252
+ "source_metadata",
2515
3253
  "ai_summary",
2516
3254
  "presentation_snapshot",
2517
3255
  "items"
@@ -2581,7 +3319,7 @@ function validateEvidenceLinks(item) {
2581
3319
  const sourceLink = typeof item.source_link === "string" && item.source_link.trim();
2582
3320
  let evidenceLink = false;
2583
3321
  if ("evidence_links" in item) {
2584
- evidenceLink = array(item.evidence_links, "items[].evidence_links").some((value) => {
3322
+ evidenceLink = array2(item.evidence_links, "items[].evidence_links").some((value) => {
2585
3323
  const link = object(value, "items[].evidence_links[]");
2586
3324
  return typeof link.url === "string" && !!link.url.trim();
2587
3325
  });
@@ -2592,17 +3330,17 @@ function validateEvidenceLinks(item) {
2592
3330
  }
2593
3331
  function validatePresentation(presentation, itemIds) {
2594
3332
  const displayed = /* @__PURE__ */ new Set();
2595
- for (const topicValue of array(presentation.topics, "presentation_snapshot.topics")) {
3333
+ for (const topicValue of array2(presentation.topics, "presentation_snapshot.topics")) {
2596
3334
  const topic = object(topicValue, "presentation_snapshot.topics[]");
2597
3335
  if ("items" in topic) {
2598
3336
  throw new Error("presentation_snapshot.topics[] must use groups[].items, not top-level items.");
2599
3337
  }
2600
- for (const groupValue of array(topic.groups, "presentation_snapshot.topics[].groups")) {
3338
+ for (const groupValue of array2(topic.groups, "presentation_snapshot.topics[].groups")) {
2601
3339
  const group = object(groupValue, "presentation_snapshot.topics[].groups[]");
2602
3340
  if (typeof group.id !== "string" || !group.id.trim() || typeof group.name !== "string" || !group.name.trim()) {
2603
3341
  throw new Error("presentation_snapshot.topics[].groups[] requires nonempty string id and name.");
2604
3342
  }
2605
- for (const itemValue of array(group.items, "presentation_snapshot.topics[].groups[].items")) {
3343
+ for (const itemValue of array2(group.items, "presentation_snapshot.topics[].groups[].items")) {
2606
3344
  const item = object(itemValue, "presentation_snapshot.topics[].groups[].items[]");
2607
3345
  if (typeof item.id !== "string" || !item.id.trim()) {
2608
3346
  throw new Error("presentation_snapshot display items require nonempty string id.");
@@ -2649,7 +3387,7 @@ var agentReviewReview = createAnalysisMetaCapabilityCommand({
2649
3387
  { name: "decisions", type: "json", required: true, desc: "Versioned decisions: item_id (string), version (integer), decision APPROVE/DEFER/REJECT, reason (required for DEFER/REJECT)." }
2650
3388
  ],
2651
3389
  buildInput: (ctx) => {
2652
- const decisions = array(ctx.json("decisions"), "--decisions").map((value) => {
3390
+ const decisions = array2(ctx.json("decisions"), "--decisions").map((value) => {
2653
3391
  const decision = object(value, "decisions[]");
2654
3392
  fields(decision, ["item_id", "version", "decision", "reason"], "decisions[]");
2655
3393
  decimalId(decision.item_id, "decisions[].item_id");
@@ -2686,7 +3424,7 @@ var agentReviewRetry = createAnalysisMetaCapabilityCommand({
2686
3424
  { name: "item-ids", type: "json", required: true, desc: "1 to 5000 failed item IDs as decimal strings. Successful items must not be retried." }
2687
3425
  ],
2688
3426
  buildInput: (ctx) => {
2689
- const ids = array(ctx.json("item-ids"), "--item-ids").map((id) => decimalId(id, "item_ids[]"));
3427
+ const ids = array2(ctx.json("item-ids"), "--item-ids").map((id) => decimalId(id, "item_ids[]"));
2690
3428
  unique(ids, "item_ids");
2691
3429
  return { ...batchInput(ctx), client_request_id: text(ctx, "client-request-id"), item_ids: ids };
2692
3430
  }
@@ -2770,9 +3508,9 @@ var analysisMetaAssetUsageList = createAnalysisGovernanceCapabilityCommand({
2770
3508
  command: "list",
2771
3509
  capabilityId: "governance.asset.list",
2772
3510
  description: "List assets for usage governance.",
2773
- flags: [projectIdFlag, queryFlag, searchsFlag, ruleFlag, operationTypeFlag, directoryLimitFlag, directoryOffsetFlag, payloadFlag],
3511
+ flags: [projectIdFlag, nodeIdFlag, queryFlag, searchsFlag, ruleFlag, operationTypeFlag, directoryLimitFlag, directoryOffsetFlag, payloadFlag],
2774
3512
  risk: "read",
2775
- buildInput: (ctx) => assetGovernanceInput(ctx, ["query", "searchs", "rule", "operation_type", "limit", "offset"])
3513
+ buildInput: (ctx) => assetGovernanceInput(ctx, ["node_id", "query", "searchs", "rule", "operation_type", "limit", "offset"])
2776
3514
  });
2777
3515
 
2778
3516
  // src/commands/te-analysis/meta/asset/usage-export.ts
@@ -2780,10 +3518,11 @@ var analysisMetaAssetUsageExport = createAnalysisGovernanceCapabilityCommand({
2780
3518
  resource: "asset",
2781
3519
  command: "export",
2782
3520
  capabilityId: "governance.asset.export",
2783
- description: "Export asset usage governance rows as an inline gateway result.",
2784
- flags: [projectIdFlag, queryFlag, searchsFlag, ruleFlag, operationTypeFlag, limitFlag, offsetFlag, payloadFlag],
3521
+ description: "Export asset usage governance rows as an asynchronous artifact; optionally wait and download.",
3522
+ flags: [projectIdFlag, nodeIdFlag, queryFlag, searchsFlag, ruleFlag, operationTypeFlag, limitFlag, offsetFlag, payloadFlag, ...governanceExportFlags("jsonl")],
2785
3523
  risk: "read",
2786
- buildInput: (ctx) => assetGovernanceInput(ctx, ["query", "searchs", "rule", "operation_type", "limit", "offset"])
3524
+ asyncArtifact: true,
3525
+ buildInput: (ctx) => assetGovernanceInput(ctx, [...governanceExportFields, "node_id", "query", "searchs", "rule", "operation_type", "limit", "offset"])
2787
3526
  });
2788
3527
 
2789
3528
  // src/commands/te-analysis/meta/asset/lineage-get.ts
@@ -2891,9 +3630,10 @@ var analysisMetaAssetBatchInfoExport = createAnalysisGovernanceCapabilityCommand
2891
3630
  command: "batch-info-export",
2892
3631
  capabilityId: "governance.asset.batch_export_info",
2893
3632
  description: "Batch export asset information.",
2894
- flags: [projectIdFlag, nodeIdsFlag, payloadFlag],
3633
+ flags: [projectIdFlag, nodeIdsFlag, payloadFlag, ...governanceExportFlags("xlsx")],
2895
3634
  risk: "read",
2896
- buildInput: (ctx) => assetGovernanceInput(ctx, ["node_ids"])
3635
+ asyncArtifact: true,
3636
+ buildInput: (ctx) => assetGovernanceInput(ctx, [...governanceExportFields, "node_ids"])
2897
3637
  });
2898
3638
 
2899
3639
  // src/commands/te-analysis/meta/asset/batch-sql-export.ts
@@ -2902,9 +3642,10 @@ var analysisMetaAssetBatchSqlExport = createAnalysisGovernanceCapabilityCommand(
2902
3642
  command: "batch-sql-export",
2903
3643
  capabilityId: "governance.asset.batch_export_sql",
2904
3644
  description: "Batch export asset SQL definitions.",
2905
- flags: [projectIdFlag, nodeIdsFlag, payloadFlag],
3645
+ flags: [projectIdFlag, nodeIdsFlag, payloadFlag, ...governanceExportFlags("xlsx")],
2906
3646
  risk: "read",
2907
- buildInput: (ctx) => assetGovernanceInput(ctx, ["node_ids"])
3647
+ asyncArtifact: true,
3648
+ buildInput: (ctx) => assetGovernanceInput(ctx, [...governanceExportFields, "node_ids"])
2908
3649
  });
2909
3650
 
2910
3651
  // src/commands/te-analysis/meta/asset/batch-delete.ts
@@ -2979,9 +3720,10 @@ var analysisMetaAssetOperationRecordExport = createAnalysisGovernanceCapabilityC
2979
3720
  command: "export",
2980
3721
  capabilityId: "governance.operation_record.export",
2981
3722
  description: "Export one asset batch operation record result.",
2982
- flags: [projectIdFlag, recordIdFlag, payloadFlag],
3723
+ flags: [projectIdFlag, recordIdFlag, payloadFlag, ...governanceExportFlags("xlsx")],
2983
3724
  risk: "read",
2984
- buildInput: (ctx) => assetGovernanceInput(ctx, ["record_id"])
3725
+ asyncArtifact: true,
3726
+ buildInput: (ctx) => assetGovernanceInput(ctx, [...governanceExportFields, "record_id"])
2985
3727
  });
2986
3728
 
2987
3729
  // src/commands/te-analysis/governance/asset-authentication-shared.ts
@@ -3359,7 +4101,7 @@ var reportList = createAnalysisCapabilityCommand({
3359
4101
  resource: "report",
3360
4102
  command: "list",
3361
4103
  capabilityId: "analysis.report.list",
3362
- description: "List analysis reports visible to the current user through the capability gateway.",
4104
+ description: "List analysis reports the current user can edit or manage. Read-only reports are excluded; use analysis asset search for readable asset discovery.",
3363
4105
  flags: [
3364
4106
  projectIdFlag,
3365
4107
  queriesFlag,
@@ -3408,7 +4150,7 @@ var reportGet = createAnalysisCapabilityCommand({
3408
4150
  resource: "report",
3409
4151
  command: "get",
3410
4152
  capabilityId: "analysis.report.get",
3411
- description: "Get one analysis report definition as AI QP without executing report data.",
4153
+ description: "Get one analysis report definition and event-report presentation without executing report data.",
3412
4154
  flags: [projectIdFlag, { name: "report-id", type: "number", required: true, desc: "Report ID." }],
3413
4155
  risk: "read",
3414
4156
  buildInput: (ctx) => ({
@@ -3439,7 +4181,7 @@ var REPORT_WRITE_MODEL_TYPE_VALUES = [
3439
4181
  ];
3440
4182
  var REPORT_WRITE_MODEL_DESCRIPTION = `${AI_MODEL_DESCRIPTION} Report create/update also supports tag for saved tag report data; use tag as the AI-facing spelling.`;
3441
4183
  var AI_DEFINITION_DESCRIPTION = 'Event metrics: omit optional display_name unless the target command schema explicitly supports it. Funnel step filters use event_property_name (not field) and string-array values, including "true"/"false" for boolean properties. For tag/cluster filters, cluster_date_policy accepts LATEST (default), AUTO (match the computed result for each analysis date), or SPECIFIED (requires specified_cluster_date in yyyy-MM-dd format). AI-facing model definition JSON. Do not pass raw QP, events, event_view, visual_view, or analysis_query. Distribution filters must be attached to the corresponding distribution_metrics[].filters; do not use top-level filters or relation. For path definitions, global filters support user_property, cluster, and tag only; event_property is not supported. session_unit accepts second (1..999), minute (1..999), or hour (1..24). Do not use day; express one day as session_interval=24 and session_unit=hour. For SQL, a simple query is {"sql":"select ..."}; raw variables use ${name}, while typed params use ${Text:name}, ${Selector:name}, or ${PartDate:name}. PartDate expands to a complete predicate, so write WHERE ${PartDate:d}, not a column followed by the placeholder. A part_date parameter may set boolean use_timezone; it defaults to false and controls whether that parameter uses the query effective timezone. Selector value must match one options[].value. Trino identifiers containing #, $, @, spaces, punctuation, or a reserved word must be delimited with double quotes, for example SELECT "#user_id", "$part_event", "end" FROM ...; single quotes are string literals. For multiline SQL JSON, the decoded sql value must contain a real line break; do not submit a literal \\n sequence outside quoted SQL text. Queries against an event table must include a date-partition predicate on the quoted "$part_date" column, for example WHERE "$part_date" BETWEEN \'2026-07-01\' AND \'2026-07-07\'; the backend rejects event-table SQL without it. The CLI preserves SQL text and never auto-quotes identifiers.';
3442
- var REPORT_WRITE_DEFINITION_DESCRIPTION = `${AI_DEFINITION_DESCRIPTION} For model_type=tag, pass a tag report intent such as {"tag":{"tag_name":"vip_users","time_range":{"mode":"recent","unit":"day","value":7}}}. Tags are supported for report create/update and report data, not ad-hoc analysis.`;
4184
+ var REPORT_WRITE_DEFINITION_DESCRIPTION = `${AI_DEFINITION_DESCRIPTION} Saved funnel definitions may set optional funnel.steps[].display_name; report get returns it and report create/update preserves it. Saved-report filters may contain one compound group level only; every item inside that group must be a leaf without another items array. Historical deeper trees remain readable but cannot be written back as a definition. For model_type=tag, pass a tag report intent such as {"tag":{"tag_name":"vip_users","time_range":{"mode":"recent","unit":"day","value":7}}}. Tags are supported for report create/update and report data, not ad-hoc analysis.`;
3443
4185
  function aiModelTypeFlag(required) {
3444
4186
  return {
3445
4187
  name: "model-type",
@@ -3453,18 +4195,32 @@ function validateFunnelStepFilters(modelType, definition) {
3453
4195
  const steps = definition.funnel.steps;
3454
4196
  if (!Array.isArray(steps)) return;
3455
4197
  const errors = [];
3456
- steps.forEach((step, stepIndex) => {
3457
- if (!isRecord(step) || !Array.isArray(step.filters)) return;
3458
- step.filters.forEach((filter, filterIndex) => {
3459
- if (!isRecord(filter)) return;
3460
- const location = `definition.funnel.steps[${stepIndex}].filters[${filterIndex}]`;
3461
- if ("field" in filter || typeof filter.event_property_name !== "string" || !filter.event_property_name.trim()) {
3462
- errors.push(`${location}: use a non-empty event_property_name, not a generic field object.`);
4198
+ const visit = (filter, location) => {
4199
+ if (!isRecord(filter)) {
4200
+ errors.push(`${location}: use a filter object.`);
4201
+ return;
4202
+ }
4203
+ if ("items" in filter) {
4204
+ if (Object.keys(filter).some((key) => key !== "items" && key !== "relation")) {
4205
+ errors.push(`${location}: compound groups contain only items and relation; put event_property_name and operator on their leaf items.`);
3463
4206
  }
3464
- if ("values" in filter && (!Array.isArray(filter.values) || filter.values.some((value) => typeof value !== "string"))) {
3465
- errors.push(`${location}.values: use an array of strings (boolean properties use "true" or "false").`);
4207
+ if (!Array.isArray(filter.items) || filter.items.length === 0) {
4208
+ errors.push(`${location}.items: use a non-empty array of event-property filters or nested groups.`);
4209
+ } else {
4210
+ filter.items.forEach((item, index) => visit(item, `${location}.items[${index}]`));
3466
4211
  }
3467
- });
4212
+ return;
4213
+ }
4214
+ if ("field" in filter || typeof filter.event_property_name !== "string" || !filter.event_property_name.trim()) {
4215
+ errors.push(`${location}: use a non-empty event_property_name, not a generic field object.`);
4216
+ }
4217
+ if ("values" in filter && (!Array.isArray(filter.values) || filter.values.some((value) => typeof value !== "string"))) {
4218
+ errors.push(`${location}.values: use an array of strings (boolean properties use "true" or "false").`);
4219
+ }
4220
+ };
4221
+ steps.forEach((step, stepIndex) => {
4222
+ if (!isRecord(step) || !Array.isArray(step.filters)) return;
4223
+ step.filters.forEach((filter, filterIndex) => visit(filter, `definition.funnel.steps[${stepIndex}].filters[${filterIndex}]`));
3468
4224
  });
3469
4225
  if (errors.length) {
3470
4226
  throw new CliValidationError(errors.join("\n"), {
@@ -3516,6 +4272,61 @@ function validateReportMetadataResolutions(ctx) {
3516
4272
  }
3517
4273
  }
3518
4274
 
4275
+ // src/commands/te-analysis/report/presentation.ts
4276
+ var reportPresentationFlag = {
4277
+ name: "presentation",
4278
+ type: "json",
4279
+ required: false,
4280
+ desc: 'Optional top-level event-report display JSON: chart_type (line|combo|bar|stacked|cumulative|pie), table_layout (date|event|group), series [{metric_index:1,type:"bar"|"line",axis:"primary"|"secondary"}]. Line/combo/cumulative require a non-total time_particle_size. Metric indexes are 1-based definition.metrics positions. Series is a subset patch; [] resets all series, and chart_type=line resets to pure primary-axis lines. Omit to preserve the saved chart/result-table layout on same-model updates. For a dashboard table card use analysis dashboard-report update --chart-type table.'
4281
+ };
4282
+ function validateReportPresentation(ctx) {
4283
+ if (!(ctx.has?.("presentation") ?? ctx.str("presentation") !== "")) return;
4284
+ const value = ctx.json("presentation");
4285
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
4286
+ throw new Error("--presentation must be a non-empty event-report display object.");
4287
+ }
4288
+ const presentation = value;
4289
+ const keys = Object.keys(presentation);
4290
+ if (keys.length === 0 || keys.some((key) => !["chart_type", "table_layout", "series"].includes(key))) {
4291
+ throw new Error("--presentation accepts only chart_type, table_layout, and series; use semantic names, not raw QP fields.");
4292
+ }
4293
+ if (presentation.chart_type === "table") {
4294
+ throw new Error("A table is a dashboard card display; use analysis dashboard-report update --chart-type table.");
4295
+ }
4296
+ if (Object.hasOwn(presentation, "chart_type") && (typeof presentation.chart_type !== "string" || !["line", "combo", "bar", "stacked", "cumulative", "pie"].includes(presentation.chart_type))) {
4297
+ throw new Error("--presentation.chart_type must be line, combo, bar, stacked, cumulative, or pie.");
4298
+ }
4299
+ if (Object.hasOwn(presentation, "table_layout") && (typeof presentation.table_layout !== "string" || !["date", "event", "group"].includes(presentation.table_layout))) {
4300
+ throw new Error("--presentation.table_layout must be date, event, or group.");
4301
+ }
4302
+ if (ctx.str("model-type") !== "" && ctx.str("model-type") !== "event") {
4303
+ throw new Error("--presentation is supported only for event reports.");
4304
+ }
4305
+ if (Object.hasOwn(presentation, "series")) validateSeries(presentation.series);
4306
+ }
4307
+ function validateSeries(value) {
4308
+ if (!Array.isArray(value)) throw new Error("--presentation.series must be an array; [] resets all series.");
4309
+ const indexes = /* @__PURE__ */ new Set();
4310
+ for (const [position, item] of value.entries()) {
4311
+ const path = `--presentation.series[${position}]`;
4312
+ if (!item || typeof item !== "object" || Array.isArray(item) || Object.keys(item).length !== 3 || Object.keys(item).some((key) => !["metric_index", "type", "axis"].includes(key))) {
4313
+ throw new Error(`${path} requires only metric_index, type, and axis, all three required.`);
4314
+ }
4315
+ const series = item;
4316
+ if (typeof series.metric_index !== "number" || !Number.isInteger(series.metric_index) || series.metric_index < 1) {
4317
+ throw new Error(`${path}.metric_index must be a positive 1-based integer position in definition.metrics.`);
4318
+ }
4319
+ if (indexes.has(series.metric_index)) throw new Error(`${path}.metric_index must not repeat another series binding.`);
4320
+ indexes.add(series.metric_index);
4321
+ if (typeof series.type !== "string" || !["bar", "line"].includes(series.type)) {
4322
+ throw new Error(`${path}.type must be bar or line.`);
4323
+ }
4324
+ if (typeof series.axis !== "string" || !["primary", "secondary"].includes(series.axis)) {
4325
+ throw new Error(`${path}.axis must be primary or secondary.`);
4326
+ }
4327
+ }
4328
+ }
4329
+
3519
4330
  // src/commands/te-analysis/report/create.ts
3520
4331
  var reportCreate = createAnalysisCapabilityCommand({
3521
4332
  resource: "report",
@@ -3527,6 +4338,7 @@ var reportCreate = createAnalysisCapabilityCommand({
3527
4338
  { name: "report-name", type: "string", required: true, desc: "Report display name." },
3528
4339
  reportWriteModelTypeFlag(true),
3529
4340
  reportWriteDefinitionFlag(true),
4341
+ reportPresentationFlag,
3530
4342
  modelDefinitionIntentSnapshotFlag,
3531
4343
  reportMetadataResolutionsFlag,
3532
4344
  { name: "report-desc", type: "string", required: false, desc: "Optional report description." },
@@ -3535,15 +4347,19 @@ var reportCreate = createAnalysisCapabilityCommand({
3535
4347
  { name: "dashboard-ids", type: "json", required: false, desc: "Optional dashboard ID array to associate after creation." }
3536
4348
  ],
3537
4349
  risk: "write",
3538
- validate: validateReportMetadataResolutions,
4350
+ validate: (ctx) => {
4351
+ validateReportMetadataResolutions(ctx);
4352
+ validateReportPresentation(ctx);
4353
+ },
3539
4354
  intentConsistency: { definitionFlag: "definition", modelTypeFlag: "model-type" },
3540
4355
  buildInput: (ctx) => compactInput({
3541
4356
  ...projectInput(ctx),
3542
4357
  report_name: ctx.str("report-name"),
3543
4358
  model_type: ctx.str("model-type"),
3544
4359
  definition: ctx.json("definition"),
4360
+ presentation: optionalJson(ctx, "presentation"),
3545
4361
  resolutions: optionalJson(ctx, "resolutions"),
3546
- report_desc: optionalString(ctx, "report-desc"),
4362
+ report_desc: optionalString(ctx, "report-desc") ?? "",
3547
4363
  cache_seconds: optionalNumber(ctx, "cache-seconds"),
3548
4364
  query_duration_ms: optionalNumber(ctx, "query-duration-ms"),
3549
4365
  dashboard_ids: optionalJsonArray(ctx, "dashboard-ids")
@@ -3554,9 +4370,10 @@ var reportCreate = createAnalysisCapabilityCommand({
3554
4370
  function validateReportUpdate(ctx) {
3555
4371
  const hasDefinition = ctx.str("definition") !== "";
3556
4372
  const hasResolutions = ctx.json("resolutions") !== void 0;
3557
- const hasMetadataUpdate = ctx.str("report-name") !== "" || ctx.str("report-desc") !== "";
3558
- if (!hasDefinition && !hasMetadataUpdate) {
3559
- throw new Error("At least one of --report-name, --report-desc, or --definition is required.");
4373
+ const hasPresentation = ctx.has?.("presentation") ?? ctx.str("presentation") !== "";
4374
+ const hasMetadataUpdate = ctx.str("report-name") !== "" || optionalStringPreserveEmpty(ctx, "report-desc") !== void 0;
4375
+ if (!hasDefinition && !hasMetadataUpdate && !hasPresentation) {
4376
+ throw new Error("At least one of --report-name, --report-desc, --definition, or --presentation is required.");
3560
4377
  }
3561
4378
  if (hasDefinition && ctx.str("model-type") === "") {
3562
4379
  throw new Error("--model-type is required when --definition is provided.");
@@ -3565,20 +4382,22 @@ function validateReportUpdate(ctx) {
3565
4382
  throw new Error("--resolutions requires --definition.");
3566
4383
  }
3567
4384
  validateReportMetadataResolutions(ctx);
4385
+ validateReportPresentation(ctx);
3568
4386
  }
3569
4387
  var reportUpdate = createAnalysisCapabilityCommand({
3570
4388
  resource: "report",
3571
4389
  command: "update",
3572
4390
  capabilityId: "analysis.report.update",
3573
- description: "Update report metadata or AI QP definition through the capability gateway.",
4391
+ description: "Update report metadata, AI QP definition, or event-report presentation through the capability gateway.",
3574
4392
  flags: [
3575
4393
  projectIdFlag,
3576
4394
  { name: "report-id", type: "number", required: true, desc: "Report ID to update." },
3577
4395
  { name: "report-version", type: "number", required: true, desc: "Current report version from report get." },
3578
4396
  { name: "report-name", type: "string", required: false, desc: "New report display name." },
3579
- { name: "report-desc", type: "string", required: false, desc: "New report description." },
4397
+ { name: "report-desc", type: "string", required: false, desc: "New report description. Pass an empty string to clear it; omit to preserve it." },
3580
4398
  reportWriteModelTypeFlag(false),
3581
4399
  reportWriteDefinitionFlag(false),
4400
+ reportPresentationFlag,
3582
4401
  modelDefinitionIntentSnapshotFlag,
3583
4402
  reportMetadataResolutionsFlag,
3584
4403
  { name: "cache-seconds", type: "number", required: false, desc: "Optional cache duration in seconds." },
@@ -3592,9 +4411,10 @@ var reportUpdate = createAnalysisCapabilityCommand({
3592
4411
  report_id: ctx.num("report-id"),
3593
4412
  version: ctx.num("report-version"),
3594
4413
  report_name: optionalString(ctx, "report-name"),
3595
- report_desc: optionalString(ctx, "report-desc"),
4414
+ report_desc: optionalStringPreserveEmpty(ctx, "report-desc"),
3596
4415
  model_type: optionalString(ctx, "model-type"),
3597
4416
  definition: optionalJson(ctx, "definition"),
4417
+ presentation: optionalJson(ctx, "presentation"),
3598
4418
  resolutions: optionalJson(ctx, "resolutions"),
3599
4419
  cache_seconds: optionalNumber(ctx, "cache-seconds"),
3600
4420
  query_duration_ms: optionalNumber(ctx, "query-duration-ms")
@@ -3841,7 +4661,7 @@ var dashboardList = createAnalysisCapabilityCommand({
3841
4661
  resource: "dashboard",
3842
4662
  command: "list",
3843
4663
  capabilityId: "analysis.dashboard.list",
3844
- description: "List dashboards visible to the current user through the capability gateway.",
4664
+ description: "List dashboards the current user can update or manage. Read-only dashboards are excluded; use analysis asset search for readable asset discovery.",
3845
4665
  flags: [
3846
4666
  projectIdFlag,
3847
4667
  queriesFlag,
@@ -4044,6 +4864,42 @@ var dashboardCopy = createAnalysisCapabilityCommand({
4044
4864
  })
4045
4865
  });
4046
4866
 
4867
+ // src/commands/te-analysis/dashboard/move.ts
4868
+ var dashboardMove = createAnalysisCapabilityCommand({
4869
+ resource: "dashboard",
4870
+ command: "move",
4871
+ capabilityId: "analysis.dashboard.move",
4872
+ description: "Move one or more dashboards to the same project-space root or folder.",
4873
+ flags: [
4874
+ projectIdFlag,
4875
+ {
4876
+ name: "dashboard-ids",
4877
+ type: "json",
4878
+ required: true,
4879
+ desc: "Dashboard ID array. Pass a one-item array to move a single dashboard."
4880
+ },
4881
+ {
4882
+ name: "to-space-id",
4883
+ type: "number",
4884
+ required: true,
4885
+ desc: "Target project space ID."
4886
+ },
4887
+ {
4888
+ name: "to-folder-id",
4889
+ type: "number",
4890
+ required: false,
4891
+ desc: "Target folder ID within the target project space. Omit to move to the space root."
4892
+ }
4893
+ ],
4894
+ risk: "write",
4895
+ buildInput: (ctx) => compactInput({
4896
+ ...projectInput(ctx),
4897
+ dashboard_ids: jsonArray(ctx, "dashboard-ids"),
4898
+ to_space_id: ctx.num("to-space-id"),
4899
+ to_folder_id: optionalNumber(ctx, "to-folder-id")
4900
+ })
4901
+ });
4902
+
4047
4903
  // src/commands/te-analysis/dashboard/freeze.ts
4048
4904
  var dashboardFreeze = createAnalysisCapabilityCommand({
4049
4905
  resource: "dashboard",
@@ -4102,6 +4958,7 @@ var commands19 = [
4102
4958
  dashboardDelete,
4103
4959
  dashboardHandover,
4104
4960
  dashboardCopy,
4961
+ dashboardMove,
4105
4962
  dashboardFreeze,
4106
4963
  dashboardAbnormalGet,
4107
4964
  dashboardTaskStatus
@@ -4127,9 +4984,71 @@ var dashboardReportAdd = createAnalysisCapabilityCommand({
4127
4984
  })
4128
4985
  });
4129
4986
 
4987
+ // src/commands/te-analysis/dashboard-report/get.ts
4988
+ var dashboardReportGet = createAnalysisCapabilityCommand({
4989
+ resource: "dashboard-report",
4990
+ command: "get",
4991
+ capabilityId: "analysis.dashboard_report.get",
4992
+ description: "Get an event report card presentation on one analysis dashboard, not the source report definition.",
4993
+ flags: [
4994
+ projectIdFlag,
4995
+ { name: "dashboard-id", type: "number", required: true, desc: "Dashboard containing the report card." },
4996
+ { name: "report-id", type: "number", required: true, desc: "Existing event report ID on that dashboard." }
4997
+ ],
4998
+ risk: "read",
4999
+ buildInput: (ctx) => ({
5000
+ ...projectInput(ctx),
5001
+ dashboard_id: ctx.num("dashboard-id"),
5002
+ report_id: ctx.num("report-id")
5003
+ })
5004
+ });
5005
+
5006
+ // src/commands/te-analysis/dashboard-report/update.ts
5007
+ var dashboardReportUpdate = createAnalysisCapabilityCommand({
5008
+ resource: "dashboard-report",
5009
+ command: "update",
5010
+ capabilityId: "analysis.dashboard_report.update",
5011
+ description: "Update one event report card presentation without changing the source report definition or other dashboards.",
5012
+ flags: [
5013
+ projectIdFlag,
5014
+ { name: "dashboard-id", type: "number", required: true, desc: "Dashboard containing the report card." },
5015
+ { name: "report-id", type: "number", required: true, desc: "Existing event report ID on that dashboard." },
5016
+ { name: "chart-type", type: "string", required: false, desc: "Card chart type: line, combo, bar, stacked, cumulative, pie, or table. Combo inherits existing source-report series; this command cannot edit series. A pure line card requires resetting source combo first. Gateway validates compatibility with the saved event definition." },
5017
+ { name: "table-layout", type: "string", required: false, desc: "Table layout: date, event, or group. Omit to preserve it." },
5018
+ { name: "date-outside", type: "boolean", required: false, desc: "Show dates outside the table. True requires a grouped table with a non-date layout; also choose event/group layout when inherited. Pass false to clear, omit to preserve." }
5019
+ ],
5020
+ risk: "write",
5021
+ validate: (ctx) => {
5022
+ const chartType = optionalString(ctx, "chart-type");
5023
+ const tableLayout = optionalString(ctx, "table-layout");
5024
+ const dateOutside = optionalBoolean(ctx, "date-outside");
5025
+ if (chartType === void 0 && tableLayout === void 0 && dateOutside === void 0) {
5026
+ throw new Error("At least one of --chart-type, --table-layout, or --date-outside is required.");
5027
+ }
5028
+ if (chartType !== void 0 && !["line", "combo", "bar", "stacked", "cumulative", "pie", "table"].includes(chartType)) {
5029
+ throw new Error("--chart-type must be line, combo, bar, stacked, cumulative, pie, or table.");
5030
+ }
5031
+ if (tableLayout !== void 0 && !["date", "event", "group"].includes(tableLayout)) {
5032
+ throw new Error("--table-layout must be date, event, or group.");
5033
+ }
5034
+ },
5035
+ buildInput: (ctx) => ({
5036
+ ...projectInput(ctx),
5037
+ dashboard_id: ctx.num("dashboard-id"),
5038
+ report_id: ctx.num("report-id"),
5039
+ presentation: compactInput({
5040
+ chart_type: optionalString(ctx, "chart-type"),
5041
+ table_layout: optionalString(ctx, "table-layout"),
5042
+ date_outside: optionalBoolean(ctx, "date-outside")
5043
+ })
5044
+ })
5045
+ });
5046
+
4130
5047
  // src/commands/te-analysis/dashboard-report/index.ts
4131
5048
  var commands20 = [
4132
- dashboardReportAdd
5049
+ dashboardReportAdd,
5050
+ dashboardReportGet,
5051
+ dashboardReportUpdate
4133
5052
  ];
4134
5053
  var dashboard_report_default = commands20;
4135
5054
 
@@ -4176,14 +5095,13 @@ var dashboardReportDataExport = createAnalysisCapabilityCommand({
4176
5095
  clusterQueryScopeFlag,
4177
5096
  slaveClusterIdFlag,
4178
5097
  { name: "zone-offset", type: "number", required: false, desc: reportDataZoneOffsetDescription },
4179
- { name: "use-cache", type: "boolean", required: false, desc: "Whether to use cache. Default: true." },
4180
5098
  { name: "request-id", type: "string", required: false, desc: "Optional cli_<32 lowercase hex> request ID. Generated when omitted." },
4181
5099
  asyncTimeoutSecondsFlag,
4182
5100
  { name: "artifact-format", type: "string", required: false, desc: "Artifact format. Only jsonl is supported." }
4183
5101
  ],
4184
5102
  risk: "read",
4185
5103
  validate: validateClusterQueryRouting,
4186
- buildInput: dashboardReportDataInput
5104
+ buildInput: (ctx) => dashboardReportDataInput(ctx, false)
4187
5105
  });
4188
5106
 
4189
5107
  // src/commands/te-analysis/dashboard-report-data/index.ts
@@ -6592,7 +7510,7 @@ var sqlTableColumns = createAnalysisCapabilityCommand({
6592
7510
  name: "table-ref",
6593
7511
  type: "string",
6594
7512
  required: true,
6595
- desc: "Exact table_ref returned by analysis sql-table list; a unique table-only reference is also accepted."
7513
+ desc: "Exact table_ref or quoted sql_reference returned by analysis sql-table list; a unique table-only reference is also accepted."
6596
7514
  },
6597
7515
  sqlTableUsageFlag
6598
7516
  ],
@@ -6609,7 +7527,7 @@ var sqlTableList = createAnalysisCapabilityCommand({
6609
7527
  resource: "sql-table",
6610
7528
  command: "list",
6611
7529
  capabilityId: "analysis.sql_table.list",
6612
- description: "List server-authoritative SQL table references queryable by the current user in a project.",
7530
+ description: "List server-authoritative SQL table references queryable by the current user in a project, including authorized space tables. Use sql_reference when copying a table into SQL.",
6613
7531
  flags: [projectIdFlag, queriesFlag, directoryLimitFlag, directoryOffsetFlag, sqlTableUsageFlag],
6614
7532
  risk: "read",
6615
7533
  validate: validateQueriesFlag,
@@ -9773,14 +10691,14 @@ var monitorTimeFields = [
9773
10691
  type: "string",
9774
10692
  required: true,
9775
10693
  pattern: "^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$",
9776
- desc: "Inclusive query range start, yyyy-MM-dd HH:mm:ss."
10694
+ desc: "Inclusive completion-time range start, yyyy-MM-dd HH:mm:ss."
9777
10695
  },
9778
10696
  {
9779
10697
  flag: "end-time",
9780
10698
  type: "string",
9781
10699
  required: true,
9782
10700
  pattern: "^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$",
9783
- desc: "Inclusive query range end, yyyy-MM-dd HH:mm:ss."
10701
+ desc: "Inclusive completion-time range end, including the entire second, yyyy-MM-dd HH:mm:ss."
9784
10702
  }
9785
10703
  ];
9786
10704
  function validateTaskQueryInput(input) {
@@ -9844,6 +10762,27 @@ var systemMonitoringCommands = [
9844
10762
  ],
9845
10763
  validate: (_ctx, input) => validateTaskQueryInput(input)
9846
10764
  }),
10765
+ defineSystemCommand({
10766
+ resource: "query-task",
10767
+ command: "realtime-list",
10768
+ capabilityId: "system.query_task.realtime_list",
10769
+ description: "List a bounded realtime query-monitor snapshot; use query-task list for historical logs.",
10770
+ risk: "read",
10771
+ fields: [
10772
+ { flag: "duration-minutes", type: "number", min: 1, max: 30, desc: "Realtime window in minutes. Default: 30." },
10773
+ ...monitorScopeFields,
10774
+ { flag: "cluster-names", type: "json", required: true, array: true, desc: "Query cluster-name JSON array." },
10775
+ { flag: "status-codes", type: "json", array: true, desc: "Optional task status-code JSON array." },
10776
+ { flag: "limit", type: "number", min: 1, max: 200, desc: "Maximum returned tasks. Default: 100, max: 200." }
10777
+ ],
10778
+ validate: (_ctx, input) => {
10779
+ validateMonitorScope(input);
10780
+ requireAtLeastOne(input, ["cluster_names"], "--cluster-names must be a non-empty JSON array.");
10781
+ if (input.status_codes !== void 0) {
10782
+ requireAtLeastOne(input, ["status_codes"], "--status-codes must be a non-empty JSON array.");
10783
+ }
10784
+ }
10785
+ }),
9847
10786
  defineSystemCommand({
9848
10787
  resource: "query-task",
9849
10788
  command: "get",
@@ -10186,6 +11125,89 @@ var commands81 = [
10186
11125
  ];
10187
11126
  var system_default = commands81;
10188
11127
 
11128
+ // src/commands/te-analysis/feedback/submit.ts
11129
+ import { createHash as createHash4, randomUUID as randomUUID2 } from "crypto";
11130
+ var analysisQueryCapabilities = /* @__PURE__ */ new Set([
11131
+ "analysis.adhoc.run",
11132
+ "analysis.adhoc.export",
11133
+ "analysis.report_data.run",
11134
+ "analysis.report_data.export",
11135
+ "analysis.dashboard_report_data.run",
11136
+ "analysis.dashboard_report_data.export",
11137
+ "analysis.bi_panel_page_data.run",
11138
+ "analysis.bi_panel_page_data.export",
11139
+ "analysis.event_detail.run",
11140
+ "analysis.event_detail.export",
11141
+ "analysis.entity_detail.run",
11142
+ "analysis.entity_detail.export",
11143
+ "analysis.query.drilldown_events",
11144
+ "analysis.query.drilldown_events_export",
11145
+ "analysis.query.drilldown_entities",
11146
+ "analysis.query.drilldown_entities_export",
11147
+ "analysis.query.drilldown_user_events",
11148
+ "analysis.query.drilldown_user_events_export",
11149
+ "analysis.query.drilldown_session_details"
11150
+ ]);
11151
+ function analysisFeedbackInput(ctx) {
11152
+ if (!ctx.bool("query-completed")) throw new CliValidationError("Feedback requires a completed data query and final analysis answer.");
11153
+ const queryCapabilityId = ctx.str("query-capability-id");
11154
+ if (!analysisQueryCapabilities.has(queryCapabilityId)) throw new CliValidationError("query-capability-id must identify an executed analysis data query.");
11155
+ const ratings = ["satisfied", "partially_satisfied", "dissatisfied", "unable_to_judge"];
11156
+ const satisfaction = ctx.str("satisfaction");
11157
+ if (!ratings.includes(satisfaction)) throw new CliValidationError("satisfaction must be an explicit user feedback category.");
11158
+ const feedbackText = ctx.str("feedback-text");
11159
+ if (!feedbackText.trim() || feedbackText.length > 2048) throw new CliValidationError("feedback-text must contain original user feedback up to 2048 characters.");
11160
+ const context = readCliAgentContext();
11161
+ if (!context.agent_session_id) throw new CliValidationError("The Agent context file must contain the evaluated agent_session_id.");
11162
+ const turns = ctx.json("target-turn-ids") ?? [];
11163
+ if (!Array.isArray(turns) || turns.length > 32 || turns.some((id) => typeof id !== "string" || !id.trim() || id.length > 191)) {
11164
+ throw new CliValidationError("target-turn-ids must be an array of at most 32 nonblank existing turn IDs.");
11165
+ }
11166
+ if (turns.includes(context.agent_turn_id)) throw new CliValidationError("target-turn-ids must reference analysis turns, not the feedback turn.");
11167
+ const targetTurns = [...new Set(turns)];
11168
+ const suppliedId = ctx.str("feedback-id");
11169
+ const feedbackId = suppliedId || (context.agent_turn_id ? createHash4("sha256").update(JSON.stringify([context.agent_session_id, context.agent_turn_id, targetTurns, queryCapabilityId, satisfaction, feedbackText])).digest("hex") : randomUUID2());
11170
+ if (!feedbackId.trim() || feedbackId.length > 128) throw new CliValidationError("feedback-id must be a nonblank string up to 128 characters.");
11171
+ const routeSummary = ctx.str("route-summary");
11172
+ if (routeSummary.length > 2048) throw new CliValidationError("route-summary must be at most 2048 characters.");
11173
+ const projectId = ctx.optionalNum("project-id");
11174
+ if (projectId !== void 0 && (!Number.isInteger(projectId) || projectId <= 0)) {
11175
+ throw new CliValidationError("project-id must be a positive integer.");
11176
+ }
11177
+ return {
11178
+ feedback_id: feedbackId,
11179
+ agent_session_id: context.agent_session_id,
11180
+ target_turn_ids: targetTurns,
11181
+ query_completed: true,
11182
+ query_capability_id: queryCapabilityId,
11183
+ satisfaction,
11184
+ feedback_text: feedbackText,
11185
+ ...projectId !== void 0 ? { project_id: projectId } : {},
11186
+ ...routeSummary.trim() ? { route_summary: routeSummary } : {}
11187
+ };
11188
+ }
11189
+ var analysisFeedbackSubmit = createAnalysisCapabilityCommand({
11190
+ resource: "feedback",
11191
+ command: "submit",
11192
+ capabilityId: "analysis.feedback.submit",
11193
+ risk: "write",
11194
+ description: "Submit explicit user feedback after a completed analysis data query and final answer. Reuses Agent session and analysis turn IDs; never submits an answer body.",
11195
+ flags: [
11196
+ { name: "query-completed", type: "boolean", desc: "Confirm that query results and the final analysis answer have been delivered." },
11197
+ { name: "query-capability-id", type: "string", required: true, desc: "Executed analysis data-query capability ID in the evaluated turns." },
11198
+ { name: "satisfaction", type: "string", required: true, desc: "Explicit rating: satisfied, partially_satisfied, dissatisfied, or unable_to_judge." },
11199
+ { name: "feedback-text", type: "string", required: true, sensitive: true, desc: "Original user feedback, up to 2048 characters. No answer content." },
11200
+ { name: "target-turn-ids", type: "json", desc: "JSON array of evaluated analysis turn IDs; omit only when unknown." },
11201
+ { name: "route-summary", type: "string", sensitive: true, desc: "Optional brief verifiable route and asset-selection rationale. No answer content." },
11202
+ { name: "feedback-id", type: "string", desc: "Stable feedback ID for retries; defaults to current session/feedback-turn fingerprint when available." },
11203
+ { name: "project-id", type: "number", desc: "Evaluated analysis project ID when available." }
11204
+ ],
11205
+ buildInput: analysisFeedbackInput
11206
+ });
11207
+
11208
+ // src/commands/te-analysis/feedback/index.ts
11209
+ var feedback_default = [analysisFeedbackSubmit];
11210
+
10189
11211
  // src/commands/te-analysis/index.ts
10190
11212
  registerCapabilityGatewayRoute("analysis", { gatewayDomain: "analysis" });
10191
11213
  registerCapabilityGatewayRoute("project", { gatewayDomain: "analysis" });
@@ -10232,7 +11254,8 @@ var baseCommands = [
10232
11254
  ...alert_detail_default,
10233
11255
  ...alert_job_default,
10234
11256
  ...alert_notice_config_default,
10235
- ...system_default
11257
+ ...system_default,
11258
+ ...feedback_default
10236
11259
  ];
10237
11260
  var commands82 = [...baseCommands];
10238
11261
  var te_analysis_default = commands82;