dsh-d365-kit 0.34.1 → 0.34.4

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 (75) hide show
  1. package/CHANGELOG.md +319 -308
  2. package/CHANGELOG.zh-CN.md +318 -307
  3. package/INSTALL.md +94 -94
  4. package/INSTALL.zh-CN.md +93 -93
  5. package/LICENSE +21 -21
  6. package/README.md +336 -327
  7. package/README.zh-CN.md +336 -327
  8. package/client.js +1818 -1818
  9. package/cordis.patch.yml +44 -44
  10. package/docs/en/architecture.md +172 -172
  11. package/docs/en/checks.md +184 -184
  12. package/docs/en/installation.md +151 -151
  13. package/docs/en/permissions.md +161 -161
  14. package/docs/en/scenarios.md +202 -202
  15. package/docs/en/tools.md +665 -665
  16. package/docs/en/troubleshooting.md +131 -131
  17. package/docs/zh/architecture.md +172 -172
  18. package/docs/zh/checks.md +184 -184
  19. package/docs/zh/installation.md +151 -151
  20. package/docs/zh/permissions.md +161 -161
  21. package/docs/zh/scenarios.md +202 -202
  22. package/docs/zh/tools.md +665 -665
  23. package/docs/zh/troubleshooting.md +131 -131
  24. package/examples/prompts.en.md +206 -206
  25. package/examples/prompts.zh-CN.md +206 -206
  26. package/examples/waivers.example.json +20 -20
  27. package/icon.svg +6 -6
  28. package/index.js +139 -139
  29. package/lib/auth.js +181 -181
  30. package/lib/client.js +496 -496
  31. package/lib/code-check.js +549 -549
  32. package/lib/config.js +323 -323
  33. package/lib/contract-history.js +49 -49
  34. package/lib/contract.js +583 -583
  35. package/lib/csharp-check.js +493 -493
  36. package/lib/data-migrate.js +1318 -1318
  37. package/lib/data-policy.js +78 -78
  38. package/lib/error-codes.js +80 -80
  39. package/lib/gitlab.js +161 -161
  40. package/lib/health.js +205 -205
  41. package/lib/migrate.js +732 -732
  42. package/lib/preflight.js +116 -116
  43. package/lib/refs.js +191 -191
  44. package/lib/resources.js +320 -320
  45. package/lib/retention-defaults.js +17 -17
  46. package/lib/retention.js +384 -384
  47. package/lib/runtime.js +232 -232
  48. package/lib/settings-http.js +512 -512
  49. package/lib/settings-store.js +371 -371
  50. package/lib/snapshot.js +149 -149
  51. package/lib/tool-code-check.js +133 -133
  52. package/lib/tool-configure.js +169 -169
  53. package/lib/tool-contract.js +376 -376
  54. package/lib/tool-data-sync.js +559 -559
  55. package/lib/tool-data-write.js +203 -203
  56. package/lib/tool-data.js +282 -282
  57. package/lib/tool-diff.js +484 -484
  58. package/lib/tool-environments.js +106 -106
  59. package/lib/tool-flows.js +540 -540
  60. package/lib/tool-health.js +127 -127
  61. package/lib/tool-layers.js +497 -497
  62. package/lib/tool-metadata.js +417 -417
  63. package/lib/tool-migrate.js +102 -102
  64. package/lib/tool-refs.js +206 -206
  65. package/lib/tool-reports.js +299 -299
  66. package/lib/tool-sync.js +430 -430
  67. package/lib/tool-write.js +563 -563
  68. package/lib/waivers.js +83 -83
  69. package/lib/write-actions.js +1374 -1374
  70. package/lib/write-policy.js +199 -199
  71. package/lib/write-store.js +167 -167
  72. package/locale/en.json +68 -68
  73. package/locale/zh.json +68 -68
  74. package/package.json +2 -2
  75. package/skills/d365-troubleshooting/SKILL.md +115 -115
