gx-code-agent 0.0.0-stage → 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 (45) hide show
  1. package/README.md +276 -2
  2. package/bin/gx-stdio-mcp.js +145 -0
  3. package/bin/gx.js +99 -0
  4. package/contracts/README.md +40 -0
  5. package/contracts/alignment.schema.json +99 -0
  6. package/contracts/code-chunk.schema.json +28 -0
  7. package/contracts/evidence.schema.json +108 -0
  8. package/contracts/examples/alignment.example.json +26 -0
  9. package/contracts/examples/code-chunk.example.json +20 -0
  10. package/contracts/examples/evidence.add-field.json +49 -0
  11. package/contracts/examples/evidence.verify-manifest.json +52 -0
  12. package/contracts/examples/ext-method.example.json +14 -0
  13. package/contracts/examples/manifest.example.json +13 -0
  14. package/contracts/examples/unknown.extension-coverage.json +29 -0
  15. package/contracts/ext-method.schema.json +57 -0
  16. package/contracts/manifest.schema.json +27 -0
  17. package/contracts/unknown.schema.json +119 -0
  18. package/eval/README.md +52 -0
  19. package/eval/code-search-eval.json +216 -0
  20. package/package.json +37 -4
  21. package/src/adapters/cli/args.js +94 -0
  22. package/src/adapters/cli/output.js +66 -0
  23. package/src/adapters/platform/mcpClient.js +202 -0
  24. package/src/application/applyWorkflow.js +138 -0
  25. package/src/application/auditCommand.js +130 -0
  26. package/src/application/auditWorkflow.js +41 -0
  27. package/src/application/chunksCommand.js +87 -0
  28. package/src/application/errors.js +27 -0
  29. package/src/application/evalSearchCommand.js +148 -0
  30. package/src/application/initWorkflow.js +563 -0
  31. package/src/application/pullWorkflow.js +74 -0
  32. package/src/application/scanCommand.js +71 -0
  33. package/src/application/scanWorkflow.js +689 -0
  34. package/src/application/verifyWorkflow.js +142 -0
  35. package/src/domain/canonicalJson.js +72 -0
  36. package/src/domain/chunker.js +297 -0
  37. package/src/domain/digest.js +60 -0
  38. package/src/domain/java/JavaAstChunker.java +139 -0
  39. package/src/domain/java/JavaAstScanner.java +107 -0
  40. package/src/domain/javaAst.js +186 -0
  41. package/src/domain/jdk.js +66 -0
  42. package/src/domain/keepBlocks.js +122 -0
  43. package/src/store/backupStore.js +106 -0
  44. package/src/store/localStore.js +79 -0
  45. package/templates/platform-rules.md +29 -0
