dsh-d365-kit 0.34.1 → 0.34.3
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.
- package/CHANGELOG.md +318 -308
- package/CHANGELOG.zh-CN.md +317 -307
- package/INSTALL.md +94 -94
- package/INSTALL.zh-CN.md +93 -93
- package/LICENSE +21 -21
- package/README.md +336 -327
- package/README.zh-CN.md +336 -327
- package/client.js +1818 -1818
- package/cordis.patch.yml +44 -44
- package/docs/en/architecture.md +172 -172
- package/docs/en/checks.md +184 -184
- package/docs/en/installation.md +151 -151
- package/docs/en/permissions.md +161 -161
- package/docs/en/scenarios.md +202 -202
- package/docs/en/tools.md +665 -665
- package/docs/en/troubleshooting.md +131 -131
- package/docs/zh/architecture.md +172 -172
- package/docs/zh/checks.md +184 -184
- package/docs/zh/installation.md +151 -151
- package/docs/zh/permissions.md +161 -161
- package/docs/zh/scenarios.md +202 -202
- package/docs/zh/tools.md +665 -665
- package/docs/zh/troubleshooting.md +131 -131
- package/examples/prompts.en.md +206 -206
- package/examples/prompts.zh-CN.md +206 -206
- package/examples/waivers.example.json +20 -20
- package/icon.svg +6 -6
- package/index.js +139 -139
- package/lib/auth.js +181 -181
- package/lib/client.js +496 -496
- package/lib/code-check.js +549 -549
- package/lib/config.js +323 -323
- package/lib/contract-history.js +49 -49
- package/lib/contract.js +583 -583
- package/lib/csharp-check.js +493 -493
- package/lib/data-migrate.js +1318 -1318
- package/lib/data-policy.js +78 -78
- package/lib/error-codes.js +80 -80
- package/lib/gitlab.js +161 -161
- package/lib/health.js +205 -205
- package/lib/migrate.js +732 -732
- package/lib/preflight.js +116 -116
- package/lib/refs.js +191 -191
- package/lib/resources.js +320 -320
- package/lib/retention-defaults.js +17 -17
- package/lib/retention.js +384 -384
- package/lib/runtime.js +232 -232
- package/lib/settings-http.js +512 -512
- package/lib/settings-store.js +371 -371
- package/lib/snapshot.js +149 -149
- package/lib/tool-code-check.js +133 -133
- package/lib/tool-configure.js +169 -169
- package/lib/tool-contract.js +376 -376
- package/lib/tool-data-sync.js +559 -559
- package/lib/tool-data-write.js +203 -203
- package/lib/tool-data.js +282 -282
- package/lib/tool-diff.js +484 -484
- package/lib/tool-environments.js +106 -106
- package/lib/tool-flows.js +540 -540
- package/lib/tool-health.js +127 -127
- package/lib/tool-layers.js +497 -497
- package/lib/tool-metadata.js +417 -417
- package/lib/tool-migrate.js +102 -102
- package/lib/tool-refs.js +206 -206
- package/lib/tool-reports.js +299 -299
- package/lib/tool-sync.js +430 -430
- package/lib/tool-write.js +563 -563
- package/lib/waivers.js +83 -83
- package/lib/write-actions.js +1374 -1374
- package/lib/write-policy.js +199 -199
- package/lib/write-store.js +167 -167
- package/locale/en.json +68 -68
- package/locale/zh.json +68 -68
- package/package.json +2 -2
- package/skills/d365-troubleshooting/SKILL.md +115 -115
package/lib/tool-configure.js
CHANGED
|
@@ -1,169 +1,169 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `d365_configure` — the agent's face of the settings page.
|
|
3
|
-
*
|
|
4
|
-
* Same operations, same storage code: an agent that learns a URL and a
|
|
5
|
-
* credential in chat writes exactly what the form would have written.
|
|
6
|
-
*/
|
|
7
|
-
import { checkEnvironment, readSettings, saveSettings } from './settings-store.js'
|
|
8
|
-
import { D365Error } from './errors.js'
|
|
9
|
-
|
|
10
|
-
export const definition = {
|
|
11
|
-
name: 'd365_configure',
|
|
12
|
-
description:
|
|
13
|
-
'查看或修改 D365 环境配置:环境 URL、租户、应用用户 ClientId、客户端密钥,以及默认环境。'
|
|
14
|
-
+ '与设置页里的"D365 环境"是同一份数据。注意:写入的密钥明文存到本机 d365.secrets.json,不进 d365.config.json。',
|
|
15
|
-
parameters: {
|
|
16
|
-
type: 'object',
|
|
17
|
-
additionalProperties: false,
|
|
18
|
-
properties: {
|
|
19
|
-
action: {
|
|
20
|
-
type: 'string',
|
|
21
|
-
enum: ['list', 'save', 'remove', 'check'],
|
|
22
|
-
description: 'list 查看;save 新增或修改一个环境;remove 删除一个环境;check 真实连一次验证凭据。默认 list。',
|
|
23
|
-
},
|
|
24
|
-
environment: { type: 'string', description: '环境 key,例如 dev。save/remove/check 必填。' },
|
|
25
|
-
url: { type: 'string', description: 'save:环境 URL,例如 https://contoso-dev.crm5.dynamics.com' },
|
|
26
|
-
label: { type: 'string', description: 'save:显示名,例如 开发。' },
|
|
27
|
-
cloud: {
|
|
28
|
-
type: 'string',
|
|
29
|
-
enum: ['public', 'usgovernment', 'dod', 'china'],
|
|
30
|
-
description: 'save:云,默认 public。',
|
|
31
|
-
},
|
|
32
|
-
tenantId: { type: 'string', description: 'save:Entra 租户 ID。' },
|
|
33
|
-
clientId: { type: 'string', description: 'save:应用用户 ClientId。' },
|
|
34
|
-
clientSecret: { type: 'string', description: 'save:客户端密钥(写入 d365.secrets.json,不进 config)。' },
|
|
35
|
-
clearSecret: { type: 'boolean', description: 'save:清掉已保存的密钥。' },
|
|
36
|
-
defaultEnvironment: { type: 'string', description: 'save:同时把默认环境设为它。' },
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
output: {
|
|
40
|
-
schema: {
|
|
41
|
-
type: 'object',
|
|
42
|
-
additionalProperties: false,
|
|
43
|
-
required: ['text'],
|
|
44
|
-
properties: { text: { type: 'string' } },
|
|
45
|
-
},
|
|
46
|
-
render(_args, value) {
|
|
47
|
-
return [{ type: 'text', text: value?.text ?? '' }]
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/** Turn a settings view back into a save payload row. */
|
|
53
|
-
function rowOf(entry) {
|
|
54
|
-
return {
|
|
55
|
-
url: entry.url,
|
|
56
|
-
label: entry.label,
|
|
57
|
-
cloud: entry.cloud,
|
|
58
|
-
tenantId: entry.tenantId,
|
|
59
|
-
tenantIdEnv: entry.tenantIdEnv,
|
|
60
|
-
clientId: entry.clientId,
|
|
61
|
-
clientIdEnv: entry.clientIdEnv,
|
|
62
|
-
note: entry.note,
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function renderSettings(settings) {
|
|
67
|
-
const lines = []
|
|
68
|
-
const envs = settings.environments ?? []
|
|
69
|
-
lines.push(`已配置 ${envs.length} 个环境,默认:${settings.defaultEnvironment ?? '(无)'}`)
|
|
70
|
-
lines.push(`配置文件:${settings.configFile ?? '(未配置 configFile)'}`)
|
|
71
|
-
if (envs.length) {
|
|
72
|
-
lines.push('')
|
|
73
|
-
lines.push('| 环境 | URL | 云 | 凭据 |')
|
|
74
|
-
lines.push('| --- | --- | --- | --- |')
|
|
75
|
-
for (const env of envs) {
|
|
76
|
-
const state = env.complete
|
|
77
|
-
? '齐全'
|
|
78
|
-
: `缺 ${env.missing.map((item) => item.kind).join('/')}`
|
|
79
|
-
const secret = env.hasSecret ? `密钥(${env.secretSource})` : '无密钥'
|
|
80
|
-
lines.push(`| ${env.key} | ${env.url} | ${env.cloud} | ${state === '齐全' ? `齐全,${secret}` : `${state},${secret}`} |`)
|
|
81
|
-
}
|
|
82
|
-
} else {
|
|
83
|
-
lines.push('', '还没有环境。用 action=save 添加,或在设置页的"D365 环境"里填。')
|
|
84
|
-
}
|
|
85
|
-
if (settings.issues?.length) {
|
|
86
|
-
lines.push('', '配置告警:')
|
|
87
|
-
for (const issue of settings.issues) lines.push(`- ${issue}`)
|
|
88
|
-
}
|
|
89
|
-
if (settings.secretsFile) lines.push('', `密钥文件:${settings.secretsFile}`)
|
|
90
|
-
return lines.join('\n')
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export function register(ctx, state) {
|
|
94
|
-
return ctx.tools.register({
|
|
95
|
-
...definition,
|
|
96
|
-
async execute(args = {}) {
|
|
97
|
-
const action = args.action ?? 'list'
|
|
98
|
-
const raw = state.rawConfig
|
|
99
|
-
|
|
100
|
-
if (action === 'list') {
|
|
101
|
-
return { text: renderSettings(await readSettings(raw)) }
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const key = String(args.environment ?? '').trim()
|
|
105
|
-
if (!key) throw new D365Error(`${action} 需要 environment`, { hint: '例如 environment: "dev"' })
|
|
106
|
-
|
|
107
|
-
if (action === 'check') {
|
|
108
|
-
const result = await checkEnvironment(raw, key)
|
|
109
|
-
if (result.ok) {
|
|
110
|
-
const org = result.organization ?? {}
|
|
111
|
-
return {
|
|
112
|
-
text: `环境 ${key} 连接正常:${org.name ?? '(未返回名称)'},版本 ${org.version ?? '?'},区域 ${org.organizationstructure ?? '?'}\nURL:${org.url ?? ''}`,
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
const missing = result.missing?.length
|
|
116
|
-
? `\n缺少:${result.missing.map((item) => `${item.kind}(${item.missing.join(' / ')})`).join(';')}`
|
|
117
|
-
: ''
|
|
118
|
-
return { text: `环境 ${key} 连接失败:${result.error}${missing}${result.hint ? `\n建议:${result.hint}` : ''}` }
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const settings = await readSettings(raw)
|
|
122
|
-
const rows = {}
|
|
123
|
-
for (const env of settings.environments) rows[env.key] = rowOf(env)
|
|
124
|
-
|
|
125
|
-
if (action === 'remove') {
|
|
126
|
-
if (!rows[key]) {
|
|
127
|
-
throw new D365Error(`没有名为 ${key} 的环境`, {
|
|
128
|
-
hint: `现有:${Object.keys(rows).join(', ') || '(无)'}`,
|
|
129
|
-
})
|
|
130
|
-
}
|
|
131
|
-
delete rows[key]
|
|
132
|
-
const result = await saveSettings(raw, {
|
|
133
|
-
defaultEnvironment: settings.defaultEnvironment,
|
|
134
|
-
environments: rows,
|
|
135
|
-
})
|
|
136
|
-
return { text: `已删除环境 ${key}。\n\n${renderSettings(result.settings)}` }
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (action === 'save') {
|
|
140
|
-
const previous = rows[key] ?? {}
|
|
141
|
-
const merged = {
|
|
142
|
-
...previous,
|
|
143
|
-
url: args.url ?? previous.url,
|
|
144
|
-
label: args.label ?? previous.label,
|
|
145
|
-
cloud: args.cloud ?? previous.cloud,
|
|
146
|
-
tenantId: args.tenantId ?? previous.tenantId,
|
|
147
|
-
clientId: args.clientId ?? previous.clientId,
|
|
148
|
-
}
|
|
149
|
-
if (args.clientSecret) merged.clientSecret = args.clientSecret
|
|
150
|
-
if (args.clearSecret) merged.clearSecret = true
|
|
151
|
-
rows[key] = merged
|
|
152
|
-
|
|
153
|
-
const result = await saveSettings(raw, {
|
|
154
|
-
defaultEnvironment: args.defaultEnvironment ?? settings.defaultEnvironment ?? key,
|
|
155
|
-
environments: rows,
|
|
156
|
-
})
|
|
157
|
-
const touched = result.secretsTouched.includes(key)
|
|
158
|
-
? '\n密钥已写入本机 d365.secrets.json(明文,勿提交到 Git)。'
|
|
159
|
-
: ''
|
|
160
|
-
return { text: `已保存环境 ${key}。${touched}\n\n${renderSettings(result.settings)}` }
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
throw new D365Error(`未知 action:${action}`, { hint: '可用:list / save / remove / check' })
|
|
164
|
-
},
|
|
165
|
-
presentCall(args = {}) {
|
|
166
|
-
return { card: 'generic', title: `D365 配置:${args.action ?? 'list'}`, kind: 'other', rawInput: args }
|
|
167
|
-
},
|
|
168
|
-
})
|
|
169
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* `d365_configure` — the agent's face of the settings page.
|
|
3
|
+
*
|
|
4
|
+
* Same operations, same storage code: an agent that learns a URL and a
|
|
5
|
+
* credential in chat writes exactly what the form would have written.
|
|
6
|
+
*/
|
|
7
|
+
import { checkEnvironment, readSettings, saveSettings } from './settings-store.js'
|
|
8
|
+
import { D365Error } from './errors.js'
|
|
9
|
+
|
|
10
|
+
export const definition = {
|
|
11
|
+
name: 'd365_configure',
|
|
12
|
+
description:
|
|
13
|
+
'查看或修改 D365 环境配置:环境 URL、租户、应用用户 ClientId、客户端密钥,以及默认环境。'
|
|
14
|
+
+ '与设置页里的"D365 环境"是同一份数据。注意:写入的密钥明文存到本机 d365.secrets.json,不进 d365.config.json。',
|
|
15
|
+
parameters: {
|
|
16
|
+
type: 'object',
|
|
17
|
+
additionalProperties: false,
|
|
18
|
+
properties: {
|
|
19
|
+
action: {
|
|
20
|
+
type: 'string',
|
|
21
|
+
enum: ['list', 'save', 'remove', 'check'],
|
|
22
|
+
description: 'list 查看;save 新增或修改一个环境;remove 删除一个环境;check 真实连一次验证凭据。默认 list。',
|
|
23
|
+
},
|
|
24
|
+
environment: { type: 'string', description: '环境 key,例如 dev。save/remove/check 必填。' },
|
|
25
|
+
url: { type: 'string', description: 'save:环境 URL,例如 https://contoso-dev.crm5.dynamics.com' },
|
|
26
|
+
label: { type: 'string', description: 'save:显示名,例如 开发。' },
|
|
27
|
+
cloud: {
|
|
28
|
+
type: 'string',
|
|
29
|
+
enum: ['public', 'usgovernment', 'dod', 'china'],
|
|
30
|
+
description: 'save:云,默认 public。',
|
|
31
|
+
},
|
|
32
|
+
tenantId: { type: 'string', description: 'save:Entra 租户 ID。' },
|
|
33
|
+
clientId: { type: 'string', description: 'save:应用用户 ClientId。' },
|
|
34
|
+
clientSecret: { type: 'string', description: 'save:客户端密钥(写入 d365.secrets.json,不进 config)。' },
|
|
35
|
+
clearSecret: { type: 'boolean', description: 'save:清掉已保存的密钥。' },
|
|
36
|
+
defaultEnvironment: { type: 'string', description: 'save:同时把默认环境设为它。' },
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
output: {
|
|
40
|
+
schema: {
|
|
41
|
+
type: 'object',
|
|
42
|
+
additionalProperties: false,
|
|
43
|
+
required: ['text'],
|
|
44
|
+
properties: { text: { type: 'string' } },
|
|
45
|
+
},
|
|
46
|
+
render(_args, value) {
|
|
47
|
+
return [{ type: 'text', text: value?.text ?? '' }]
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Turn a settings view back into a save payload row. */
|
|
53
|
+
function rowOf(entry) {
|
|
54
|
+
return {
|
|
55
|
+
url: entry.url,
|
|
56
|
+
label: entry.label,
|
|
57
|
+
cloud: entry.cloud,
|
|
58
|
+
tenantId: entry.tenantId,
|
|
59
|
+
tenantIdEnv: entry.tenantIdEnv,
|
|
60
|
+
clientId: entry.clientId,
|
|
61
|
+
clientIdEnv: entry.clientIdEnv,
|
|
62
|
+
note: entry.note,
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function renderSettings(settings) {
|
|
67
|
+
const lines = []
|
|
68
|
+
const envs = settings.environments ?? []
|
|
69
|
+
lines.push(`已配置 ${envs.length} 个环境,默认:${settings.defaultEnvironment ?? '(无)'}`)
|
|
70
|
+
lines.push(`配置文件:${settings.configFile ?? '(未配置 configFile)'}`)
|
|
71
|
+
if (envs.length) {
|
|
72
|
+
lines.push('')
|
|
73
|
+
lines.push('| 环境 | URL | 云 | 凭据 |')
|
|
74
|
+
lines.push('| --- | --- | --- | --- |')
|
|
75
|
+
for (const env of envs) {
|
|
76
|
+
const state = env.complete
|
|
77
|
+
? '齐全'
|
|
78
|
+
: `缺 ${env.missing.map((item) => item.kind).join('/')}`
|
|
79
|
+
const secret = env.hasSecret ? `密钥(${env.secretSource})` : '无密钥'
|
|
80
|
+
lines.push(`| ${env.key} | ${env.url} | ${env.cloud} | ${state === '齐全' ? `齐全,${secret}` : `${state},${secret}`} |`)
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
lines.push('', '还没有环境。用 action=save 添加,或在设置页的"D365 环境"里填。')
|
|
84
|
+
}
|
|
85
|
+
if (settings.issues?.length) {
|
|
86
|
+
lines.push('', '配置告警:')
|
|
87
|
+
for (const issue of settings.issues) lines.push(`- ${issue}`)
|
|
88
|
+
}
|
|
89
|
+
if (settings.secretsFile) lines.push('', `密钥文件:${settings.secretsFile}`)
|
|
90
|
+
return lines.join('\n')
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function register(ctx, state) {
|
|
94
|
+
return ctx.tools.register({
|
|
95
|
+
...definition,
|
|
96
|
+
async execute(args = {}) {
|
|
97
|
+
const action = args.action ?? 'list'
|
|
98
|
+
const raw = state.rawConfig
|
|
99
|
+
|
|
100
|
+
if (action === 'list') {
|
|
101
|
+
return { text: renderSettings(await readSettings(raw)) }
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const key = String(args.environment ?? '').trim()
|
|
105
|
+
if (!key) throw new D365Error(`${action} 需要 environment`, { hint: '例如 environment: "dev"' })
|
|
106
|
+
|
|
107
|
+
if (action === 'check') {
|
|
108
|
+
const result = await checkEnvironment(raw, key)
|
|
109
|
+
if (result.ok) {
|
|
110
|
+
const org = result.organization ?? {}
|
|
111
|
+
return {
|
|
112
|
+
text: `环境 ${key} 连接正常:${org.name ?? '(未返回名称)'},版本 ${org.version ?? '?'},区域 ${org.organizationstructure ?? '?'}\nURL:${org.url ?? ''}`,
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const missing = result.missing?.length
|
|
116
|
+
? `\n缺少:${result.missing.map((item) => `${item.kind}(${item.missing.join(' / ')})`).join(';')}`
|
|
117
|
+
: ''
|
|
118
|
+
return { text: `环境 ${key} 连接失败:${result.error}${missing}${result.hint ? `\n建议:${result.hint}` : ''}` }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const settings = await readSettings(raw)
|
|
122
|
+
const rows = {}
|
|
123
|
+
for (const env of settings.environments) rows[env.key] = rowOf(env)
|
|
124
|
+
|
|
125
|
+
if (action === 'remove') {
|
|
126
|
+
if (!rows[key]) {
|
|
127
|
+
throw new D365Error(`没有名为 ${key} 的环境`, {
|
|
128
|
+
hint: `现有:${Object.keys(rows).join(', ') || '(无)'}`,
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
delete rows[key]
|
|
132
|
+
const result = await saveSettings(raw, {
|
|
133
|
+
defaultEnvironment: settings.defaultEnvironment,
|
|
134
|
+
environments: rows,
|
|
135
|
+
})
|
|
136
|
+
return { text: `已删除环境 ${key}。\n\n${renderSettings(result.settings)}` }
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (action === 'save') {
|
|
140
|
+
const previous = rows[key] ?? {}
|
|
141
|
+
const merged = {
|
|
142
|
+
...previous,
|
|
143
|
+
url: args.url ?? previous.url,
|
|
144
|
+
label: args.label ?? previous.label,
|
|
145
|
+
cloud: args.cloud ?? previous.cloud,
|
|
146
|
+
tenantId: args.tenantId ?? previous.tenantId,
|
|
147
|
+
clientId: args.clientId ?? previous.clientId,
|
|
148
|
+
}
|
|
149
|
+
if (args.clientSecret) merged.clientSecret = args.clientSecret
|
|
150
|
+
if (args.clearSecret) merged.clearSecret = true
|
|
151
|
+
rows[key] = merged
|
|
152
|
+
|
|
153
|
+
const result = await saveSettings(raw, {
|
|
154
|
+
defaultEnvironment: args.defaultEnvironment ?? settings.defaultEnvironment ?? key,
|
|
155
|
+
environments: rows,
|
|
156
|
+
})
|
|
157
|
+
const touched = result.secretsTouched.includes(key)
|
|
158
|
+
? '\n密钥已写入本机 d365.secrets.json(明文,勿提交到 Git)。'
|
|
159
|
+
: ''
|
|
160
|
+
return { text: `已保存环境 ${key}。${touched}\n\n${renderSettings(result.settings)}` }
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
throw new D365Error(`未知 action:${action}`, { hint: '可用:list / save / remove / check' })
|
|
164
|
+
},
|
|
165
|
+
presentCall(args = {}) {
|
|
166
|
+
return { card: 'generic', title: `D365 配置:${args.action ?? 'list'}`, kind: 'other', rawInput: args }
|
|
167
|
+
},
|
|
168
|
+
})
|
|
169
|
+
}
|