@@ -1,167 +1,167 @@
1
- /**
2
- * Pending write plans and the change ledger.
3
- *
4
- * A plan is inert data. It becomes a change only when a person presses the
5
- * confirm button in the settings page, which then calls the Host's audited
6
- * execute route. The agent can create plans and read them; it cannot run one.
7
- */
8
- import { mkdir, readdir, readFile, rm, writeFile } from 'node:fs/promises'
9
- import { join } from 'node:path'
10
- import { dataRoot } from './snapshot.js'
11
-
12
- const PLAN_ID = /^[0-9A-Za-z-]{6,64}$/
13
-
14
- export function plansDir(config) {
15
- return join(dataRoot(config), 'pending-writes')
16
- }
17
-
18
- export function changesDir(config) {
19
- return join(dataRoot(config), 'changes')
20
- }
21
-
22
- function planPath(config, id) {
23
- if (!PLAN_ID.test(String(id ?? ''))) return undefined
24
- return join(plansDir(config), `${id}.json`)
25
- }
26
-
27
- /** Persist a plan and return it with its id. */
28
- export async function createPlan(config, plan) {
29
- const id = plan.id ?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`
30
- const record = { ...plan, id, createdAt: new Date().toISOString(), status: 'pending' }
31
- const dir = plansDir(config)
32
- await mkdir(dir, { recursive: true })
33
- await writeFile(join(dir, `${id}.json`), `${JSON.stringify(record, null, 2)}\n`, 'utf8')
34
- return record
35
- }
36
-
37
- export async function readPlan(config, id) {
38
- const path = planPath(config, id)
39
- if (!path) return undefined
40
- try {
41
- return JSON.parse(await readFile(path, 'utf8'))
42
- } catch {
43
- return undefined
44
- }
45
- }
46
-
47
- export async function deletePlan(config, id) {
48
- const path = planPath(config, id)
49
- if (!path) return false
50
- try {
51
- await rm(path)
52
- return true
53
- } catch {
54
- return false
55
- }
56
- }
57
-
58
- /**
59
- * Move a plan through its lifecycle: pending → running → done | failed.
60
- *
61
- * The file is the only guard against executing a plan twice. Marking it
62
- * "running" before the first write means a crash mid-plan leaves a record that
63
- * refuses a silent second run, instead of replaying the operations that already
64
- * landed.
65
- */
66
- export async function setPlanStatus(config, id, status, extra = {}) {
67
- const plan = await readPlan(config, id)
68
- if (!plan) return undefined
69
- const path = planPath(config, id)
70
- if (!path) return undefined
71
- const next = { ...plan, ...extra, status, updatedAt: new Date().toISOString() }
72
- await writeFile(path, `${JSON.stringify(next, null, 2)}\n`, 'utf8')
73
- return next
74
- }
75
-
76
- /** Every still-readable plan, newest first. */
77
- export async function listPlans(config) {
78
- const dir = plansDir(config)
79
- let names = []
80
- try {
81
- names = await readdir(dir)
82
- } catch {
83
- return []
84
- }
85
- const plans = []
86
- for (const name of names.filter((name) => name.endsWith('.json'))) {
87
- const plan = await readPlan(config, name.replace(/\.json$/, ''))
88
- if (plan) plans.push(plan)
89
- }
90
- return plans.sort((a, b) => String(b.createdAt).localeCompare(String(a.createdAt)))
91
- }
92
-
93
- /**
94
- * Append one executed change to the ledger. This file is the only record of
95
- * "what did the agent change and when", so it is written before the HTTP calls
96
- * settle and never rewritten.
97
- */
98
- export async function recordChange(config, record) {
99
- const dir = changesDir(config)
100
- await mkdir(dir, { recursive: true })
101
- const stamp = new Date().toISOString().replace(/[:.]/g, '-')
102
- const name = `${stamp}-${record.planId ?? 'plan'}.json`
103
- const path = join(dir, name)
104
- await writeFile(path, `${JSON.stringify({ ...record, recordedAt: new Date().toISOString() }, null, 2)}\n`, 'utf8')
105
- return path
106
- }
107
-
108
- /** Recent ledger entries, newest first. */
109
- export async function listChanges(config, limit = 20) {
110
- const dir = changesDir(config)
111
- let names = []
112
- try {
113
- names = await readdir(dir)
114
- } catch {
115
- return []
116
- }
117
- const files = names.filter((name) => name.endsWith('.json')).sort().reverse().slice(0, limit)
118
- const entries = []
119
- for (const name of files) {
120
- try {
121
- entries.push(JSON.parse(await readFile(join(dir, name), 'utf8')))
122
- } catch {
123
- // A half-written ledger entry is skipped rather than failing the page.
124
- }
125
- }
126
- return entries
127
- }
128
-
129
- /**
130
- * Record how one publish attempt ended. One file per plan: a re-publish
131
- * overwrites the previous outcome, which is what "current state" means here.
132
- */
133
- export async function writePublishReport(config, planId, record) {
134
- const dir = changesDir(config)
135
- await mkdir(dir, { recursive: true })
136
- const path = join(dir, `publish-${planId}.json`)
137
- await writeFile(path, `${JSON.stringify(record, null, 2)}\n`, 'utf8')
138
- return path
139
- }
140
-
141
- /**
142
- * How the publish for each executed plan ended.
143
- *
144
- * The publish runs detached, so the ledger can only say "running"; the sidecar
145
- * written when the request settles is the only place that knows the outcome.
146
- * Keyed by planId so the plans panel can show it next to the change.
147
- */
148
- export async function listPublishReports(config) {
149
- const dir = changesDir(config)
150
- let names = []
151
- try {
152
- names = await readdir(dir)
153
- } catch {
154
- return {}
155
- }
156
- const reports = {}
157
- for (const name of names.filter((name) => name.startsWith('publish-') && name.endsWith('.json'))) {
158
- try {
159
- const record = JSON.parse(await readFile(join(dir, name), 'utf8'))
160
- if (record?.planId) reports[record.planId] = record
161
- } catch {
162
- // Skip an unreadable sidecar; the UI falls back to the ledger state.
163
- }
164
- }
165
- return reports
166
- }
167
-
1
+ /**
2
+ * Pending write plans and the change ledger.
3
+ *
4
+ * A plan is inert data. It becomes a change only when a person presses the
5
+ * confirm button in the settings page, which then calls the Host's audited
6
+ * execute route. The agent can create plans and read them; it cannot run one.
7
+ */
8
+ import { mkdir, readdir, readFile, rm, writeFile } from 'node:fs/promises'
9
+ import { join } from 'node:path'
10
+ import { dataRoot } from './snapshot.js'
11
+
12
+ const PLAN_ID = /^[0-9A-Za-z-]{6,64}$/
13
+
14
+ export function plansDir(config) {
15
+ return join(dataRoot(config), 'pending-writes')
16
+ }
17
+
18
+ export function changesDir(config) {
19
+ return join(dataRoot(config), 'changes')
20
+ }
21
+
22
+ function planPath(config, id) {
23
+ if (!PLAN_ID.test(String(id ?? ''))) return undefined
24
+ return join(plansDir(config), `${id}.json`)
25
+ }
26
+
27
+ /** Persist a plan and return it with its id. */
28
+ export async function createPlan(config, plan) {
29
+ const id = plan.id ?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`
30
+ const record = { ...plan, id, createdAt: new Date().toISOString(), status: 'pending' }
31
+ const dir = plansDir(config)
32
+ await mkdir(dir, { recursive: true })
33
+ await writeFile(join(dir, `${id}.json`), `${JSON.stringify(record, null, 2)}\n`, 'utf8')
34
+ return record
35
+ }
36
+
37
+ export async function readPlan(config, id) {
38
+ const path = planPath(config, id)
39
+ if (!path) return undefined
40
+ try {
41
+ return JSON.parse(await readFile(path, 'utf8'))
42
+ } catch {
43
+ return undefined
44
+ }
45
+ }
46
+
47
+ export async function deletePlan(config, id) {
48
+ const path = planPath(config, id)
49
+ if (!path) return false
50
+ try {
51
+ await rm(path)
52
+ return true
53
+ } catch {
54
+ return false
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Move a plan through its lifecycle: pending → running → done | failed.
60
+ *
61
+ * The file is the only guard against executing a plan twice. Marking it
62
+ * "running" before the first write means a crash mid-plan leaves a record that
63
+ * refuses a silent second run, instead of replaying the operations that already
64
+ * landed.
65
+ */
66
+ export async function setPlanStatus(config, id, status, extra = {}) {
67
+ const plan = await readPlan(config, id)
68
+ if (!plan) return undefined
69
+ const path = planPath(config, id)
70
+ if (!path) return undefined
71
+ const next = { ...plan, ...extra, status, updatedAt: new Date().toISOString() }
72
+ await writeFile(path, `${JSON.stringify(next, null, 2)}\n`, 'utf8')
73
+ return next
74
+ }
75
+
76
+ /** Every still-readable plan, newest first. */
77
+ export async function listPlans(config) {
78
+ const dir = plansDir(config)
79
+ let names = []
80
+ try {
81
+ names = await readdir(dir)
82
+ } catch {
83
+ return []
84
+ }
85
+ const plans = []
86
+ for (const name of names.filter((name) => name.endsWith('.json'))) {
87
+ const plan = await readPlan(config, name.replace(/\.json$/, ''))
88
+ if (plan) plans.push(plan)
89
+ }
90
+ return plans.sort((a, b) => String(b.createdAt).localeCompare(String(a.createdAt)))
91
+ }
92
+
93
+ /**
94
+ * Append one executed change to the ledger. This file is the only record of
95
+ * "what did the agent change and when", so it is written before the HTTP calls
96
+ * settle and never rewritten.
97
+ */
98
+ export async function recordChange(config, record) {
99
+ const dir = changesDir(config)
100
+ await mkdir(dir, { recursive: true })
101
+ const stamp = new Date().toISOString().replace(/[:.]/g, '-')
102
+ const name = `${stamp}-${record.planId ?? 'plan'}.json`
103
+ const path = join(dir, name)
104
+ await writeFile(path, `${JSON.stringify({ ...record, recordedAt: new Date().toISOString() }, null, 2)}\n`, 'utf8')
105
+ return path
106
+ }
107
+
108
+ /** Recent ledger entries, newest first. */
109
+ export async function listChanges(config, limit = 20) {
110
+ const dir = changesDir(config)
111
+ let names = []
112
+ try {
113
+ names = await readdir(dir)
114
+ } catch {
115
+ return []
116
+ }
117
+ const files = names.filter((name) => name.endsWith('.json')).sort().reverse().slice(0, limit)
118
+ const entries = []
119
+ for (const name of files) {
120
+ try {
121
+ entries.push(JSON.parse(await readFile(join(dir, name), 'utf8')))
122
+ } catch {
123
+ // A half-written ledger entry is skipped rather than failing the page.
124
+ }
125
+ }
126
+ return entries
127
+ }
128
+
129
+ /**
130
+ * Record how one publish attempt ended. One file per plan: a re-publish
131
+ * overwrites the previous outcome, which is what "current state" means here.
132
+ */
133
+ export async function writePublishReport(config, planId, record) {
134
+ const dir = changesDir(config)
135
+ await mkdir(dir, { recursive: true })
136
+ const path = join(dir, `publish-${planId}.json`)
137
+ await writeFile(path, `${JSON.stringify(record, null, 2)}\n`, 'utf8')
138
+ return path
139
+ }
140
+
141
+ /**
142
+ * How the publish for each executed plan ended.
143
+ *
144
+ * The publish runs detached, so the ledger can only say "running"; the sidecar
145
+ * written when the request settles is the only place that knows the outcome.
146
+ * Keyed by planId so the plans panel can show it next to the change.
147
+ */
148
+ export async function listPublishReports(config) {
149
+ const dir = changesDir(config)
150
+ let names = []
151
+ try {
152
+ names = await readdir(dir)
153
+ } catch {
154
+ return {}
155
+ }
156
+ const reports = {}
157
+ for (const name of names.filter((name) => name.startsWith('publish-') && name.endsWith('.json'))) {
158
+ try {
159
+ const record = JSON.parse(await readFile(join(dir, name), 'utf8'))
160
+ if (record?.planId) reports[record.planId] = record
161
+ } catch {
162
+ // Skip an unreadable sidecar; the UI falls back to the ledger state.
163
+ }
164
+ }
165
+ return reports
166
+ }
167
+
package/locale/en.json CHANGED
@@ -1,68 +1,68 @@
1
- {
2
- "meta": {
3
- "title": "D365 Toolkit",
4
- "description": "Developer and deployment toolkit for Dynamics 365 CE: metadata, layers, migration risk, code checks, contract drift and environment health."
5
- },
6
- "tools": {
7
- "d365_envs": {
8
- "title": "Environments",
9
- "description": "List configured environments, credential status and connectivity"
10
- },
11
- "d365_metadata": {
12
- "title": "Metadata",
13
- "description": "Query entities, attributes, forms, views, plugins and solutions by resource"
14
- },
15
- "d365_layers": {
16
- "title": "Solution layers",
17
- "description": "See which solutions cover a component and which layer is active"
18
- },
19
- "d365_sync": {
20
- "title": "Sync snapshot",
21
- "description": "Pull environment metadata into a local snapshot and record completeness"
22
- },
23
- "d365_diff": {
24
- "title": "Diff snapshots",
25
- "description": "Compare two snapshots: additions, deletions and field-level edits"
26
- },
27
- "d365_configure": {
28
- "title": "Configure environments",
29
- "description": "List, save, remove or test environment definitions"
30
- },
31
- "d365_write": {
32
- "title": "Metadata changes",
33
- "description": "Plan option values, attributes, table names and view columns, then apply after approval"
34
- },
35
- "d365_migrate": {
36
- "title": "Migration risk",
37
- "description": "Assess importing a solution elsewhere: shadowing, missing components, lost option values"
38
- },
39
- "d365_code_check": {
40
- "title": "Code change check",
41
- "description": "Read a GitLab MR and check whether script and plugin changes will run in the target environment"
42
- },
43
- "d365_refs": {
44
- "title": "References",
45
- "description": "Which forms, views and flows use a field, which forms load a script, which steps a plugin has"
46
- },
47
- "d365_data": {
48
- "title": "Query data",
49
- "description": "Count, group or sample business records (requires environment permission)"
50
- },
51
- "d365_data_write": {
52
- "title": "Write data",
53
- "description": "Create or update one business record after approval (requires environment permission)"
54
- },
55
- "d365_contract": {
56
- "title": "Contract drift",
57
- "description": "Check plugin registrations, form scripts and sitemaps across environments, with waivers"
58
- },
59
- "d365_health": {
60
- "title": "Environment health",
61
- "description": "Suspended and failed jobs, running imports and publishes, recently installed solutions"
62
- },
63
- "d365_reports": {
64
- "title": "Local data",
65
- "description": "Inspect local artifact usage, clean up by retention policy or compact snapshots"
66
- }
67
- }
68
- }
1
+ {
2
+ "meta": {
3
+ "title": "D365 Toolkit",
4
+ "description": "Developer and deployment toolkit for Dynamics 365 CE: metadata, layers, migration risk, code checks, contract drift and environment health."
5
+ },
6
+ "tools": {
7
+ "d365_envs": {
8
+ "title": "Environments",
9
+ "description": "List configured environments, credential status and connectivity"
10
+ },
11
+ "d365_metadata": {
12
+ "title": "Metadata",
13
+ "description": "Query entities, attributes, forms, views, plugins and solutions by resource"
14
+ },
15
+ "d365_layers": {
16
+ "title": "Solution layers",
17
+ "description": "See which solutions cover a component and which layer is active"
18
+ },
19
+ "d365_sync": {
20
+ "title": "Sync snapshot",
21
+ "description": "Pull environment metadata into a local snapshot and record completeness"
22
+ },
23
+ "d365_diff": {
24
+ "title": "Diff snapshots",
25
+ "description": "Compare two snapshots: additions, deletions and field-level edits"
26
+ },
27
+ "d365_configure": {
28
+ "title": "Configure environments",
29
+ "description": "List, save, remove or test environment definitions"
30
+ },
31
+ "d365_write": {
32
+ "title": "Metadata changes",
33
+ "description": "Plan option values, attributes, table names and view columns, then apply after approval"
34
+ },
35
+ "d365_migrate": {
36
+ "title": "Migration risk",
37
+ "description": "Assess importing a solution elsewhere: shadowing, missing components, lost option values"
38
+ },
39
+ "d365_code_check": {
40
+ "title": "Code change check",
41
+ "description": "Read a GitLab MR and check whether script and plugin changes will run in the target environment"
42
+ },
43
+ "d365_refs": {
44
+ "title": "References",
45
+ "description": "Which forms, views and flows use a field, which forms load a script, which steps a plugin has"
46
+ },
47
+ "d365_data": {
48
+ "title": "Query data",
49
+ "description": "Count, group or sample business records (requires environment permission)"
50
+ },
51
+ "d365_data_write": {
52
+ "title": "Write data",
53
+ "description": "Create or update one business record after approval (requires environment permission)"
54
+ },
55
+ "d365_contract": {
56
+ "title": "Contract drift",
57
+ "description": "Check plugin registrations, form scripts and sitemaps across environments, with waivers"
58
+ },
59
+ "d365_health": {
60
+ "title": "Environment health",
61
+ "description": "Suspended and failed jobs, running imports and publishes, recently installed solutions"
62
+ },
63
+ "d365_reports": {
64
+ "title": "Local data",
65
+ "description": "Inspect local artifact usage, clean up by retention policy or compact snapshots"
66
+ }
67
+ }
68
+ }
package/locale/zh.json CHANGED
@@ -1,68 +1,68 @@
1
- {
2
- "meta": {
3
- "title": "D365 工具箱",
4
- "description": "Dynamics 365 CE 的开发与部署助手:元数据、解决方案层、迁移风险、代码改动检查、契约漂移、环境健康。"
5
- },
6
- "tools": {
7
- "d365_envs": {
8
- "title": "环境清单",
9
- "description": "列出已配置环境、凭据状态与连通性"
10
- },
11
- "d365_metadata": {
12
- "title": "元数据查询",
13
- "description": "按类别查询实体、字段、表单、视图、插件、解决方案等"
14
- },
15
- "d365_layers": {
16
- "title": "解决方案层",
17
- "description": "查看组件被哪些解决方案覆盖、当前生效的是哪一层"
18
- },
19
- "d365_sync": {
20
- "title": "同步快照",
21
- "description": "把环境元数据拉成本地快照并记录采集完整度"
22
- },
23
- "d365_diff": {
24
- "title": "快照对比",
25
- "description": "比较两份快照的新增、删除与字段级修改"
26
- },
27
- "d365_configure": {
28
- "title": "环境配置",
29
- "description": "读写环境清单:列出、保存、删除或测试连接"
30
- },
31
- "d365_write": {
32
- "title": "元数据变更",
33
- "description": "准备选项值、字段、表名与视图列的修改计划,确认后执行"
34
- },
35
- "d365_migrate": {
36
- "title": "迁移评估",
37
- "description": "评估解决方案导入其它环境的风险:遮蔽、缺失、选项值丢失"
38
- },
39
- "d365_code_check": {
40
- "title": "代码改动检查",
41
- "description": "读 GitLab MR,检查脚本与插件改动发到目标环境能否运行"
42
- },
43
- "d365_refs": {
44
- "title": "引用反查",
45
- "description": "字段被哪些表单/视图/流程引用,Web 资源被谁加载,程序集有哪些步骤"
46
- },
47
- "d365_data": {
48
- "title": "业务数据查询",
49
- "description": "统计、分组或抽样读取业务记录(需环境授权)"
50
- },
51
- "d365_data_write": {
52
- "title": "业务数据写入",
53
- "description": "新建或修改一条业务记录,确认后执行(需环境授权)"
54
- },
55
- "d365_contract": {
56
- "title": "契约漂移",
57
- "description": "核对插件注册、表单脚本与站点地图在上游下游是否一致,支持豁免"
58
- },
59
- "d365_health": {
60
- "title": "环境健康",
61
- "description": "挂起与失败的后台作业、正在运行的导入发布、最近安装的解决方案"
62
- },
63
- "d365_reports": {
64
- "title": "本机数据",
65
- "description": "查看本机产物占用,按保留策略清理或压缩快照"
66
- }
67
- }
68
- }
1
+ {
2
+ "meta": {
3
+ "title": "D365 工具箱",
4
+ "description": "Dynamics 365 CE 的开发与部署助手:元数据、解决方案层、迁移风险、代码改动检查、契约漂移、环境健康。"
5
+ },
6
+ "tools": {
7
+ "d365_envs": {
8
+ "title": "环境清单",
9
+ "description": "列出已配置环境、凭据状态与连通性"
10
+ },
11
+ "d365_metadata": {
12
+ "title": "元数据查询",
13
+ "description": "按类别查询实体、字段、表单、视图、插件、解决方案等"
14
+ },
15
+ "d365_layers": {
16
+ "title": "解决方案层",
17
+ "description": "查看组件被哪些解决方案覆盖、当前生效的是哪一层"
18
+ },
19
+ "d365_sync": {
20
+ "title": "同步快照",
21
+ "description": "把环境元数据拉成本地快照并记录采集完整度"
22
+ },
23
+ "d365_diff": {
24
+ "title": "快照对比",
25
+ "description": "比较两份快照的新增、删除与字段级修改"
26
+ },
27
+ "d365_configure": {
28
+ "title": "环境配置",
29
+ "description": "读写环境清单:列出、保存、删除或测试连接"
30
+ },
31
+ "d365_write": {
32
+ "title": "元数据变更",
33
+ "description": "准备选项值、字段、表名与视图列的修改计划,确认后执行"
34
+ },
35
+ "d365_migrate": {
36
+ "title": "迁移评估",
37
+ "description": "评估解决方案导入其它环境的风险:遮蔽、缺失、选项值丢失"
38
+ },
39
+ "d365_code_check": {
40
+ "title": "代码改动检查",
41
+ "description": "读 GitLab MR,检查脚本与插件改动发到目标环境能否运行"
42
+ },
43
+ "d365_refs": {
44
+ "title": "引用反查",
45
+ "description": "字段被哪些表单/视图/流程引用,Web 资源被谁加载,程序集有哪些步骤"
46
+ },
47
+ "d365_data": {
48
+ "title": "业务数据查询",
49
+ "description": "统计、分组或抽样读取业务记录(需环境授权)"
50
+ },
51
+ "d365_data_write": {
52
+ "title": "业务数据写入",
53
+ "description": "新建或修改一条业务记录,确认后执行(需环境授权)"
54
+ },
55
+ "d365_contract": {
56
+ "title": "契约漂移",
57
+ "description": "核对插件注册、表单脚本与站点地图在上游下游是否一致,支持豁免"
58
+ },
59
+ "d365_health": {
60
+ "title": "环境健康",
61
+ "description": "挂起与失败的后台作业、正在运行的导入发布、最近安装的解决方案"
62
+ },
63
+ "d365_reports": {
64
+ "title": "本机数据",
65
+ "description": "查看本机产物占用,按保留策略清理或压缩快照"
66
+ }
67
+ }
68
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-d365-kit",
3
- "version": "0.34.1",
3
+ "version": "0.34.4",
4
4
  "type": "module",
5
5
  "description": "Dynamics 365 CE developer and deployment toolkit for DSH: metadata, layers, snapshots, migration risk, code checks, contract drift, environment health, plug-in traces, message invocation and business-record sync.",
6
6
  "license": "MIT",
@@ -58,4 +58,4 @@
58
58
  "inject": []
59
59
  }
60
60
  }
61
- }
61
+ }