@@ -0,0 +1,106 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+
4
+ import { ensureDir, removeFile } from "./localStore.js";
5
+
6
+ /**
7
+ * 创建备份根目录:`.gx/backup/<ISO timestamp>`。
8
+ *
9
+ * @param {string} dir
10
+ * @returns {string}
11
+ */
12
+ export function createBackupRoot(dir) {
13
+ const stamp = new Date().toISOString().replace(/[:.]/g, "-");
14
+ return path.join(dir, ".gx", "backup", stamp);
15
+ }
16
+
17
+ /**
18
+ * 把文件安全地映射到备份目录内。
19
+ *
20
+ * @param {string} dir
21
+ * @param {string} file
22
+ * @returns {string}
23
+ */
24
+ function backupRelativePath(dir, file) {
25
+ const relative = path.relative(dir, file);
26
+ if (relative.startsWith("..") || path.isAbsolute(relative)) {
27
+ return path.join("_external", path.basename(file));
28
+ }
29
+ return relative;
30
+ }
31
+
32
+ /**
33
+ * 初始化写入事务:写入前备份原文件,失败时可回滚。
34
+ */
35
+ export class InitTransaction {
36
+ /**
37
+ * @param {string} dir 项目目录
38
+ * @param {string} backupRoot 备份根目录
39
+ */
40
+ constructor(dir, backupRoot) {
41
+ this.dir = dir;
42
+ this.backupRoot = backupRoot;
43
+ /** @type {{file: string, existed: boolean, backupPath: string | null}[]} */
44
+ this.entries = [];
45
+ this.seen = new Set();
46
+ }
47
+
48
+ /**
49
+ * 记录即将写入的文件,并在需要时备份。
50
+ *
51
+ * @param {string} file
52
+ * @returns {string | null} 备份路径
53
+ */
54
+ record(file) {
55
+ if (this.seen.has(file)) {
56
+ const existing = this.entries.find((entry) => entry.file === file);
57
+ return existing ? existing.backupPath : null;
58
+ }
59
+ this.seen.add(file);
60
+
61
+ const existed = fs.existsSync(file);
62
+ let backupPath = null;
63
+ if (existed) {
64
+ backupPath = path.join(this.backupRoot, backupRelativePath(this.dir, file));
65
+ ensureDir(path.dirname(backupPath));
66
+ fs.copyFileSync(file, backupPath);
67
+ }
68
+ this.entries.push({ file, existed, backupPath });
69
+ return backupPath;
70
+ }
71
+
72
+ /**
73
+ * 回滚所有已记录文件。
74
+ */
75
+ rollback() {
76
+ for (const entry of [...this.entries].reverse()) {
77
+ if (entry.existed && entry.backupPath) {
78
+ ensureDir(path.dirname(entry.file));
79
+ fs.copyFileSync(entry.backupPath, entry.file);
80
+ } else if (!entry.existed) {
81
+ removeFile(entry.file);
82
+ }
83
+ }
84
+ }
85
+ }
86
+
87
+ /**
88
+ * 只保留最近 N 次备份。
89
+ *
90
+ * @param {string} dir
91
+ * @param {number} keep
92
+ */
93
+ export function pruneBackups(dir, keep = 5) {
94
+ const root = path.join(dir, ".gx", "backup");
95
+ if (!fs.existsSync(root)) {
96
+ return;
97
+ }
98
+ const entries = fs.readdirSync(root, { withFileTypes: true })
99
+ .filter((entry) => entry.isDirectory())
100
+ .map((entry) => entry.name)
101
+ .sort()
102
+ .reverse();
103
+ for (const name of entries.slice(keep)) {
104
+ fs.rmSync(path.join(root, name), { recursive: true, force: true });
105
+ }
106
+ }
@@ -0,0 +1,79 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+
4
+ /**
5
+ * 读取 JSON;文件不存在或为空时返回 fallback。
6
+ *
7
+ * @param {string} file
8
+ * @param {unknown} fallback
9
+ * @returns {unknown}
10
+ */
11
+ export function readJson(file, fallback) {
12
+ if (!fs.existsSync(file)) {
13
+ return fallback;
14
+ }
15
+ const content = fs.readFileSync(file, "utf8").trim();
16
+ if (!content) {
17
+ return fallback;
18
+ }
19
+ try {
20
+ return JSON.parse(content);
21
+ } catch (error) {
22
+ throw new Error(`无法解析 ${file},请先确保它是合法 JSON。原因:${error.message}`);
23
+ }
24
+ }
25
+
26
+ /**
27
+ * 读取文本;不存在时返回空字符串。
28
+ *
29
+ * @param {string} file
30
+ * @returns {string}
31
+ */
32
+ export function readText(file) {
33
+ return fs.existsSync(file) ? fs.readFileSync(file, "utf8") : "";
34
+ }
35
+
36
+ /**
37
+ * 写入文本。
38
+ *
39
+ * @param {string} file
40
+ * @param {string} content
41
+ */
42
+ export function writeText(file, content) {
43
+ fs.mkdirSync(path.dirname(file), { recursive: true });
44
+ fs.writeFileSync(file, content, "utf8");
45
+ }
46
+
47
+ /**
48
+ * 写入 JSON。
49
+ *
50
+ * @param {string} file
51
+ * @param {unknown} data
52
+ */
53
+ export function writeJson(file, data) {
54
+ writeText(file, `${JSON.stringify(data, null, 2)}\n`);
55
+ }
56
+
57
+ /**
58
+ * 删除文件;不存在时忽略。
59
+ *
60
+ * @param {string} file
61
+ */
62
+ export function removeFile(file) {
63
+ try {
64
+ fs.unlinkSync(file);
65
+ } catch (error) {
66
+ if (!(error instanceof Error && "code" in error && error.code === "ENOENT")) {
67
+ throw error;
68
+ }
69
+ }
70
+ }
71
+
72
+ /**
73
+ * 确保目录存在。
74
+ *
75
+ * @param {string} dir
76
+ */
77
+ export function ensureDir(dir) {
78
+ fs.mkdirSync(dir, { recursive: true });
79
+ }
@@ -0,0 +1,29 @@
1
+ # GX 高代码平台:MCP 使用纪律
2
+
3
+ 你正在通过 `gx-code` MCP Server 访问 GX 高代码平台。请遵守:
4
+
5
+ ## 1. 结构变更只走 MCP
6
+ - 加表、加字段、改关系、加索引、改查询视图:必须调用 MCP 工具。
7
+ - 禁止直接编辑平台生成的 Entity / DTO / VO / QBean / Repository 等生成层文件。
8
+ - 写工具默认 `dryRun=true`;先看影响面,再显式 `apply`。
9
+
10
+ ## 2. 行为代码写在扩展层
11
+ - 业务逻辑写 `XxxServiceImpl`、`XxxHook`、自定义 Controller / DTO。
12
+ - 扩展方法优先加 `@ExtMethod(entity, intent, triggers)`,便于平台对账与检索。
13
+ - 修改扩展层后运行 `gx scan` 上报;提交前运行 `gx audit --strict` 检查缺注解、失效引用与 manifest 漂移。
14
+ - 平台再生代码时不会覆盖扩展层文件。
15
+
16
+ ## 3. 技术栈约束
17
+ - 持久层只使用 JPA + QueryDSL,禁止 MyBatis / MyBatis-Plus。
18
+ - 禁止物理外键,关联使用逻辑关联 + QueryDSL Join。
19
+ - ID 统一 `Long`,跨端序列化注意精度;基础字段 `isDeleted` / `createdDate` / `lastModifiedDate` 由基类维护。
20
+ - 避免 `@OneToMany(mappedBy=...)` 隐式加载,优先显式投影 / fetch join,防 N+1。
21
+
22
+ ## 4. 回答与修改要求
23
+ - 先读元数据与源文件,再给结论;不确定时先调用查询工具。
24
+ - 修改前说明「结构变更」还是「行为变更」,并列出受影响文件。
25
+ - 不要臆造字段、表名、接口;以 MCP 返回结果为准。
26
+
27
+ ## 5. 安全
28
+ - 不要输出、记录或提交 API Token。
29
+ - 生成层文件头带 checksum;发现不一致时先报告漂移,不要直接覆盖。