@dsh-enhanced/lark-channel 0.1.47 → 0.1.49
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/README.md +19 -8
- package/docs/rsi-setup.md +123 -11
- package/docs/setup.md +27 -14
- package/docs/supervised-growth.md +2 -0
- package/lib/adapter.d.ts +6 -0
- package/lib/adapter.d.ts.map +1 -1
- package/lib/adapter.js +79 -8
- package/lib/adapter.js.map +1 -1
- package/lib/business-cli-install.d.ts +9 -0
- package/lib/business-cli-install.d.ts.map +1 -0
- package/lib/business-cli-install.js +367 -0
- package/lib/business-cli-install.js.map +1 -0
- package/lib/business-environment.d.ts +2 -0
- package/lib/business-environment.d.ts.map +1 -0
- package/lib/business-environment.js +16 -0
- package/lib/business-environment.js.map +1 -0
- package/lib/business-skill.d.ts +32 -0
- package/lib/business-skill.d.ts.map +1 -0
- package/lib/business-skill.js +202 -0
- package/lib/business-skill.js.map +1 -0
- package/lib/rsi-authority-config.d.ts +29 -0
- package/lib/rsi-authority-config.d.ts.map +1 -0
- package/lib/rsi-authority-config.js +233 -0
- package/lib/rsi-authority-config.js.map +1 -0
- package/lib/rsi-authority-resources.d.ts +36 -0
- package/lib/rsi-authority-resources.d.ts.map +1 -0
- package/lib/rsi-authority-resources.js +139 -0
- package/lib/rsi-authority-resources.js.map +1 -0
- package/lib/rsi-authority-runtime.d.ts +50 -0
- package/lib/rsi-authority-runtime.d.ts.map +1 -0
- package/lib/rsi-authority-runtime.js +393 -0
- package/lib/rsi-authority-runtime.js.map +1 -0
- package/lib/rsi-bootstrap-manifest.d.ts +39 -0
- package/lib/rsi-bootstrap-manifest.d.ts.map +1 -0
- package/lib/rsi-bootstrap-manifest.js +366 -0
- package/lib/rsi-bootstrap-manifest.js.map +1 -0
- package/lib/rsi-bootstrap.d.ts +30 -0
- package/lib/rsi-bootstrap.d.ts.map +1 -0
- package/lib/rsi-bootstrap.js +363 -0
- package/lib/rsi-bootstrap.js.map +1 -0
- package/lib/rsi-build.d.ts +45 -0
- package/lib/rsi-build.d.ts.map +1 -0
- package/lib/rsi-build.js +404 -0
- package/lib/rsi-build.js.map +1 -0
- package/lib/rsi-creation-build.d.ts +47 -0
- package/lib/rsi-creation-build.d.ts.map +1 -0
- package/lib/rsi-creation-build.js +333 -0
- package/lib/rsi-creation-build.js.map +1 -0
- package/lib/rsi-host-authorities.d.ts +18 -0
- package/lib/rsi-host-authorities.d.ts.map +1 -0
- package/lib/rsi-host-authorities.js +129 -0
- package/lib/rsi-host-authorities.js.map +1 -0
- package/lib/rsi-host-update.d.ts +113 -0
- package/lib/rsi-host-update.d.ts.map +1 -0
- package/lib/rsi-host-update.js +316 -0
- package/lib/rsi-host-update.js.map +1 -0
- package/lib/rsi-install-inputs.d.ts +43 -0
- package/lib/rsi-install-inputs.d.ts.map +1 -0
- package/lib/rsi-install-inputs.js +342 -0
- package/lib/rsi-install-inputs.js.map +1 -0
- package/lib/rsi-install.d.ts +54 -0
- package/lib/rsi-install.d.ts.map +1 -0
- package/lib/rsi-install.js +404 -0
- package/lib/rsi-install.js.map +1 -0
- package/lib/rsi-local-activation.d.ts +78 -0
- package/lib/rsi-local-activation.d.ts.map +1 -0
- package/lib/rsi-local-activation.js +485 -0
- package/lib/rsi-local-activation.js.map +1 -0
- package/lib/rsi-local-cohort.d.ts +70 -0
- package/lib/rsi-local-cohort.d.ts.map +1 -0
- package/lib/rsi-local-cohort.js +781 -0
- package/lib/rsi-local-cohort.js.map +1 -0
- package/lib/rsi-local-install.d.ts +40 -0
- package/lib/rsi-local-install.d.ts.map +1 -0
- package/lib/rsi-local-install.js +221 -0
- package/lib/rsi-local-install.js.map +1 -0
- package/lib/rsi-local-pair-install.d.ts +38 -0
- package/lib/rsi-local-pair-install.d.ts.map +1 -0
- package/lib/rsi-local-pair-install.js +200 -0
- package/lib/rsi-local-pair-install.js.map +1 -0
- package/lib/rsi-local-profile-update.d.ts +25 -0
- package/lib/rsi-local-profile-update.d.ts.map +1 -0
- package/lib/rsi-local-profile-update.js +226 -0
- package/lib/rsi-local-profile-update.js.map +1 -0
- package/lib/rsi-local-resources.d.ts +37 -0
- package/lib/rsi-local-resources.d.ts.map +1 -0
- package/lib/rsi-local-resources.js +184 -0
- package/lib/rsi-local-resources.js.map +1 -0
- package/lib/rsi-local-roots-extension.d.ts +11 -0
- package/lib/rsi-local-roots-extension.d.ts.map +1 -0
- package/lib/rsi-local-roots-extension.js +31 -0
- package/lib/rsi-local-roots-extension.js.map +1 -0
- package/lib/rsi-local-update-build.d.ts +18 -0
- package/lib/rsi-local-update-build.d.ts.map +1 -0
- package/lib/rsi-local-update-build.js +37 -0
- package/lib/rsi-local-update-build.js.map +1 -0
- package/lib/rsi-local-update.d.ts +39 -0
- package/lib/rsi-local-update.d.ts.map +1 -0
- package/lib/rsi-local-update.js +205 -0
- package/lib/rsi-local-update.js.map +1 -0
- package/lib/rsi-memory-learning.d.ts +22 -0
- package/lib/rsi-memory-learning.d.ts.map +1 -0
- package/lib/rsi-memory-learning.js +76 -0
- package/lib/rsi-memory-learning.js.map +1 -0
- package/lib/rsi-owner-profile.d.ts +37 -0
- package/lib/rsi-owner-profile.d.ts.map +1 -0
- package/lib/rsi-owner-profile.js +178 -0
- package/lib/rsi-owner-profile.js.map +1 -0
- package/lib/rsi-plugin-creation.d.ts +31 -0
- package/lib/rsi-plugin-creation.d.ts.map +1 -0
- package/lib/rsi-plugin-creation.js +179 -0
- package/lib/rsi-plugin-creation.js.map +1 -0
- package/lib/rsi-profile.d.ts +23 -0
- package/lib/rsi-profile.d.ts.map +1 -1
- package/lib/rsi-profile.js +154 -43
- package/lib/rsi-profile.js.map +1 -1
- package/lib/rsi-release-build.d.ts +41 -0
- package/lib/rsi-release-build.d.ts.map +1 -0
- package/lib/rsi-release-build.js +223 -0
- package/lib/rsi-release-build.js.map +1 -0
- package/lib/rsi-service-environment.d.ts +6 -0
- package/lib/rsi-service-environment.d.ts.map +1 -0
- package/lib/rsi-service-environment.js +113 -0
- package/lib/rsi-service-environment.js.map +1 -0
- package/lib/rsi-service-setup.d.ts +10 -0
- package/lib/rsi-service-setup.d.ts.map +1 -0
- package/lib/rsi-service-setup.js +34 -0
- package/lib/rsi-service-setup.js.map +1 -0
- package/lib/rsi-setup.d.ts +35 -2
- package/lib/rsi-setup.d.ts.map +1 -1
- package/lib/rsi-setup.js +459 -32
- package/lib/rsi-setup.js.map +1 -1
- package/lib/rsi-source-maintenance.d.ts +25 -0
- package/lib/rsi-source-maintenance.d.ts.map +1 -0
- package/lib/rsi-source-maintenance.js +348 -0
- package/lib/rsi-source-maintenance.js.map +1 -0
- package/lib/rsi-source-update.d.ts +26 -0
- package/lib/rsi-source-update.d.ts.map +1 -0
- package/lib/rsi-source-update.js +276 -0
- package/lib/rsi-source-update.js.map +1 -0
- package/lib/rsi-source.d.ts +34 -0
- package/lib/rsi-source.d.ts.map +1 -0
- package/lib/rsi-source.js +375 -0
- package/lib/rsi-source.js.map +1 -0
- package/lib/rsi-systemd-bootstrap.d.ts +46 -0
- package/lib/rsi-systemd-bootstrap.d.ts.map +1 -0
- package/lib/rsi-systemd-bootstrap.js +271 -0
- package/lib/rsi-systemd-bootstrap.js.map +1 -0
- package/lib/sdk.d.ts.map +1 -1
- package/lib/sdk.js +26 -1
- package/lib/sdk.js.map +1 -1
- package/lib/setup-business.d.ts +49 -0
- package/lib/setup-business.d.ts.map +1 -0
- package/lib/setup-business.js +335 -0
- package/lib/setup-business.js.map +1 -0
- package/lib/setup-profile.d.ts +1 -1
- package/lib/setup-profile.d.ts.map +1 -1
- package/lib/setup-profile.js +25 -2
- package/lib/setup-profile.js.map +1 -1
- package/lib/setup.d.ts +12 -1
- package/lib/setup.d.ts.map +1 -1
- package/lib/setup.js +138 -34
- package/lib/setup.js.map +1 -1
- package/lib/systemd.d.ts +10 -0
- package/lib/systemd.d.ts.map +1 -1
- package/lib/systemd.js +23 -6
- package/lib/systemd.js.map +1 -1
- package/lib/types.d.ts +7 -0
- package/lib/types.d.ts.map +1 -1
- package/lib/types.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +32 -20
package/lib/setup.js
CHANGED
|
@@ -15,6 +15,9 @@ import { createOfficialLarkTransport } from './sdk.js';
|
|
|
15
15
|
import { installDshResidentService } from './resident.js';
|
|
16
16
|
import { prepareDshSystemdUserService } from './systemd.js';
|
|
17
17
|
import { configureLarkProfilePatch, refreshLarkAgentPolicyPatch } from './setup-profile.js';
|
|
18
|
+
import { ensureLarkBusinessCli } from './business-cli-install.js';
|
|
19
|
+
import { setupLarkBusinessTools } from './setup-business.js';
|
|
20
|
+
import { reconcileLarkBusinessSkill } from './business-skill.js';
|
|
18
21
|
import { assertRawManagedProfileIntegrity, materializeManagedProfileOverride, } from './setup-materialization.js';
|
|
19
22
|
const setupKeyPattern = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/u;
|
|
20
23
|
const keychainLocatorPattern = /^[A-Za-z0-9][A-Za-z0-9/._-]{0,255}$/u;
|
|
@@ -33,13 +36,14 @@ export function parseLarkSetupArgs(argv) {
|
|
|
33
36
|
tenant: 'personal',
|
|
34
37
|
createApp: false,
|
|
35
38
|
calendarReadonly: false,
|
|
39
|
+
businessTools: true,
|
|
36
40
|
appName: 'DSH Personal Assistant',
|
|
37
41
|
timeoutMs: 300_000,
|
|
38
42
|
installServiceOnly: false,
|
|
39
43
|
refreshAgentPolicy: false,
|
|
40
44
|
manageService: true,
|
|
41
45
|
linuxCredentialProvider: 'auto',
|
|
42
|
-
agentTools: '
|
|
46
|
+
agentTools: 'auto',
|
|
43
47
|
help: false,
|
|
44
48
|
};
|
|
45
49
|
for (let index = 0; index < argv.length; index += 1) {
|
|
@@ -66,6 +70,8 @@ export function parseLarkSetupArgs(argv) {
|
|
|
66
70
|
result.createApp = true;
|
|
67
71
|
else if (option === '--calendar-readonly')
|
|
68
72
|
result.calendarReadonly = true;
|
|
73
|
+
else if (option === '--no-business-tools')
|
|
74
|
+
result.businessTools = false;
|
|
69
75
|
else if (option === '--install-service')
|
|
70
76
|
result.installServiceOnly = true;
|
|
71
77
|
else if (option === '--refresh-agent-policy')
|
|
@@ -75,11 +81,11 @@ export function parseLarkSetupArgs(argv) {
|
|
|
75
81
|
else if (option === '--linux-credential-provider') {
|
|
76
82
|
result.linuxCredentialProvider = argumentValue(argv, index++, option);
|
|
77
83
|
}
|
|
78
|
-
else if (option === '--allow-agent-tools' || option === '--disable-agent-tools') {
|
|
79
|
-
if (result.agentTools !== '
|
|
80
|
-
throw new Error('lark-channel setup: --allow-agent-tools and --
|
|
84
|
+
else if (option === '--allow-agent-tools' || option === '--disable-agent-tools' || option === '--preserve-agent-tools') {
|
|
85
|
+
if (result.agentTools !== 'auto') {
|
|
86
|
+
throw new Error('lark-channel setup: --allow-agent-tools, --disable-agent-tools and --preserve-agent-tools are mutually exclusive');
|
|
81
87
|
}
|
|
82
|
-
result.agentTools = option === '--allow-agent-tools' ? 'enable' : 'disable';
|
|
88
|
+
result.agentTools = option === '--allow-agent-tools' ? 'enable' : option === '--disable-agent-tools' ? 'disable' : 'preserve';
|
|
83
89
|
}
|
|
84
90
|
else if (option === '--app-name')
|
|
85
91
|
result.appName = argumentValue(argv, index++, option);
|
|
@@ -100,12 +106,12 @@ export function parseLarkSetupArgs(argv) {
|
|
|
100
106
|
if (!result.help && result.refreshAgentPolicy) {
|
|
101
107
|
const incompatible = [
|
|
102
108
|
'--domain', '--tenant', '--app-id', '--create-app', '--install-service',
|
|
103
|
-
'--no-service', '--linux-credential-provider', '--app-name', '--timeout-ms',
|
|
109
|
+
'--no-service', '--linux-credential-provider', '--app-name', '--timeout-ms', '--no-business-tools',
|
|
104
110
|
].find(option => argv.includes(option));
|
|
105
111
|
if (incompatible !== undefined) {
|
|
106
112
|
throw new Error(`lark-channel setup: --refresh-agent-policy cannot be combined with ${incompatible}`);
|
|
107
113
|
}
|
|
108
|
-
if (result.agentTools
|
|
114
|
+
if (result.agentTools !== 'enable' && result.agentTools !== 'disable') {
|
|
109
115
|
throw new Error('lark-channel setup: --refresh-agent-policy requires --allow-agent-tools or --disable-agent-tools');
|
|
110
116
|
}
|
|
111
117
|
}
|
|
@@ -118,10 +124,13 @@ export function parseLarkSetupArgs(argv) {
|
|
|
118
124
|
if (result.installServiceOnly && (result.createApp || result.appId !== undefined)) {
|
|
119
125
|
throw new Error('lark-channel setup: --install-service cannot be combined with application setup options');
|
|
120
126
|
}
|
|
127
|
+
if (result.installServiceOnly && !result.businessTools) {
|
|
128
|
+
throw new Error('lark-channel setup: --install-service cannot be combined with --no-business-tools');
|
|
129
|
+
}
|
|
121
130
|
if (result.installServiceOnly && argv.includes('--linux-credential-provider')) {
|
|
122
131
|
throw new Error('lark-channel setup: --install-service cannot be combined with --linux-credential-provider');
|
|
123
132
|
}
|
|
124
|
-
if (result.installServiceOnly && result.agentTools !== '
|
|
133
|
+
if (result.installServiceOnly && result.agentTools !== 'auto') {
|
|
125
134
|
throw new Error('lark-channel setup: --install-service cannot be combined with agent-tools options');
|
|
126
135
|
}
|
|
127
136
|
const appNameHasControlCharacter = [...result.appName]
|
|
@@ -151,7 +160,7 @@ export function createLarkRegistrationOptions(input) {
|
|
|
151
160
|
desc: '由 DeepSeek Harness 驱动的个人助理',
|
|
152
161
|
},
|
|
153
162
|
addons: {
|
|
154
|
-
preset: false,
|
|
163
|
+
preset: input.businessTools !== false,
|
|
155
164
|
scopes: { tenant: [
|
|
156
165
|
'application:bot.basic_info:read',
|
|
157
166
|
'im:message.group_at_msg:readonly',
|
|
@@ -289,10 +298,13 @@ Options:
|
|
|
289
298
|
--install-service Only install/restart the profile's resident service
|
|
290
299
|
--refresh-agent-policy Only refresh policy from the existing channel binding
|
|
291
300
|
--no-service Configure Lark without installing a resident service
|
|
301
|
+
--no-business-tools Only configure the message channel; skip business CLI and user authorization
|
|
292
302
|
--linux-credential-provider <mode>
|
|
293
303
|
auto, protected-file, or secret-service (default: auto)
|
|
294
304
|
--allow-agent-tools Allow mounted foreground/external Agent capabilities
|
|
295
305
|
--disable-agent-tools Remove setup-managed Agent capability rules
|
|
306
|
+
--preserve-agent-tools Preserve existing rules, including on first setup
|
|
307
|
+
Default: allow for a new owner, preserve on reconfiguration
|
|
296
308
|
--timeout-ms <ms> Owner DM wait, 30000..900000 (default: 300000)
|
|
297
309
|
-h, --help Show this help
|
|
298
310
|
|
|
@@ -1146,6 +1158,7 @@ async function registerLarkApplication(args) {
|
|
|
1146
1158
|
appName: args.appName,
|
|
1147
1159
|
...(args.appId === undefined ? {} : { appId: args.appId }),
|
|
1148
1160
|
...(args.calendarReadonly ? { calendarReadonly: true } : {}),
|
|
1161
|
+
businessTools: args.businessTools,
|
|
1149
1162
|
signal: abortController.signal,
|
|
1150
1163
|
onQRCodeReady(info) {
|
|
1151
1164
|
process.stdout.write(`\n请在飞书中打开以下链接,选择已有应用或创建新应用(${info.expireIn} 秒内有效):\n${info.url}\n\n`);
|
|
@@ -1881,6 +1894,40 @@ function effectiveProfileHasEnabledLarkChannel(effectiveProfile, profile) {
|
|
|
1881
1894
|
throw new Error(`lark-channel setup: profile ${profile} has an invalid Lark config`);
|
|
1882
1895
|
return config.get('enabled') !== false;
|
|
1883
1896
|
}
|
|
1897
|
+
function effectiveDeliveryConsumerDatabasePaths(effectiveProfile, dshHome, profile) {
|
|
1898
|
+
const document = parseDocument(effectiveProfile, { uniqueKeys: true });
|
|
1899
|
+
if (document.errors.length > 0 || !isSeq(document.contents)) {
|
|
1900
|
+
throw new Error(`lark-channel setup: cannot verify effective Delivery consumers in profile ${profile}`);
|
|
1901
|
+
}
|
|
1902
|
+
const paths = [];
|
|
1903
|
+
for (const row of document.contents.items) {
|
|
1904
|
+
if (!isMap(row))
|
|
1905
|
+
continue;
|
|
1906
|
+
const id = row.get('id');
|
|
1907
|
+
const name = row.get('name');
|
|
1908
|
+
if (id !== 'dsh-enhanced-assistant-delivery' && name !== '@dsh-enhanced/assistant-delivery')
|
|
1909
|
+
continue;
|
|
1910
|
+
if (!setupRowIsEnabled(row))
|
|
1911
|
+
continue;
|
|
1912
|
+
if (name !== '@dsh-enhanced/assistant-delivery') {
|
|
1913
|
+
throw new Error(`lark-channel setup: profile ${profile} has an invalid effective Delivery package row`);
|
|
1914
|
+
}
|
|
1915
|
+
const config = row.get('config', true);
|
|
1916
|
+
if (!isMap(config))
|
|
1917
|
+
throw new Error(`lark-channel setup: profile ${profile} has an invalid Delivery config`);
|
|
1918
|
+
const schedulerEnabled = config.get('schedulerEnabled');
|
|
1919
|
+
if (schedulerEnabled !== undefined && typeof schedulerEnabled !== 'boolean') {
|
|
1920
|
+
throw new Error(`lark-channel setup: profile ${profile} has a non-boolean Delivery schedulerEnabled value`);
|
|
1921
|
+
}
|
|
1922
|
+
// Delivery defaults to starting its scheduler independently of the Lark
|
|
1923
|
+
// adapter. A stopped service may restart later; configuration alone only
|
|
1924
|
+
// proves that it cannot consume when the scheduler is explicitly disabled.
|
|
1925
|
+
if (schedulerEnabled === false)
|
|
1926
|
+
continue;
|
|
1927
|
+
paths.push(dshEffectiveDataPath(config.get('databasePath'), dshHome, 'assistant-delivery databasePath'));
|
|
1928
|
+
}
|
|
1929
|
+
return paths;
|
|
1930
|
+
}
|
|
1884
1931
|
function externalPrincipalKeyId(principal) {
|
|
1885
1932
|
return [principal.channel, principal.account, principal.tenant, principal.user]
|
|
1886
1933
|
.map(component => encodeURIComponent(component))
|
|
@@ -2181,7 +2228,7 @@ function assertEffectiveLarkOwnerBinding(input) {
|
|
|
2181
2228
|
throw new Error(`lark-channel setup: effective Lark binding no longer represents the ${suffix}`);
|
|
2182
2229
|
}
|
|
2183
2230
|
}
|
|
2184
|
-
async function
|
|
2231
|
+
async function assertNoOtherProfileSharesDelivery(input) {
|
|
2185
2232
|
let entries;
|
|
2186
2233
|
try {
|
|
2187
2234
|
entries = await readdir(platformJoin(input.dshHome, 'profiles'), { withFileTypes: true });
|
|
@@ -2198,7 +2245,7 @@ async function assertNoOtherLarkProfileSharesDelivery(input) {
|
|
|
2198
2245
|
|| !setupKeyPattern.test(entry.name))
|
|
2199
2246
|
continue;
|
|
2200
2247
|
const patchPath = platformJoin(input.dshHome, 'profiles', entry.name, 'cordis.patch.yml');
|
|
2201
|
-
// A profile can inherit Lark
|
|
2248
|
+
// A profile can inherit Delivery or Lark from a lower bundle while its raw
|
|
2202
2249
|
// override contains no channel row. Activation and database identity must
|
|
2203
2250
|
// therefore come from effective config whenever that profile composes.
|
|
2204
2251
|
try {
|
|
@@ -2214,21 +2261,24 @@ async function assertNoOtherLarkProfileSharesDelivery(input) {
|
|
|
2214
2261
|
effective = await input.readEffectiveProfile(entry.name);
|
|
2215
2262
|
}
|
|
2216
2263
|
catch (error) {
|
|
2217
|
-
// Raw absence cannot prove absence:
|
|
2264
|
+
// Raw absence cannot prove absence: consumers may be inherited from a lower
|
|
2218
2265
|
// bundle and a resident using the last valid composition may still run.
|
|
2219
2266
|
// Without a durable ownership registry, an unverifiable real profile is
|
|
2220
2267
|
// therefore a fail-closed handoff boundary.
|
|
2221
|
-
throw new Error(`lark-channel setup: cannot verify effective Lark ownership in profile ${entry.name}`, {
|
|
2268
|
+
throw new Error(`lark-channel setup: cannot verify effective Lark ownership in profile ${entry.name} or its Delivery consumers`, {
|
|
2222
2269
|
cause: error,
|
|
2223
2270
|
});
|
|
2224
2271
|
}
|
|
2225
|
-
if (
|
|
2226
|
-
|
|
2227
|
-
const otherDatabasePath = deliveryDatabasePathFromEffectiveProfile(effective, input.dshHome);
|
|
2228
|
-
if (normalizeSetupResourcePath(otherDatabasePath) === databasePath) {
|
|
2272
|
+
if (effectiveProfileHasEnabledLarkChannel(effective, entry.name)
|
|
2273
|
+
&& normalizeSetupResourcePath(deliveryDatabasePathFromEffectiveProfile(effective, input.dshHome)) === databasePath) {
|
|
2229
2274
|
throw new Error(`lark-channel setup: profile ${entry.name} already owns Lark for the same assistant-delivery database; `
|
|
2230
2275
|
+ 'refusing to revoke its owner from another profile');
|
|
2231
2276
|
}
|
|
2277
|
+
if (effectiveDeliveryConsumerDatabasePaths(effective, input.dshHome, entry.name)
|
|
2278
|
+
.some(path => normalizeSetupResourcePath(path) === databasePath)) {
|
|
2279
|
+
throw new Error(`lark-channel setup: profile ${entry.name} has an enabled assistant-delivery scheduler for the same database; `
|
|
2280
|
+
+ 'disable its scheduler or configure a separate database before continuing');
|
|
2281
|
+
}
|
|
2232
2282
|
}
|
|
2233
2283
|
}
|
|
2234
2284
|
async function withDeliveryOwnerSetupLock(databasePath, operation, options = {}) {
|
|
@@ -2406,7 +2456,7 @@ async function recoverLarkSetupJournalUnlocked(input) {
|
|
|
2406
2456
|
stagedCredential: journal.stagedCredential,
|
|
2407
2457
|
context: 'journal',
|
|
2408
2458
|
});
|
|
2409
|
-
await
|
|
2459
|
+
await assertNoOtherProfileSharesDelivery({
|
|
2410
2460
|
dshHome: input.dshHome,
|
|
2411
2461
|
profile: input.profile,
|
|
2412
2462
|
databasePath,
|
|
@@ -2588,7 +2638,7 @@ export async function executeLarkSetupProfileTransaction(input) {
|
|
|
2588
2638
|
effectiveProfile,
|
|
2589
2639
|
});
|
|
2590
2640
|
await withDeliveryOwnerSetupLock(databasePath, async () => {
|
|
2591
|
-
await
|
|
2641
|
+
await assertNoOtherProfileSharesDelivery({
|
|
2592
2642
|
dshHome: input.dshHome,
|
|
2593
2643
|
profile: input.args.profile,
|
|
2594
2644
|
databasePath,
|
|
@@ -2824,7 +2874,7 @@ export async function runLarkSetup(argv = process.argv.slice(2), runtime = {}) {
|
|
|
2824
2874
|
const effectiveProfile = await readEffectiveProfile(args.profile);
|
|
2825
2875
|
const databasePath = deliveryDatabasePathFromEffectiveProfile(effectiveProfile, dshHome);
|
|
2826
2876
|
await withDeliveryOwnerSetupLock(databasePath, async () => {
|
|
2827
|
-
await
|
|
2877
|
+
await assertNoOtherProfileSharesDelivery({
|
|
2828
2878
|
dshHome,
|
|
2829
2879
|
profile: args.profile,
|
|
2830
2880
|
databasePath,
|
|
@@ -2911,7 +2961,7 @@ export async function runLarkSetup(argv = process.argv.slice(2), runtime = {}) {
|
|
|
2911
2961
|
});
|
|
2912
2962
|
const databasePath = deliveryDatabasePathFromEffectiveProfile(await readEffectiveProfile(args.profile), dshHome);
|
|
2913
2963
|
return withDeliveryOwnerSetupLock(databasePath, async () => {
|
|
2914
|
-
await
|
|
2964
|
+
await assertNoOtherProfileSharesDelivery({
|
|
2915
2965
|
dshHome,
|
|
2916
2966
|
profile: args.profile,
|
|
2917
2967
|
databasePath,
|
|
@@ -2971,7 +3021,7 @@ export async function runLarkSetup(argv = process.argv.slice(2), runtime = {}) {
|
|
|
2971
3021
|
});
|
|
2972
3022
|
const databasePath = deliveryDatabasePathFromEffectiveProfile(await readEffectiveProfile(args.profile), dshHome);
|
|
2973
3023
|
await withDeliveryOwnerSetupLock(databasePath, async () => {
|
|
2974
|
-
await
|
|
3024
|
+
await assertNoOtherProfileSharesDelivery({
|
|
2975
3025
|
dshHome,
|
|
2976
3026
|
profile: args.profile,
|
|
2977
3027
|
databasePath,
|
|
@@ -2979,6 +3029,9 @@ export async function runLarkSetup(argv = process.argv.slice(2), runtime = {}) {
|
|
|
2979
3029
|
});
|
|
2980
3030
|
}, runtime.profileLockOptions);
|
|
2981
3031
|
}, runtime.profileLockOptions);
|
|
3032
|
+
const businessCli = args.businessTools
|
|
3033
|
+
? await (runtime.ensureBusinessCli ?? ensureLarkBusinessCli)({ dshHome })
|
|
3034
|
+
: undefined;
|
|
2982
3035
|
let appId = args.appId;
|
|
2983
3036
|
let createApp = args.createApp;
|
|
2984
3037
|
if (appId === undefined && !createApp) {
|
|
@@ -2995,9 +3048,9 @@ export async function runLarkSetup(argv = process.argv.slice(2), runtime = {}) {
|
|
|
2995
3048
|
let generatedSecret;
|
|
2996
3049
|
if (createApp) {
|
|
2997
3050
|
process.stdout.write(args.appId === undefined
|
|
2998
|
-
? '\n
|
|
2999
|
-
: `\n将通过飞书官方设备授权更新已有应用 ${args.appId}
|
|
3000
|
-
const registration = await registerLarkApplication(args);
|
|
3051
|
+
? '\n将通过飞书官方设备授权选择已有应用或创建新应用,并增量申请应用权限。App Secret 不会显示或写入 profile。\n'
|
|
3052
|
+
: `\n将通过飞书官方设备授权更新已有应用 ${args.appId},并增量申请应用权限。App Secret 不会显示或写入 profile。\n`);
|
|
3053
|
+
const registration = await (runtime.registerApplication ?? registerLarkApplication)(args);
|
|
3001
3054
|
appId = registration.client_id;
|
|
3002
3055
|
resolvedDomain = registration.user_info?.tenant_brand ?? resolvedDomain;
|
|
3003
3056
|
generatedSecret = registration.client_secret;
|
|
@@ -3014,6 +3067,7 @@ export async function runLarkSetup(argv = process.argv.slice(2), runtime = {}) {
|
|
|
3014
3067
|
throw new Error('lark-channel setup: Feishu did not return an App ID');
|
|
3015
3068
|
const configuredAppId = appId;
|
|
3016
3069
|
let installedService;
|
|
3070
|
+
let businessBinding;
|
|
3017
3071
|
await executeLarkSetupProfileTransaction({
|
|
3018
3072
|
args,
|
|
3019
3073
|
dshHome,
|
|
@@ -3049,17 +3103,38 @@ export async function runLarkSetup(argv = process.argv.slice(2), runtime = {}) {
|
|
|
3049
3103
|
: undefined);
|
|
3050
3104
|
},
|
|
3051
3105
|
readEffectiveProfile,
|
|
3106
|
+
validateProfile: validate,
|
|
3107
|
+
...runtime.ownerSetupOperations,
|
|
3052
3108
|
async discoverOwner(ownerInput) {
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3109
|
+
let owner;
|
|
3110
|
+
if (runtime.discoverOwner !== undefined)
|
|
3111
|
+
owner = await runtime.discoverOwner(ownerInput);
|
|
3112
|
+
else {
|
|
3113
|
+
const phrase = `DSH-CONNECT-${randomBytes(4).toString('hex').toUpperCase()}`;
|
|
3114
|
+
const transport = createOfficialLarkTransport({
|
|
3115
|
+
appId: ownerInput.appId,
|
|
3116
|
+
appSecret: ownerInput.appSecret,
|
|
3117
|
+
domain: ownerInput.domain,
|
|
3118
|
+
handshakeTimeoutMs: 15_000,
|
|
3119
|
+
requestTimeoutMs: 30_000,
|
|
3120
|
+
imageDownloadTimeoutMs: 30_000,
|
|
3121
|
+
});
|
|
3122
|
+
owner = await discoverOwner(transport, phrase, ownerInput.account, ownerInput.tenant, ownerInput.timeoutMs);
|
|
3123
|
+
}
|
|
3124
|
+
if (args.businessTools)
|
|
3125
|
+
businessBinding = { appSecret: ownerInput.appSecret, owner };
|
|
3126
|
+
const previousDocument = parseDocument(await readEffectiveProfile(args.profile), { uniqueKeys: true });
|
|
3127
|
+
const previousRow = isSeq(previousDocument.contents)
|
|
3128
|
+
? previousDocument.contents.items.find(item => isMap(item) && item.get('id') === 'dsh-enhanced-lark-channel')
|
|
3129
|
+
: undefined;
|
|
3130
|
+
const previousConfig = isMap(previousRow) ? previousRow.get('config', true) : undefined;
|
|
3131
|
+
const previousAccount = isMap(previousConfig) ? previousConfig.get('account') : undefined;
|
|
3132
|
+
await reconcileLarkBusinessSkill({
|
|
3133
|
+
dshHome, profile: args.profile, account: args.account, appId: ownerInput.appId,
|
|
3134
|
+
ownerUserId: owner.user, enabled: args.businessTools,
|
|
3135
|
+
...(typeof previousAccount === 'string' ? { previousAccount } : {}),
|
|
3061
3136
|
});
|
|
3062
|
-
return
|
|
3137
|
+
return owner;
|
|
3063
3138
|
},
|
|
3064
3139
|
...(args.manageService ? {
|
|
3065
3140
|
async afterCommit() {
|
|
@@ -3068,6 +3143,35 @@ export async function runLarkSetup(argv = process.argv.slice(2), runtime = {}) {
|
|
|
3068
3143
|
} : {}),
|
|
3069
3144
|
},
|
|
3070
3145
|
});
|
|
3146
|
+
if (businessCli !== undefined) {
|
|
3147
|
+
const binding = businessBinding;
|
|
3148
|
+
if (binding === undefined)
|
|
3149
|
+
throw new Error('lark-channel setup: business tools require the completed owner binding');
|
|
3150
|
+
process.stdout.write('\n消息通道已配置;正在接入飞书业务工具并检查 owner 用户授权。\n');
|
|
3151
|
+
const business = await (runtime.setupBusinessTools ?? setupLarkBusinessTools)({
|
|
3152
|
+
dshHome, profile: args.profile, account: args.account, appId: configuredAppId,
|
|
3153
|
+
appSecret: binding.appSecret, domain: resolvedDomain, ownerUserId: binding.owner.user,
|
|
3154
|
+
cli: businessCli, timeoutMs: args.timeoutMs,
|
|
3155
|
+
async onAuthorization(url) {
|
|
3156
|
+
process.stdout.write(`\n请用刚才绑定的飞书账号完成业务权限授权:\n${url}\n\n`);
|
|
3157
|
+
try {
|
|
3158
|
+
process.stdout.write(`${await QRCode.toString(url, { type: 'terminal', small: true })}\n`);
|
|
3159
|
+
}
|
|
3160
|
+
catch {
|
|
3161
|
+
process.stdout.write('终端二维码生成失败,请打开上面的链接。\n');
|
|
3162
|
+
}
|
|
3163
|
+
},
|
|
3164
|
+
});
|
|
3165
|
+
businessBinding = undefined;
|
|
3166
|
+
process.stdout.write(`飞书业务工具已接入${business.reusedAuthorization ? ',复用已有 owner 授权' : ''}。技能:${business.skillPath}\n`);
|
|
3167
|
+
if (business.permissionCompletion === 'partial') {
|
|
3168
|
+
process.stdout.write(`用户登录已完成;本次申请仍有 ${business.missingScopes.length} 项权限未获批,业务工具仅使用实际已授予的权限。\n`
|
|
3169
|
+
+ `未获批权限:${business.missingScopes.join(', ')}\n`);
|
|
3170
|
+
}
|
|
3171
|
+
else if (business.permissionCompletion === 'unknown') {
|
|
3172
|
+
process.stdout.write('已验证 owner 登录;当前授权证据不足以确认完整权限清单,具体操作仍以平台当前授权为准。\n');
|
|
3173
|
+
}
|
|
3174
|
+
}
|
|
3071
3175
|
if (args.manageService) {
|
|
3072
3176
|
const service = installedService;
|
|
3073
3177
|
if (service === undefined)
|