kcode-pi 0.1.0

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 (219) hide show
  1. package/README.md +358 -0
  2. package/dist/cli/kcode.d.ts +15 -0
  3. package/dist/cli/kcode.js +153 -0
  4. package/dist/cli/main.d.ts +2 -0
  5. package/dist/cli/main.js +7 -0
  6. package/docs/KCODE_DISTRIBUTION.md +91 -0
  7. package/extensions/kingdee-harness.ts +180 -0
  8. package/extensions/kingdee-header.ts +122 -0
  9. package/extensions/kingdee-tools.ts +379 -0
  10. package/knowledge/.backup/v1.0.0/version.json +10 -0
  11. package/knowledge/cangqiong/product-notes.md +15 -0
  12. package/knowledge/common/business-flows.md +115 -0
  13. package/knowledge/common/config-guides.md +110 -0
  14. package/knowledge/common/error-patterns.md +170 -0
  15. package/knowledge/common/implementation.md +144 -0
  16. package/knowledge/cosmic/hard-constraints.md +38 -0
  17. package/knowledge/cosmic/ksql-datafix.md +34 -0
  18. package/knowledge/cosmic/platform-baseline.md +32 -0
  19. package/knowledge/cosmic/plugin-decision-matrix.md +40 -0
  20. package/knowledge/cosmic/review-checklist.md +40 -0
  21. package/knowledge/cosmic/unittest.md +35 -0
  22. package/knowledge/enterprise/api-reference.md +186 -0
  23. package/knowledge/enterprise/code-patterns.md +217 -0
  24. package/knowledge/enterprise/plugin-lifecycle.md +188 -0
  25. package/knowledge/enterprise/tables.json +159 -0
  26. package/knowledge/flagship/api-reference.md +237 -0
  27. package/knowledge/flagship/code-patterns.md +246 -0
  28. package/knowledge/flagship/cosmic-platform-note.md +15 -0
  29. package/knowledge/flagship/plugin-lifecycle.md +248 -0
  30. package/knowledge/flagship/tables.json +159 -0
  31. package/knowledge/version.json +10 -0
  32. package/knowledge/xinghan/product-notes.md +15 -0
  33. package/package.json +71 -0
  34. package/prompts/kd-discuss.md +11 -0
  35. package/prompts/kd-execute.md +12 -0
  36. package/prompts/kd-plan.md +12 -0
  37. package/prompts/kd-ship.md +12 -0
  38. package/prompts/kd-spec.md +12 -0
  39. package/prompts/kd-verify.md +12 -0
  40. package/skills/kd-check/SKILL.md +26 -0
  41. package/skills/kd-cosmic-dev/SKILL.md +82 -0
  42. package/skills/kd-cosmic-review/SKILL.md +90 -0
  43. package/skills/kd-cosmic-unittest/SKILL.md +92 -0
  44. package/skills/kd-debug/SKILL.md +30 -0
  45. package/skills/kd-discuss/SKILL.md +24 -0
  46. package/skills/kd-execute/SKILL.md +22 -0
  47. package/skills/kd-gen/SKILL.md +34 -0
  48. package/skills/kd-ksql/SKILL.md +86 -0
  49. package/skills/kd-plan/SKILL.md +24 -0
  50. package/skills/kd-ship/SKILL.md +22 -0
  51. package/skills/kd-spec/SKILL.md +24 -0
  52. package/skills/kd-verify/SKILL.md +22 -0
  53. package/themes/kcode-dark.json +81 -0
  54. package/vendor/kingdee-skills/cosmic-unittest/SKILL.md +788 -0
  55. package/vendor/kingdee-skills/cosmic-unittest/author-cache.json +5 -0
  56. package/vendor/kingdee-skills/cosmic-unittest/cosmic-unittest-skill-overview.html +746 -0
  57. package/vendor/kingdee-skills/cosmic-unittest/examples/business-test.md +205 -0
  58. package/vendor/kingdee-skills/cosmic-unittest/examples/common-test.md +257 -0
  59. package/vendor/kingdee-skills/cosmic-unittest/examples/formplugin-test.md +560 -0
  60. package/vendor/kingdee-skills/cosmic-unittest/examples/op-plugin-test.md +231 -0
  61. package/vendor/kingdee-skills/cosmic-unittest/examples/validator-test.md +232 -0
  62. package/vendor/kingdee-skills/cosmic-unittest/patterns/business-helper.md +184 -0
  63. package/vendor/kingdee-skills/cosmic-unittest/patterns/common-module.md +355 -0
  64. package/vendor/kingdee-skills/cosmic-unittest/patterns/convert-plugin.md +130 -0
  65. package/vendor/kingdee-skills/cosmic-unittest/patterns/formplugin.md +235 -0
  66. package/vendor/kingdee-skills/cosmic-unittest/patterns/op-plugin.md +226 -0
  67. package/vendor/kingdee-skills/cosmic-unittest/patterns/validator.md +206 -0
  68. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/SKILL.md +674 -0
  69. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/advanced-scenario-checklist.md +307 -0
  70. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/algox-performance-checklist.md +129 -0
  71. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/coding-standard-checklist.md +491 -0
  72. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/cosmic-api-checklist.md +285 -0
  73. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/data-access-checklist.md +261 -0
  74. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/data-transaction-checklist.md +390 -0
  75. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/domain-logic-checklist.md +295 -0
  76. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/form-plugin-checklist.md +508 -0
  77. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/infra-checklist.md +254 -0
  78. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/ksql-checklist.md +305 -0
  79. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/lifecycle-checklist.md +298 -0
  80. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/operation-plugin-checklist.md +442 -0
  81. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/test-mock-checklist.md +120 -0
  82. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/ui-performance-checklist.md +320 -0
  83. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/scripts/pattern-matcher.py +336 -0
  84. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/scripts/review-score-calculator.py +121 -0
  85. package/vendor/kingdee-skills/ok-cosmic/CHANGELOG.md +295 -0
  86. package/vendor/kingdee-skills/ok-cosmic/README.md +460 -0
  87. package/vendor/kingdee-skills/ok-cosmic/SKILL.md +287 -0
  88. package/vendor/kingdee-skills/ok-cosmic/agents/openai.yaml +17 -0
  89. package/vendor/kingdee-skills/ok-cosmic/assets/BatchImportPluginTemplate.java +93 -0
  90. package/vendor/kingdee-skills/ok-cosmic/assets/BillPlugInTemplate.java +156 -0
  91. package/vendor/kingdee-skills/ok-cosmic/assets/ConvertPlugInTemplate.java +255 -0
  92. package/vendor/kingdee-skills/ok-cosmic/assets/FormPluginTemplate.java +597 -0
  93. package/vendor/kingdee-skills/ok-cosmic/assets/IWorkflowPluginTemplate.java +91 -0
  94. package/vendor/kingdee-skills/ok-cosmic/assets/ListPluginTemplate.java +194 -0
  95. package/vendor/kingdee-skills/ok-cosmic/assets/OpPluginTemplate.java +201 -0
  96. package/vendor/kingdee-skills/ok-cosmic/assets/OpenApiControllerTemplate.java +103 -0
  97. package/vendor/kingdee-skills/ok-cosmic/assets/PrintPluginTemplate.java +95 -0
  98. package/vendor/kingdee-skills/ok-cosmic/assets/ReportFormPluginTemplate.java +257 -0
  99. package/vendor/kingdee-skills/ok-cosmic/assets/ReportListDataPluginTemplate.java +70 -0
  100. package/vendor/kingdee-skills/ok-cosmic/assets/StandardTreeListPluginTemplate.java +130 -0
  101. package/vendor/kingdee-skills/ok-cosmic/assets/TaskTemplate.java +80 -0
  102. package/vendor/kingdee-skills/ok-cosmic/assets/TreeListPluginTemplate.java +152 -0
  103. package/vendor/kingdee-skills/ok-cosmic/assets/WriteBackPlugInTemplate.java +286 -0
  104. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/attachment/AttachmentUploadBindSample.java +93 -0
  105. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/botp/BotpTracePushSample.java +168 -0
  106. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/botp/SampleConvertPlugin.java +223 -0
  107. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/cache/SampleCacheUsage.java +218 -0
  108. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/concurrent/SampleThreadPoolBatch.java +156 -0
  109. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/data/DynamicObjectCrudSample.java +205 -0
  110. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/data/DynamicObjectOpsSample.java +100 -0
  111. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/BeforeOperationConfirmSample.java +217 -0
  112. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/ConfirmDialogSample.java +131 -0
  113. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/EntryRowCalculateSample.java +116 -0
  114. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/F7FilterSample.java +134 -0
  115. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/GetAndSetValueSample.java +176 -0
  116. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/HyperlinkJumpSample.java +124 -0
  117. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/OpenBillModalSample.java +253 -0
  118. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/ReturnParentDataSample.java +295 -0
  119. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/TreeControlSample.java +140 -0
  120. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/ViewControlOpsSample.java +132 -0
  121. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/list/ListPluginBasicSample.java +170 -0
  122. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/list/ListPreOpenFilterSample.java +68 -0
  123. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/message/MessageNotifySample.java +95 -0
  124. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/mq/SampleMQConsumer.java +198 -0
  125. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/mq/sample_mq.xml +15 -0
  126. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/operation/OpAddValidatorsSample.java +137 -0
  127. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/operation/OperationOptionBridgeSample.java +228 -0
  128. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/package-info.java +19 -0
  129. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/query/BaseDataQuerySample.java +194 -0
  130. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/query/BatchQuerySample.java +368 -0
  131. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/query/DataSetQueryStatSample.java +131 -0
  132. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/report/SampleReportFormPlugin.java +179 -0
  133. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/report/SampleReportListDataPlugin.java +616 -0
  134. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/snippets-guide.md +64 -0
  135. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/task/ScheduleTaskSample.java +160 -0
  136. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/workflow/SampleWorkflowPlugin.java +302 -0
  137. package/vendor/kingdee-skills/ok-cosmic/manifest.json +78 -0
  138. package/vendor/kingdee-skills/ok-cosmic/ok-cosmic-intro.html +903 -0
  139. package/vendor/kingdee-skills/ok-cosmic/references/adv/attachment-api.md +114 -0
  140. package/vendor/kingdee-skills/ok-cosmic/references/adv/botp-convert.md +98 -0
  141. package/vendor/kingdee-skills/ok-cosmic/references/adv/dynamic-object.md +113 -0
  142. package/vendor/kingdee-skills/ok-cosmic/references/adv/entity-metadata.md +123 -0
  143. package/vendor/kingdee-skills/ok-cosmic/references/adv/event-lifecycle.md +184 -0
  144. package/vendor/kingdee-skills/ok-cosmic/references/adv/flex-prop.md +114 -0
  145. package/vendor/kingdee-skills/ok-cosmic/references/adv/form-utils.md +133 -0
  146. package/vendor/kingdee-skills/ok-cosmic/references/adv/operate-chain.md +159 -0
  147. package/vendor/kingdee-skills/ok-cosmic/references/adv/plugin-base.md +218 -0
  148. package/vendor/kingdee-skills/ok-cosmic/references/adv/query-dataset.md +149 -0
  149. package/vendor/kingdee-skills/ok-cosmic/references/adv/request-context.md +88 -0
  150. package/vendor/kingdee-skills/ok-cosmic/references/adv/view-handler.md +157 -0
  151. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-bill.md +76 -0
  152. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-botp.md +70 -0
  153. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-form.md +165 -0
  154. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-import.md +69 -0
  155. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-list.md +227 -0
  156. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-openapi.md +112 -0
  157. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-operation.md +135 -0
  158. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-print.md +65 -0
  159. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-report-data.md +64 -0
  160. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-report-form.md +90 -0
  161. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-task.md +62 -0
  162. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-tree-list.md +71 -0
  163. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-workflow.md +82 -0
  164. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-writeback.md +71 -0
  165. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-algo.md +67 -0
  166. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-cache.md +63 -0
  167. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-dynamic-model-svc.md +82 -0
  168. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-dynamic-object.md +70 -0
  169. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-entity-model.md +61 -0
  170. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-exception.md +64 -0
  171. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-file.md +63 -0
  172. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-id.md +47 -0
  173. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-lock.md +61 -0
  174. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-log.md +63 -0
  175. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-network-control.md +70 -0
  176. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-orm-access.md +78 -0
  177. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-request-context.md +62 -0
  178. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-threadpool.md +63 -0
  179. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-tx.md +64 -0
  180. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-utils.md +67 -0
  181. package/vendor/kingdee-skills/ok-cosmic/requirements.txt +2 -0
  182. package/vendor/kingdee-skills/ok-cosmic/rules/a-layer-rules.json +24 -0
  183. package/vendor/kingdee-skills/ok-cosmic/rules/anti-patterns.md +48 -0
  184. package/vendor/kingdee-skills/ok-cosmic/rules/cheat-sheet.md +256 -0
  185. package/vendor/kingdee-skills/ok-cosmic/rules/coding-preferences.md +140 -0
  186. package/vendor/kingdee-skills/ok-cosmic/rules/constraints.md +61 -0
  187. package/vendor/kingdee-skills/ok-cosmic/rules/decision-matrix.md +222 -0
  188. package/vendor/kingdee-skills/ok-cosmic/rules/intent-routing.md +94 -0
  189. package/vendor/kingdee-skills/ok-cosmic/rules/platform-baseline.md +69 -0
  190. package/vendor/kingdee-skills/ok-cosmic/rules/post-check.md +109 -0
  191. package/vendor/kingdee-skills/ok-cosmic/scripts/config_loader.py +204 -0
  192. package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-api-knowledge.py +910 -0
  193. package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-basedata-query.py +359 -0
  194. package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-config-check.py +181 -0
  195. package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-extpoints-query.py +389 -0
  196. package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-form-metadata.py +856 -0
  197. package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-post-check.py +262 -0
  198. package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-post-lint.py +293 -0
  199. package/vendor/kingdee-skills/ok-cosmic/scripts/lint/__init__.py +2 -0
  200. package/vendor/kingdee-skills/ok-cosmic/scripts/lint/base.py +393 -0
  201. package/vendor/kingdee-skills/ok-cosmic/scripts/lint/resource_check.py +176 -0
  202. package/vendor/kingdee-skills/ok-cosmic/scripts/lint/scene_check.py +375 -0
  203. package/vendor/kingdee-skills/ok-cosmic/scripts/lint/style_check.py +434 -0
  204. package/vendor/kingdee-skills/ok-cosmic/scripts/lint/verify_check.py +36 -0
  205. package/vendor/kingdee-skills/ok-cosmic/scripts/route_client.py +186 -0
  206. package/vendor/kingdee-skills/ok-cosmic/scripts/script_utils.py +40 -0
  207. package/vendor/kingdee-skills/ok-cosmic/scripts/sqlite_cache.py +142 -0
  208. package/vendor/kingdee-skills/ok-cosmic/setup/cuslib/kd-cd-cosmic-commons.jar +0 -0
  209. package/vendor/kingdee-skills/ok-cosmic/setup/cuslib/kd-cd-cosmic-features.jar +0 -0
  210. package/vendor/kingdee-skills/ok-cosmic/setup/ok-cosmic-docs.db +0 -0
  211. package/vendor/kingdee-skills/ok-cosmic/setup/ok-cosmic.json +13 -0
  212. package/vendor/kingdee-skills/ok-cosmic/setup/setup-mac.sh +18 -0
  213. package/vendor/kingdee-skills/ok-cosmic/setup/setup-windows.bat +53 -0
  214. package/vendor/kingdee-skills/ok-cosmic/setup/setup.jar +0 -0
  215. package/vendor/kingdee-skills/ok-ksql/SKILL.md +81 -0
  216. package/vendor/kingdee-skills/ok-ksql/agents/openai.yaml +7 -0
  217. package/vendor/kingdee-skills/ok-ksql/manifest.json +14 -0
  218. package/vendor/kingdee-skills/ok-ksql/references/ksql-datafix.md +452 -0
  219. package/vendor/kingdee-skills/ok-ksql/scripts/ksql_lint.py +363 -0
@@ -0,0 +1,359 @@
1
+ #!/usr/bin/env python3
2
+ # SPDX-License-Identifier: NOASSERTION
3
+ """
4
+ cosmic-basedata-query.py — Cosmic base data query and cache tool.
5
+
6
+ Usage:
7
+ python3 cosmic-basedata-query.py --config ok-cosmic.json get --entity-id bd_supplier
8
+ python3 cosmic-basedata-query.py --config ok-cosmic.json get --entity-id bd_supplier --number-or-name 1001
9
+ python3 cosmic-basedata-query.py --config ok-cosmic.json get --entity-id bd_supplier --number-or-name 华东 --full
10
+ python3 cosmic-basedata-query.py --config ok-cosmic.json get --entity-id bd_supplier --refresh
11
+ python3 cosmic-basedata-query.py --config ok-cosmic.json get --entity-id bd_supplier --json
12
+
13
+ What it provides:
14
+ 1. Query one base data result by entityId plus number/name keyword
15
+ 2. Local SQLite cache in a dedicated table with a fixed 10-minute TTL
16
+ 3. Config-first API resolution with environment-variable fallback
17
+ 4. Human-readable summary output with optional JSON mode
18
+
19
+ What it does NOT do:
20
+ - It does not infer entityId from Chinese labels or form field names
21
+ - It only accepts entityId that is already confirmed by the user or by the metadata script
22
+ - It does not auto-query metadata; when entityId is unknown, query metadata for refType or look up the real English identifier by Chinese name first
23
+ - It does not batch query multiple entityIds in one request
24
+
25
+ Prerequisites:
26
+ - A valid ok-cosmic.json or equivalent project config
27
+ - A configured graph.dbPath for SQLite cache storage
28
+ - A reachable route.apiUrl (`runtime/route`) configured by config or environment
29
+ """
30
+
31
+ import argparse
32
+ import json
33
+ import sys
34
+ from typing import Any, Dict, List, Optional
35
+
36
+ from config_loader import load_project_config
37
+ from route_client import RouteClient, unwrap_route_raw
38
+ from sqlite_cache import JsonSqliteCache, resolve_graph_db_path
39
+ from script_utils import FriendlyArgumentParser, run_cli
40
+
41
+
42
+ CACHE_TTL_SECONDS = 600
43
+ TABLE_NAME = "basedata_query_cache"
44
+
45
+
46
+ def contains_cjk(text: str) -> bool:
47
+ return any("\u4e00" <= ch <= "\u9fff" for ch in text)
48
+
49
+
50
+ def _looks_like_basedata_payload(value: Any) -> bool:
51
+ return isinstance(value, dict) and (
52
+ "entityId" in value
53
+ or "numberOrName" in value
54
+ or "traceId" in value
55
+ or "data" in value
56
+ )
57
+
58
+
59
+ def _unwrap_route_raw(raw: Dict[str, Any]) -> Dict[str, Any]:
60
+ return unwrap_route_raw(raw, _looks_like_basedata_payload)
61
+
62
+
63
+ class BaseDataDbCache:
64
+ def __init__(self, db_path: str, ttl: int = CACHE_TTL_SECONDS):
65
+ self._cache = JsonSqliteCache(
66
+ db_path,
67
+ table_name=TABLE_NAME,
68
+ key_column="cache_key",
69
+ create_sql=f"""
70
+ CREATE TABLE IF NOT EXISTS {TABLE_NAME} (
71
+ cache_key TEXT PRIMARY KEY,
72
+ entity_id TEXT NOT NULL,
73
+ number_or_name TEXT NOT NULL,
74
+ full INTEGER NOT NULL,
75
+ payload TEXT NOT NULL,
76
+ updated_at INTEGER NOT NULL
77
+ )
78
+ """,
79
+ ttl=ttl,
80
+ init_error_message="初始化基础资料缓存表失败",
81
+ write_error_message="写入基础资料缓存失败",
82
+ )
83
+
84
+ def get(self, cache_key: str) -> Optional[Dict[str, Any]]:
85
+ return self._cache.get(cache_key)
86
+
87
+ def set(
88
+ self,
89
+ cache_key: str,
90
+ entity_id: str,
91
+ number_or_name: str,
92
+ full: bool,
93
+ payload: Dict[str, Any],
94
+ ):
95
+ self._cache.set_payload(
96
+ cache_key,
97
+ payload,
98
+ extra_columns=("entity_id", "number_or_name", "full"),
99
+ extra_values=(entity_id, number_or_name, 1 if full else 0),
100
+ )
101
+
102
+ def remove(self, cache_key: str):
103
+ self._cache.remove(cache_key)
104
+
105
+
106
+ class BaseDataQuery:
107
+ def __init__(self, config: Dict[str, Any], debug: bool = False):
108
+ self.debug = debug
109
+
110
+ route_config = config.get("route", {})
111
+ if not isinstance(route_config, dict):
112
+ route_config = {}
113
+ self.db_path = resolve_graph_db_path(
114
+ config,
115
+ "未配置 graph.dbPath,请在 ok-cosmic.json 中指定 SQLite 数据库路径。",
116
+ )
117
+ self.cache = BaseDataDbCache(self.db_path, ttl=CACHE_TTL_SECONDS)
118
+ self.route_client = RouteClient(
119
+ route_config,
120
+ debug=debug,
121
+ missing_message=(
122
+ "未配置基础资料查询 API。请在 ok-cosmic.json 的 route.apiUrl 中配置统一路由,"
123
+ "或设置 COSMIC_ROUTE_API / COSMIC_RUNTIME_ROUTE_API 环境变量。"
124
+ ),
125
+ )
126
+
127
+ def _log_debug(self, msg: str):
128
+ if self.debug:
129
+ print(f" (DEBUG) {msg}", file=sys.stderr)
130
+
131
+ @staticmethod
132
+ def _cache_key(entity_id: str, number_or_name: str, full: bool) -> str:
133
+ return f"{entity_id}|{number_or_name}|{1 if full else 0}"
134
+
135
+ def _post(self, payload: Dict[str, Any]) -> Dict[str, Any]:
136
+ return self.route_client.post(payload)
137
+
138
+ @staticmethod
139
+ def _normalize_result(
140
+ raw: Dict[str, Any],
141
+ entity_id: str,
142
+ number_or_name: str,
143
+ full: bool,
144
+ ) -> Dict[str, Any]:
145
+ payload_data = raw.get("data")
146
+ if not isinstance(payload_data, dict):
147
+ return {
148
+ "entityId": entity_id,
149
+ "numberOrName": number_or_name,
150
+ "full": full,
151
+ "traceId": None,
152
+ "data": payload_data,
153
+ }
154
+
155
+ return {
156
+ "entityId": payload_data.get("entityId", entity_id),
157
+ "numberOrName": payload_data.get("numberOrName", number_or_name),
158
+ "full": bool(payload_data.get("full", full)),
159
+ "traceId": payload_data.get("traceId"),
160
+ "data": payload_data.get("data"),
161
+ }
162
+
163
+ def query_one(self, entity_id: str, number_or_name: str = "", full: bool = False) -> Dict[str, Any]:
164
+ normalized_entity_id = (entity_id or "").strip()
165
+ normalized_keyword = (number_or_name or "").strip()
166
+ normalized_full = bool(full)
167
+
168
+ if not normalized_entity_id:
169
+ raise ValueError(
170
+ "entityId 不能为空。只允许使用用户明确给出的准确英文标识或元数据脚本确认出的真实标识;如不清楚,请先用元数据脚本查 refType 或按中文名称查英文标识。"
171
+ )
172
+ if contains_cjk(normalized_entity_id):
173
+ raise ValueError(
174
+ "entityId 必须是已确认的英文基础资料标识;只允许使用用户明确给出的准确英文标识或元数据脚本确认出的真实标识,不能直接传中文名称。"
175
+ )
176
+
177
+ cache_key = self._cache_key(normalized_entity_id, normalized_keyword, normalized_full)
178
+ cached = self.cache.get(cache_key)
179
+ if cached:
180
+ self._log_debug(f"命中基础资料缓存: {cache_key}")
181
+ return {"status": "ok", "source": "cache", **cached}
182
+
183
+ req_data = {
184
+ "entityId": normalized_entity_id,
185
+ "numberOrName": normalized_keyword,
186
+ "full": normalized_full,
187
+ }
188
+ payload = {
189
+ "data": {
190
+ "type": "basedata",
191
+ "reqData": req_data,
192
+ }
193
+ }
194
+ raw = _unwrap_route_raw(self._post(payload))
195
+
196
+ if raw.get("status") is False:
197
+ message = str(raw.get("message") or "remote api status=false")
198
+ error_code = raw.get("errorCode")
199
+ if " is not exist" in message:
200
+ return {
201
+ "status": "not_found",
202
+ "message": message,
203
+ "errorCode": error_code,
204
+ "entityId": normalized_entity_id,
205
+ "numberOrName": normalized_keyword,
206
+ "full": normalized_full,
207
+ }
208
+ raise RuntimeError(f"{message} (errorCode={error_code})")
209
+
210
+ result = self._normalize_result(raw, normalized_entity_id, normalized_keyword, normalized_full)
211
+ self.cache.set(cache_key, normalized_entity_id, normalized_keyword, normalized_full, result)
212
+ return {"status": "ok", "source": "api", **result}
213
+
214
+ def refresh(self, entity_id: str, number_or_name: str = "", full: bool = False):
215
+ cache_key = self._cache_key((entity_id or "").strip(), (number_or_name or "").strip(), bool(full))
216
+ self.cache.remove(cache_key)
217
+
218
+ @staticmethod
219
+ def _maybe_render_mapping_table(data: Any) -> List[str]:
220
+ if not isinstance(data, list) or not data:
221
+ return []
222
+
223
+ rows: List[Dict[str, str]] = []
224
+ for item in data:
225
+ if not isinstance(item, dict):
226
+ return []
227
+ number = item.get("number") or item.get("Number") or item.get("code") or item.get("Code")
228
+ name = item.get("name") or item.get("Name")
229
+ item_id = item.get("id") or item.get("Id") or item.get("pkId") or item.get("masterId")
230
+ if number is None and name is None and item_id is None:
231
+ return []
232
+ rows.append(
233
+ {
234
+ "number": str(number or "-"),
235
+ "name": str(name or "-"),
236
+ "id": str(item_id or "-"),
237
+ }
238
+ )
239
+
240
+ md = [
241
+ "### [List] 编码名称映射",
242
+ "| 编码 | 名称 | ID |",
243
+ "| :--- | :--- | :--- |",
244
+ ]
245
+ for row in rows:
246
+ md.append(f"| `{row['number']}` | {row['name']} | `{row['id']}` |")
247
+ return md
248
+
249
+ def render(self, result: Dict[str, Any], json_mode: bool = False) -> str:
250
+ if json_mode:
251
+ return json.dumps(result, ensure_ascii=False, indent=2)
252
+
253
+ status = result.get("status")
254
+ if status == "not_found":
255
+ message = str(result.get("message") or "未找到基础资料")
256
+ error_code = result.get("errorCode")
257
+ lines = [
258
+ "## ✖️ 未找到基础资料",
259
+ f"**基础资料标识**: `{result.get('entityId') or '-'}`",
260
+ f"**查询词**: `{result.get('numberOrName') or '-'}`",
261
+ f"**完整模式**: `{bool(result.get('full'))}`",
262
+ f"**说明**: {message}",
263
+ ]
264
+ if error_code is not None:
265
+ lines.append(f"**错误码**: `{error_code}`")
266
+ return "\n".join(lines)
267
+
268
+ lines = [
269
+ f"## [BaseData] 基础资料: `{result.get('entityId') or '-'}`",
270
+ f"**查询词**: `{result.get('numberOrName') or '(空,通常返回前50条映射)'}`",
271
+ f"**完整模式**: `{bool(result.get('full'))}`",
272
+ f"**结果来源**: `{result.get('source') or '-'}`",
273
+ ]
274
+
275
+ trace_id = result.get("traceId")
276
+ if trace_id:
277
+ lines.append(f"**traceId**: `{trace_id}`")
278
+
279
+ data = result.get("data")
280
+ mapping_table = self._maybe_render_mapping_table(data)
281
+ if mapping_table:
282
+ lines.append("")
283
+ lines.extend(mapping_table)
284
+ else:
285
+ lines.append("\n### [Data] 返回数据")
286
+ lines.append("```json")
287
+ lines.append(json.dumps(data, ensure_ascii=False, indent=2))
288
+ lines.append("```")
289
+
290
+ return "\n".join(lines)
291
+
292
+
293
+ def main():
294
+ parser = FriendlyArgumentParser(
295
+ description="Cosmic BaseData Query CLI — 苍穹基础资料在线查询(带本地缓存)",
296
+ formatter_class=argparse.RawDescriptionHelpFormatter,
297
+ epilog="""\
298
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
299
+ 推荐用法
300
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
301
+ # 按 entityId + 编码/名称查询
302
+ %(prog)s --config ok-cosmic.json get --entity-id <entityId> --number-or-name <keyword>
303
+
304
+ # 不传 --number-or-name 时返回前 50 条编码名称映射
305
+ %(prog)s --config ok-cosmic.json get --entity-id <entityId>
306
+
307
+ # 返回完整数据包
308
+ %(prog)s --config ok-cosmic.json get --entity-id <entityId> --full
309
+
310
+ # 清除缓存后重新请求
311
+ %(prog)s --config ok-cosmic.json get --entity-id <entityId> --refresh
312
+
313
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
314
+ AI 调用约束(摘要,完整约束见 SKILL.md 跨脚本硬约束)
315
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
316
+ - entityId 必须来自"用户明确给出"或"元数据脚本确认";来源不清时停止,先查元数据。
317
+ - 默认精确查询,先传编码或精确名称;--full 仅在需要完整结构时使用。
318
+
319
+ 缓存说明:
320
+ - 使用 graph.dbPath 对应的 SQLite 文件,独立表 basedata_query_cache
321
+ - 固定缓存时长 10 分钟,可用 --refresh 手动刷新
322
+ """,
323
+ )
324
+ parser.add_argument("--config", help="Path to ok-cosmic.json")
325
+ parser.add_argument("--debug", action="store_true")
326
+
327
+ sub_parser = parser.add_subparsers(dest="command")
328
+ get_parser = sub_parser.add_parser("get")
329
+ get_parser.add_argument(
330
+ "--entity-id",
331
+ required=True,
332
+ help="基础资料标识(英文 entityId,且来源必须已确认;不确定时先用元数据脚本查 refType 或按中文名称查英文标识)",
333
+ )
334
+ get_parser.add_argument("--number-or-name", default="", help="编码或名称;为空时通常返回前50条映射")
335
+ get_parser.add_argument("--keyword", dest="number_or_name", help="--number-or-name 的别名")
336
+ get_parser.add_argument("--full", action="store_true", help="返回完整字段")
337
+ get_parser.add_argument("--json", action="store_true", help="直接输出 JSON")
338
+ get_parser.add_argument("--refresh", action="store_true", help="删除当前查询条件对应的本地缓存后再请求")
339
+ get_parser.add_argument("--debug", action="store_true")
340
+
341
+ args = parser.parse_args()
342
+ if args.command != "get":
343
+ parser.print_help()
344
+ return
345
+
346
+ try:
347
+ config = load_project_config(args.config)
348
+ query = BaseDataQuery(config, debug=(args.debug or getattr(args, "debug", False)))
349
+ if args.refresh:
350
+ query.refresh(args.entity_id, args.number_or_name, args.full)
351
+ result = query.query_one(args.entity_id, args.number_or_name, args.full)
352
+ print(query.render(result, json_mode=args.json))
353
+ except Exception as e:
354
+ print(f"✖️ 错误: {str(e)}", file=sys.stderr)
355
+ sys.exit(1)
356
+
357
+
358
+ if __name__ == "__main__":
359
+ sys.exit(run_cli(main))
@@ -0,0 +1,181 @@
1
+ #!/usr/bin/env python3
2
+ # SPDX-License-Identifier: NOASSERTION
3
+ """
4
+ cosmic-config-check.py — Step 0 comprehensive preflight for ok-cosmic.
5
+
6
+ Checks performed:
7
+ 1. Python version (>= 3.8)
8
+ 2. Python dependencies — auto-install if missing (tree-sitter, tree-sitter-java)
9
+ 3. ok-cosmic.json configuration validation
10
+
11
+ Usage:
12
+ python3 cosmic-config-check.py
13
+ python3 cosmic-config-check.py --config /path/to/ok-cosmic.json
14
+ python3 cosmic-config-check.py --config ok-cosmic.json --strict
15
+ python3 cosmic-config-check.py --config ok-cosmic.json --json
16
+ """
17
+
18
+ import argparse
19
+ import json
20
+ import os
21
+ import subprocess
22
+ import sys
23
+ from typing import Any, Dict, List
24
+
25
+ from config_loader import read_project_config, validate_project_config
26
+ from script_utils import FriendlyArgumentParser, run_cli
27
+
28
+ # ──────────────────────────────────────────────
29
+ # Python 依赖包清单(module_name → pip_name)
30
+ # ──────────────────────────────────────────────
31
+
32
+ REQUIRED_PACKAGES = {
33
+ "tree_sitter": "tree-sitter",
34
+ "tree_sitter_java": "tree-sitter-java",
35
+ }
36
+
37
+
38
+ # 进度输出流(--json 模式时切换到 stderr,避免污染 JSON 输出)
39
+ _progress_out = sys.stdout
40
+
41
+
42
+ def _progress(msg: str) -> None:
43
+ print(msg, file=_progress_out)
44
+
45
+
46
+ # ──────────────────────────────────────────────
47
+ # Phase 1: 运行环境检查
48
+ # ──────────────────────────────────────────────
49
+
50
+ def _check_python_version(issues: List[Dict[str, str]]) -> None:
51
+ """检查 Python 版本 >= 3.8。"""
52
+ ver = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
53
+ if sys.version_info < (3, 8):
54
+ issues.append({"level": "ERROR", "key": "python.version",
55
+ "message": f"Python >= 3.8 required, current: {ver}"})
56
+ else:
57
+ _progress(f"[OK] Python {ver}")
58
+
59
+
60
+ def _check_and_install_dependencies(issues: List[Dict[str, str]]) -> None:
61
+ """检测缺失的 Python 依赖包并自动安装。"""
62
+ missing = []
63
+ for module_name, pip_name in REQUIRED_PACKAGES.items():
64
+ try:
65
+ __import__(module_name)
66
+ except ImportError:
67
+ missing.append((module_name, pip_name))
68
+
69
+ if not missing:
70
+ names = ", ".join(REQUIRED_PACKAGES.values())
71
+ _progress(f"[OK] Python 依赖已就绪 ({names})")
72
+ return
73
+
74
+ pip_names = [p for _, p in missing]
75
+ display = ", ".join(pip_names)
76
+ _progress(f"[AUTO] 正在安装缺失的 Python 依赖: {display} ...")
77
+ try:
78
+ result = subprocess.run(
79
+ [sys.executable, "-m", "pip", "install", "--quiet"] + pip_names,
80
+ capture_output=True, text=True, timeout=120,
81
+ )
82
+ if result.returncode == 0:
83
+ _progress(f"[OK] 已自动安装: {display}")
84
+ else:
85
+ err = (result.stderr or "").strip()[:200]
86
+ issues.append({"level": "ERROR", "key": "python.deps",
87
+ "message": f"自动安装失败: {err}。请手动执行: {sys.executable} -m pip install {' '.join(pip_names)}"})
88
+ except subprocess.TimeoutExpired:
89
+ issues.append({"level": "ERROR", "key": "python.deps",
90
+ "message": f"安装超时。请手动执行: {sys.executable} -m pip install {' '.join(pip_names)}"})
91
+ except Exception as e:
92
+ issues.append({"level": "ERROR", "key": "python.deps",
93
+ "message": f"安装异常: {e}。请手动执行: {sys.executable} -m pip install {' '.join(pip_names)}"})
94
+
95
+
96
+
97
+
98
+ # ──────────────────────────────────────────────
99
+ # 报告输出
100
+ # ──────────────────────────────────────────────
101
+
102
+ def _group_issues(issues: List[Dict[str, str]]) -> Dict[str, List[Dict[str, str]]]:
103
+ errors = [issue for issue in issues if issue.get("level") == "ERROR"]
104
+ warnings = [issue for issue in issues if issue.get("level") == "WARNING"]
105
+ return {"errors": errors, "warnings": warnings}
106
+
107
+
108
+ def _print_text_report(issues: List[Dict[str, str]]) -> None:
109
+ """打印环境+配置检查的文本报告([OK] 行已在检查过程中实时输出)。"""
110
+ for issue in issues:
111
+ level = issue.get("level", "INFO")
112
+ key = issue.get("key", "-")
113
+ message = issue.get("message", "")
114
+ print(f"[{level}] {key}: {message}")
115
+
116
+ grouped = _group_issues(issues)
117
+ errs, warns = len(grouped["errors"]), len(grouped["warnings"])
118
+ print(f"[SUMMARY] errors={errs} warnings={warns}")
119
+
120
+
121
+ # ──────────────────────────────────────────────
122
+ # 主入口
123
+ # ──────────────────────────────────────────────
124
+
125
+ def main() -> int:
126
+ parser = FriendlyArgumentParser(
127
+ description="Step 0 环境与配置预检:检查 Python 依赖(自动安装)、ok-cosmic.json 配置完整性。"
128
+ )
129
+ parser.add_argument("--config", help="Path to ok-cosmic.json")
130
+ parser.add_argument("--strict", action="store_true", help="Treat warnings as failures.")
131
+ parser.add_argument("--json", action="store_true", help="Output machine-readable JSON report.")
132
+ args = parser.parse_args()
133
+
134
+ issues: List[Dict[str, str]] = []
135
+
136
+ # --json 模式下,进度信息输出到 stderr,避免污染 JSON 输出
137
+ global _progress_out
138
+ if args.json:
139
+ _progress_out = sys.stderr
140
+
141
+ # Phase 1: 运行环境
142
+ _check_python_version(issues)
143
+ _check_and_install_dependencies(issues)
144
+
145
+ # Phase 2: 配置文件
146
+ config_path_str = args.config or "ok-cosmic.json"
147
+ try:
148
+ resolved_path, raw_config = read_project_config(args.config)
149
+ config: Dict[str, Any] = dict(raw_config)
150
+ config["__config_path__"] = str(resolved_path)
151
+ config["__config_dir__"] = str(resolved_path.parent)
152
+ _progress(f"[OK] 已找到配置文件: {resolved_path}")
153
+ issues.extend(validate_project_config(config, str(resolved_path)))
154
+ config_path_str = str(resolved_path)
155
+ except Exception as e:
156
+ issues.append({"level": "ERROR", "key": "__file__", "message": str(e)})
157
+
158
+ # 汇总
159
+ grouped = _group_issues(issues)
160
+ ok = not grouped["errors"] and not (args.strict and grouped["warnings"])
161
+
162
+ if args.json:
163
+ print(json.dumps({
164
+ "ok": ok,
165
+ "configPath": config_path_str,
166
+ "errors": grouped["errors"],
167
+ "warnings": grouped["warnings"],
168
+ }, ensure_ascii=False, indent=2))
169
+ else:
170
+ if issues:
171
+ _print_text_report(issues)
172
+ else:
173
+ print("[OK] 全部检查通过,未发现问题。")
174
+ if args.strict and grouped["warnings"] and not grouped["errors"]:
175
+ print("[STRICT] strict 模式下 warning 也会导致失败。", file=sys.stderr)
176
+
177
+ return 0 if ok else 1
178
+
179
+
180
+ if __name__ == "__main__":
181
+ sys.exit(run_cli(main))