openyida 2026.8.5 → 2026.8.11

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 CHANGED
@@ -369,6 +369,8 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
369
369
  | `openyida corp-efficiency [overview\|details\|detail\|groups\|notify] [options] [--open\|--no-open]` | Query enterprise efficiency overview and detail reports |
370
370
  | `openyida create-app "<name>"\|--name <name> [options] [--locale zh_CN\|en_US\|ja_JP] [--open\|--no-open]` | Create a Yida app |
371
371
  | `openyida update-app <appType> [--name "..."] [--layout slide\|ver] [--theme deepBlue]` | Update app info |
372
+ | `openyida app-online <appType> [--to-ding-app-center] [--show-app-center]` | Enable a Yida app |
373
+ | `openyida app-offline <appType> [--to-ding-app-center] [--show-app-center]` | Disable a Yida app |
372
374
  | `openyida nav-group <list\|create\|rename\|delete\|move\|order\|auto-order\|hide\|show> <appType> ...` | Manage app sidebar navigation groups |
373
375
  | `openyida app-permission <get\|set\|add\|remove\|search-user> ...` | Manage app primary, data, and developer admins |
374
376
  | `openyida i18n <overview\|config\|languages\|list\|upsert\|delete\|translate\|translate-all\|upgrade> <appType> ...` | Manage app multilingual copy and language config |
package/bin/yida.js CHANGED
@@ -841,6 +841,13 @@ async function main() {
841
841
  break;
842
842
  }
843
843
 
844
+ case 'app-online':
845
+ case 'app-offline': {
846
+ const { run: runAppLifecycle } = require('../lib/app/app-lifecycle');
847
+ await runAppLifecycle(command === 'app-online' ? 'online' : 'offline', args);
848
+ break;
849
+ }
850
+
844
851
  case 'nav-group':
845
852
  case 'group': {
846
853
  const { run: runNavGroup } = require('../lib/app/nav-group');
@@ -0,0 +1,128 @@
1
+ /**
2
+ * app-lifecycle.js - 启用或停用宜搭应用
3
+ *
4
+ * 用法:
5
+ * openyida app-online <appType> [--to-ding-app-center] [--show-app-center]
6
+ * openyida app-offline <appType> [--to-ding-app-center] [--show-app-center]
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const querystring = require('querystring');
12
+ const { httpPost, requestWithAutoLogin } = require('../core/utils');
13
+ const { createAuthRef } = require('../core/yida-client');
14
+ const { t } = require('../core/i18n');
15
+ const { throwCommandError, throwUsage } = require('../core/command-errors');
16
+
17
+ const ACTIONS = Object.freeze({
18
+ online: Object.freeze({ endpoint: 'onlineApp', api: 'App.goOnline' }),
19
+ offline: Object.freeze({ endpoint: 'offlineApp', api: 'App.goOffline' }),
20
+ });
21
+
22
+ function parseArgs(args = []) {
23
+ const params = {
24
+ appType: null,
25
+ toDingAppCenter: false,
26
+ showAppCenter: false,
27
+ help: false,
28
+ };
29
+
30
+ for (const arg of args) {
31
+ if (arg === '--help' || arg === '-h') {
32
+ params.help = true;
33
+ } else if (arg === '--to-ding-app-center') {
34
+ params.toDingAppCenter = true;
35
+ } else if (arg === '--show-app-center') {
36
+ params.showAppCenter = true;
37
+ } else if (!arg.startsWith('-') && !params.appType) {
38
+ params.appType = arg;
39
+ } else {
40
+ throwUsage(t('app_lifecycle.invalid_argument', arg));
41
+ }
42
+ }
43
+
44
+ return params;
45
+ }
46
+
47
+ function buildRequestPath(action, appType, stamp = Date.now()) {
48
+ const config = ACTIONS[action];
49
+ if (!config) {
50
+ throw new Error(t('app_lifecycle.invalid_action', action));
51
+ }
52
+ return `/dingtalk/web/${encodeURIComponent(appType)}/query/app/${config.endpoint}.json` +
53
+ `?_api=${encodeURIComponent(config.api)}&_mock=false&_stamp=${stamp}`;
54
+ }
55
+
56
+ function buildPostData(params, authRef) {
57
+ return querystring.stringify({
58
+ _csrf_token: authRef.csrfToken || '',
59
+ _locale_time_zone_offset: '28800000',
60
+ isToDingAppCenter: params.toDingAppCenter ? 'y' : 'n',
61
+ showAppCenter: params.showAppCenter ? 'y' : 'n',
62
+ });
63
+ }
64
+
65
+ async function changeAppLifecycle(action, params, authRef = createAuthRef()) {
66
+ const response = await requestWithAutoLogin((auth) => httpPost(
67
+ auth.baseUrl,
68
+ buildRequestPath(action, params.appType),
69
+ buildPostData(params, auth),
70
+ auth.cookies
71
+ ), authRef);
72
+
73
+ if (!response || response.success !== true || response.content !== true) {
74
+ const errorMsg = response && (response.errorMsg || response.message || response.errorCode);
75
+ throwCommandError(errorMsg || t('app_lifecycle.request_failed'), {
76
+ code: action === 'online' ? 'APP_ONLINE_FAILED' : 'APP_OFFLINE_FAILED',
77
+ details: { action, appType: params.appType },
78
+ });
79
+ }
80
+
81
+ return {
82
+ success: true,
83
+ action,
84
+ appType: params.appType,
85
+ isToDingAppCenter: params.toDingAppCenter,
86
+ showAppCenter: params.showAppCenter,
87
+ };
88
+ }
89
+
90
+ function printUsage(action) {
91
+ const { usage } = require('../core/chalk');
92
+ usage(t(`app_lifecycle.${action}_usage`), t(`app_lifecycle.${action}_example`));
93
+ }
94
+
95
+ async function run(action, args = []) {
96
+ if (!ACTIONS[action]) {
97
+ throwCommandError(t('app_lifecycle.invalid_action', action), {
98
+ code: 'APP_LIFECYCLE_INVALID_ACTION',
99
+ });
100
+ }
101
+
102
+ const params = parseArgs(args);
103
+ if (params.help) {
104
+ printUsage(action);
105
+ return { success: true, help: true };
106
+ }
107
+ if (!params.appType) {
108
+ printUsage(action);
109
+ throwUsage(t('app_lifecycle.missing_app_type'), t(`app_lifecycle.${action}_usage`), {
110
+ code: 'APP_LIFECYCLE_USAGE',
111
+ });
112
+ }
113
+
114
+ const output = await changeAppLifecycle(action, params);
115
+ const { result } = require('../core/chalk');
116
+ result(true, t(`app_lifecycle.${action}_success`), [['appType', params.appType]]);
117
+ console.log(JSON.stringify(output));
118
+ return output;
119
+ }
120
+
121
+ module.exports = {
122
+ ACTIONS,
123
+ buildPostData,
124
+ buildRequestPath,
125
+ changeAppLifecycle,
126
+ parseArgs,
127
+ run,
128
+ };
@@ -187,6 +187,117 @@ function buildComponentAliasMaps(schemaResult) {
187
187
  return { aliasByFieldId, fieldIdByAlias };
188
188
  }
189
189
 
190
+ function parseJsonObject(value) {
191
+ if (typeof value !== 'string') {
192
+ return value && typeof value === 'object' ? value : null;
193
+ }
194
+ try {
195
+ const parsed = JSON.parse(value);
196
+ return parsed && typeof parsed === 'object' ? parsed : null;
197
+ } catch {
198
+ return null;
199
+ }
200
+ }
201
+
202
+ function resolveSchemaContent(schemaResult) {
203
+ if (!schemaResult) {
204
+ return null;
205
+ }
206
+ const content = schemaResult.content !== undefined ? schemaResult.content : schemaResult;
207
+ return parseJsonObject(content);
208
+ }
209
+
210
+ function addImportedModules(target, value) {
211
+ let modules = value;
212
+ if (typeof modules === 'string') {
213
+ const trimmed = modules.trim();
214
+ if (!trimmed) {
215
+ return;
216
+ }
217
+ try {
218
+ modules = JSON.parse(trimmed);
219
+ } catch {
220
+ modules = [trimmed];
221
+ }
222
+ }
223
+ if (!Array.isArray(modules)) {
224
+ return;
225
+ }
226
+ modules
227
+ .map(item => String(item || '').trim())
228
+ .filter(Boolean)
229
+ .forEach((item) => {
230
+ if (!target.includes(item)) {
231
+ target.push(item);
232
+ }
233
+ });
234
+ }
235
+
236
+ function codeBytes(value) {
237
+ return typeof value === 'string' ? Buffer.byteLength(value, 'utf8') : 0;
238
+ }
239
+
240
+ function isComponentInstance(node) {
241
+ return !!(node && typeof node === 'object' && (node.id || node.props || node.children));
242
+ }
243
+
244
+ function extractDisplayPageSummary(schemaResult) {
245
+ const content = resolveSchemaContent(schemaResult);
246
+ if (!content || typeof content !== 'object') {
247
+ return null;
248
+ }
249
+
250
+ const displayPage = {
251
+ hasYidaCodeCanvas: false,
252
+ hasNativeJsx: false,
253
+ runtimeCodeBytes: 0,
254
+ sourceCodeBytes: 0,
255
+ compiledCodeBytes: 0,
256
+ importedModules: [],
257
+ componentCount: 0,
258
+ };
259
+
260
+ function traverse(node) {
261
+ if (!node) {
262
+ return;
263
+ }
264
+ if (Array.isArray(node)) {
265
+ node.forEach(traverse);
266
+ return;
267
+ }
268
+ if (typeof node !== 'object') {
269
+ return;
270
+ }
271
+
272
+ if (node.componentName === 'YidaCodeCanvas' && isComponentInstance(node)) {
273
+ const props = node.props || {};
274
+ displayPage.hasYidaCodeCanvas = true;
275
+ displayPage.componentCount++;
276
+ displayPage.runtimeCodeBytes += codeBytes(props.runtimeCode);
277
+ displayPage.sourceCodeBytes += codeBytes(props.code);
278
+ addImportedModules(displayPage.importedModules, props.importedModules);
279
+ } else if (node.componentName === 'Jsx' && isComponentInstance(node)) {
280
+ displayPage.hasNativeJsx = true;
281
+ displayPage.componentCount++;
282
+ }
283
+
284
+ Object.keys(node).forEach((key) => traverse(node[key]));
285
+ }
286
+
287
+ traverse(content.pages || content);
288
+
289
+ const module = content.actions && content.actions.module;
290
+ if (displayPage.hasNativeJsx && module && typeof module === 'object') {
291
+ displayPage.sourceCodeBytes += codeBytes(module.source);
292
+ displayPage.compiledCodeBytes += codeBytes(module.compiled);
293
+ }
294
+
295
+ if (!displayPage.hasYidaCodeCanvas && !displayPage.hasNativeJsx) {
296
+ return null;
297
+ }
298
+ return displayPage;
299
+ }
300
+
190
301
  function parsePositiveInt(value, fallback, min, max) {
191
302
  const parsed = Number.parseInt(value, 10);
192
303
  if (!Number.isFinite(parsed) || parsed < min) {
@@ -402,7 +513,7 @@ function printFieldSummary(result) {
402
513
 
403
514
  function buildSchemaSummary(appType, formUuid, schemaResult, meta = {}) {
404
515
  const fields = extractFieldSummary(schemaResult);
405
- return {
516
+ const summary = {
406
517
  success: true,
407
518
  appType,
408
519
  formUuid,
@@ -410,6 +521,11 @@ function buildSchemaSummary(appType, formUuid, schemaResult, meta = {}) {
410
521
  fieldCount: fields.length,
411
522
  fields,
412
523
  };
524
+ const displayPage = extractDisplayPageSummary(schemaResult);
525
+ if (displayPage) {
526
+ summary.displayPage = displayPage;
527
+ }
528
+ return summary;
413
529
  }
414
530
 
415
531
  function filterForms(forms, keyword) {
@@ -454,7 +570,7 @@ async function fetchSchemaRecord(appType, form, authRef, retries) {
454
570
  try {
455
571
  const result = await fetchSchema(appType, form.formUuid, authRef);
456
572
  if (isSuccessfulSchemaResult(result)) {
457
- return {
573
+ const record = {
458
574
  formUuid: form.formUuid,
459
575
  formName: form.formName,
460
576
  formType: form.formType,
@@ -464,6 +580,11 @@ async function fetchSchemaRecord(appType, form, authRef, retries) {
464
580
  fieldSummary: extractFieldSummary(result),
465
581
  schema: result,
466
582
  };
583
+ const displayPage = extractDisplayPageSummary(result);
584
+ if (displayPage) {
585
+ record.displayPage = displayPage;
586
+ }
587
+ return record;
467
588
  }
468
589
  lastError = new Error(result ? result.errorMsg || t('common.unknown_error') : t('common.request_failed'));
469
590
  } catch (error) {
@@ -430,6 +430,8 @@ const COMMAND_SIDE_EFFECTS = new Map([
430
430
 
431
431
  ...sideEffectEntries([
432
432
  'add-validation',
433
+ 'app-offline',
434
+ 'app-online',
433
435
  'append-chart',
434
436
  'cdn-refresh',
435
437
  'cdn-upload',
@@ -667,6 +669,7 @@ const COMMAND_PERMISSIONS = new Map([
667
669
 
668
670
  ...permissionEntries([
669
671
  'add-validation',
672
+ 'app-online',
670
673
  'append-chart',
671
674
  'build-page',
672
675
  'cdn-config',
@@ -727,10 +730,11 @@ const COMMAND_PERMISSIONS = new Map([
727
730
  })),
728
731
 
729
732
  ...permissionEntries([
733
+ 'app-offline',
730
734
  'connector.delete',
731
735
  'connector.delete-action',
732
736
  ], permission('ask', 'destructive', {
733
- reason: 'Deletes or removes existing configuration.',
737
+ reason: 'Deletes, removes, or disables existing remote state.',
734
738
  })),
735
739
 
736
740
  ...permissionEntries([
@@ -1032,6 +1036,8 @@ const COMMAND_GROUPS = [
1032
1036
  }),
1033
1037
  command('create-app', ['create-app'], 'create-app "<name>"|--name <name> [options] [--locale zh_CN|en_US|ja_JP] [--open|--no-open]', 'help.cmd_create_app'),
1034
1038
  command('update-app', ['update-app'], 'update-app <appType> [--name "..."] [--layout slide|ver] [--theme deepBlue]', 'help.cmd_update_app'),
1039
+ command('app-online', ['app-online'], 'app-online <appType> [--to-ding-app-center] [--show-app-center]', 'help.cmd_app_online'),
1040
+ command('app-offline', ['app-offline'], 'app-offline <appType> [--to-ding-app-center] [--show-app-center]', 'help.cmd_app_offline'),
1035
1041
  command('nav-group', ['nav-group'], 'nav-group <list|create|rename|delete|move|order|auto-order|hide|show> <appType> ...', 'help.cmd_nav_group', {
1036
1042
  output: 'json',
1037
1043
  aliases: ['group'],
@@ -23,6 +23,8 @@ module.exports = {
23
23
  cmd_corp_efficiency: 'Query enterprise efficiency overview and detail reports',
24
24
  cmd_create_app: 'Create a Yida app',
25
25
  cmd_update_app: 'Update app info',
26
+ cmd_app_online: 'Enable a Yida app',
27
+ cmd_app_offline: 'Disable a Yida app',
26
28
  cmd_nav_group: 'Manage app sidebar navigation groups',
27
29
  cmd_app_permission: 'Manage app primary, data, and developer admins',
28
30
  cmd_i18n: 'Manage app multilingual copy and language config',
@@ -960,6 +962,19 @@ Examples:
960
962
  layout_notice: 'Note: layoutDirection is consumed by the Yida app shell during creation/refresh. If the top action bar does not recover immediately after a backend switch, reopen the workbench or recreate the app with the target layout.',
961
963
  },
962
964
 
965
+ app_lifecycle: {
966
+ online_usage: 'Usage: openyida app-online <appType> [--to-ding-app-center] [--show-app-center]',
967
+ online_example: 'Example: openyida app-online APP_XXX',
968
+ offline_usage: 'Usage: openyida app-offline <appType> [--to-ding-app-center] [--show-app-center]',
969
+ offline_example: 'Example: openyida app-offline APP_XXX',
970
+ missing_app_type: 'Error: missing appType argument',
971
+ invalid_argument: 'Unsupported argument: {0}',
972
+ invalid_action: 'Unsupported app lifecycle action: {0}',
973
+ request_failed: 'App lifecycle operation failed',
974
+ online_success: 'App enabled',
975
+ offline_success: 'App disabled',
976
+ },
977
+
963
978
  // ── lib/update-form-config.js ──────────────────────
964
979
  update_form_config: {
965
980
  usage: 'Usage: openyida update-form-config <appType> <formUuid> <isRenderNav> <title>',
@@ -23,6 +23,8 @@ module.exports = {
23
23
  cmd_corp_efficiency: '查询企业效能概览和明细报表',
24
24
  cmd_create_app: '创建宜搭应用',
25
25
  cmd_update_app: '更新应用信息',
26
+ cmd_app_online: '启用宜搭应用',
27
+ cmd_app_offline: '停用宜搭应用',
26
28
  cmd_nav_group: '管理应用左侧导航分组',
27
29
  cmd_app_permission: '管理应用主管理员、数据管理员和开发成员',
28
30
  cmd_i18n: '管理应用多语言文案和语言配置',
@@ -889,6 +891,19 @@ openyida - 宜搭命令行工具
889
891
  layout_notice: '提示:layoutDirection 由宜搭应用外壳在创建/刷新时消费;若后台切换后顶部操作栏未立即恢复,请重新打开工作台或使用目标 layout 重新创建应用。',
890
892
  },
891
893
 
894
+ app_lifecycle: {
895
+ online_usage: '用法: openyida app-online <appType> [--to-ding-app-center] [--show-app-center]',
896
+ online_example: '示例: openyida app-online APP_XXX',
897
+ offline_usage: '用法: openyida app-offline <appType> [--to-ding-app-center] [--show-app-center]',
898
+ offline_example: '示例: openyida app-offline APP_XXX',
899
+ missing_app_type: '错误: 缺少 appType 参数',
900
+ invalid_argument: '不支持的参数: {0}',
901
+ invalid_action: '不支持的应用生命周期操作: {0}',
902
+ request_failed: '应用生命周期操作失败',
903
+ online_success: '应用已启用',
904
+ offline_success: '应用已停用',
905
+ },
906
+
892
907
  // ── lib/process/create-process.js ─────────────────
893
908
  create_process: {
894
909
  title: '宜搭流程表单一体化创建',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openyida",
3
- "version": "2026.8.5",
3
+ "version": "2026.8.11",
4
4
  "description": "OpenYida CLI - 宜搭低代码 AI 开发工具(安装即用,零配置)",
5
5
  "bin": {
6
6
  "openyida": "bin/yida.js",
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: openyida
3
3
  description: >
4
- 宜搭应用开发总入口技能。通过具备代码生成能力的智能体(悟空/Claude/Open Code 等)+ 宜搭低代码平台,实现一句话搭建或修改完整应用。
4
+ 宜搭应用开发总入口技能。通过具备代码生成能力的智能体(千问办公/Claude/Open Code 等)+ 宜搭低代码平台,实现一句话搭建或修改完整应用。
5
5
  包含资源上下文解析、应用创建/复用、表单设计/更新、自定义页面开发、页面发布、登录态管理等完整开发流程。
6
6
  当用户提到“宜搭”、“yida”、“低代码”、“创建应用”、“创建表单”、“发布页面”、“搭建”、“系统”等关键词时,使用此技能;以下情况不要触发:只是讨论通用前端/后端代码、非宜搭平台产品、或只需要解释概念而不操作宜搭资源。
7
7
  重要路由规则:当用户首次创建完整应用/系统/平台时,如帮我搭建一个管理应用或者创建一个管理系统等,必须先加载 yida-app 子技能作为唯一编排入口,禁止直接调用 create-app/create-form/create-page 等子命令手动拼接。已有 app 且已有自定义页面的补齐或修改按常规路由即可。
@@ -9,7 +9,7 @@ description: >
9
9
 
10
10
  # 宜搭应用开发指南
11
11
 
12
- 通过具备代码生成能力的智能体(悟空/Claude/Open Code 等)+ 宜搭低代码平台,实现一句话搭建或修改完整应用。所有操作通过 **`openyida`** CLI 统一执行。登录态分流必须以 `openyida agent-capabilities --summary-json` 或 `openyida login --check-only --json` 返回的 OpenYida auth snapshot 为准;只有 snapshot 明确返回 `login.auth_source=env` 或 `failure_reason=env_token_missing` 时,才按运行环境注入 token 模式处理。其他未登录 token 场景走默认 OAuth token 登录,不要根据 agent 名称、运行环境类型或手写环境判断自行分流;禁止读取 `.cache/cookies*.json`。
12
+ 通过具备代码生成能力的智能体(千问办公/Claude/Open Code 等)+ 宜搭低代码平台,实现一句话搭建或修改完整应用。所有操作通过 **`openyida`** CLI 统一执行。登录态分流必须以 `openyida agent-capabilities --summary-json` 或 `openyida login --check-only --json` 返回的 OpenYida auth snapshot 为准;只有 snapshot 明确返回 `login.auth_source=env` 或 `failure_reason=env_token_missing` 时,才按运行环境注入 token 模式处理。其他未登录 token 场景走默认 OAuth token 登录,不要根据 agent 名称、运行环境类型或手写环境判断自行分流;禁止读取 `.cache/cookies*.json`。
13
13
 
14
14
  ---
15
15
 
@@ -165,7 +165,7 @@ OpenYida builder 默认使用 `create-app / create-form / create-page / publish`
165
165
  | 大类目录 | 第一层意图信号 | 子技能 |
166
166
  |------|------|------|
167
167
  | `yida-skills/context` | 登录、退出、切换组织、组织版本/容量、Schema、fieldId、只读预检 | `yida-login`、`yida-logout`、`yida-basic-info`、`yida-get-schema`、`yida-corp-efficiency` |
168
- | `yida-skills/app` | 从零搭应用、完整系统、应用导航、多语言 | `yida-app`、`yida-create-app`、`yida-nav-group`、`yida-i18n` |
168
+ | `yida-skills/app` | 从零搭应用、完整系统、应用启停、应用导航、多语言 | `yida-app`、`yida-create-app`、`yida-app-lifecycle`、`yida-nav-group`、`yida-i18n` |
169
169
  | `yida-skills/design` | 完整应用产品设计、单页 UI 改造、主页面视觉设计、应用主题色、全局换肤、PRD 和 design.md | `yida-design` |
170
170
  | `yida-skills/form` | 表单字段、公式、校验、业务关联规则、详情页、批量录入、数据记录 | `yida-create-form-page`、`yida-formula`、`yida-formula-evaluate`、`yida-business-rule`、`yida-form-detail`、`yida-canvas-table-form`、`yida-table-form`、`yida-data-management` |
171
171
  | `yida-skills/process` | 审批、流程表单、流程规则、节点/分支/字段权限、流程代理 | `yida-create-process`、`yida-process-rule`、`yida-agent-center` |
@@ -186,6 +186,7 @@ OpenYida builder 默认使用 `create-app / create-form / create-page / publish`
186
186
  | 用户给 taskUuid 并要求转 PRD | 先用 `yida-tingji` 读取听记内容,再把已有内容交给 `yida-flash-note-to-prd` 生成 PRD |
187
187
  | 已有会议纪要/闪记内容转 PRD | `yida-flash-note-to-prd`,只处理已有内容,不负责按 taskUuid 拉取听记 |
188
188
  | 只创建应用壳并拿 appType | `yida-create-app`;创建成功后把真实 `appType` 交给 `yida-design` 生成或更新 `prd/<项目名>/prd.md` 和 `prd/<项目名>/design.md`,后续表单、流程、页面和发布都消费这两份文件 |
189
+ | 启用/上线或停用/下线已有应用 | `yida-app-lifecycle`;只有用户明确要求时执行,`app-offline` 执行前需再次确认目标应用 |
189
190
  | 创建自定义展示页资源 | `yida-create-page`,之后默认接 `yida-canvas-custom-page` 和 `yida-publish-page` |
190
191
  | 开发表单字段结构 / 增删改字段 | 先加载 `yida-form-detail` 做表单视觉引导并合并 Divider 分割线,再用 `yida-create-form-page` 落地字段结构 |
191
192
  | 创建带审批的流程表单 | `yida-create-process` |
@@ -0,0 +1,56 @@
1
+ ---
2
+ name: yida-app-lifecycle
3
+ description: 宜搭应用启用与停用。仅当用户明确要求启用、停用、上线或下线某个已有应用时使用;不用于创建应用、发布页面或发布到钉钉应用中心。
4
+ ---
5
+
6
+ # 宜搭应用启用与停用
7
+
8
+ ## 严格要求 (MUST DO)
9
+
10
+ - 只有用户明确说“启用应用 / 上线应用 / 停用应用 / 下线应用”时,才允许调用本技能的远程写命令;不得从“发布页面”“更新应用”“应用不可用”等间接描述推断执行。
11
+ - 执行前必须确认唯一的 `appType` 和当前登录组织;目标不明确时先询问用户。
12
+ - `app-offline` 会让现有应用停止服务,执行前必须向用户展示目标 `appType` 与完整命令并获得确认。
13
+ - 默认保持 `isToDingAppCenter=n`、`showAppCenter=n`。只有用户明确要求同步钉钉应用中心或显示应用中心时,才添加对应开关。
14
+ - 命令失败后完整展示错误并停止;不得无修改连续重试,也不得改用浏览器抓包中的 Cookie、token 或 `sec-*` header 绕过认证。
15
+
16
+ ## 严格禁止 (NEVER DO)
17
+
18
+ - 不得把首次创建应用、表单/页面发布、应用信息更新自动升级为应用启用。
19
+ - 不得把“暂时隐藏页面”“禁用集成自动化”“关闭公开访问”路由为应用停用。
20
+ - 不得在测试、评测或默认 shared real E2E 中执行真实启用/停用。
21
+ - 不得把本能力扩展为钉钉应用中心完整发布流程。
22
+
23
+ ## 意图与命令
24
+
25
+ 启用或上线已有应用:
26
+
27
+ ```bash
28
+ openyida app-online <appType>
29
+ ```
30
+
31
+ 停用或下线已有应用(需确认):
32
+
33
+ ```bash
34
+ openyida app-offline <appType>
35
+ ```
36
+
37
+ 仅在用户明确要求应用中心相关行为时使用:
38
+
39
+ ```bash
40
+ openyida app-online <appType> --to-ding-app-center --show-app-center
41
+ openyida app-offline <appType> --to-ding-app-center --show-app-center
42
+ ```
43
+
44
+ ## 完成条件
45
+
46
+ - CLI 返回 `success: true`,且返回的 `action` 与用户意图一致。
47
+ - 向用户说明目标 `appType` 已启用或已停用;失败时不得宣称状态已改变。
48
+
49
+ ## 异常处理
50
+
51
+ | 异常场景 | 处理方式 |
52
+ |---------|----------|
53
+ | 缺少或存在多个 appType 候选 | 停止并要求用户确认唯一目标 |
54
+ | 登录态失效 / 组织不符 | 重新登录或切换到目标组织后再执行 |
55
+ | 权限不足 | 停止并提示使用具备应用管理权限的账号 |
56
+ | 平台返回 `success: false` 或 `content: false` | 展示 `errorMsg` / `errorCode`,不得重试或宣称成功 |
@@ -1,7 +1,7 @@
1
1
  # 素材工作流:官网 / 品牌页的真实图片如何落地
2
2
 
3
3
  > 官网、品牌首页、活动落地页需要**大 Hero 图和真实产品/场景图**才好看。但绝不能编造图片 URL。
4
- > 本文档告诉本地智能体(Claude / 悟空等):**怎么拿到真实图片、怎么校验、怎么回填进页面**,以及拿不到时怎么诚实标注草稿。
4
+ > 本文档告诉本地智能体(Claude / 千问办公等):**怎么拿到真实图片、怎么校验、怎么回填进页面**,以及拿不到时怎么诚实标注草稿。
5
5
 
6
6
  ---
7
7
 
@@ -102,6 +102,40 @@
102
102
  "应用权限"
103
103
  ]
104
104
  },
105
+ {
106
+ "name": "yida-app-lifecycle",
107
+ "path": "skills/yida-app-lifecycle/SKILL.md",
108
+ "display_name": "应用启用与停用",
109
+ "description": "宜搭应用启用与停用。仅当用户明确要求启用、停用、上线或下线某个已有应用时使用;不用于创建应用、发布页面或发布到钉钉应用中心。",
110
+ "category": "yida-skills/app",
111
+ "tags": [
112
+ "启用应用",
113
+ "停用应用",
114
+ "上线应用",
115
+ "下线应用"
116
+ ],
117
+ "aliases": [
118
+ "应用生命周期",
119
+ "应用上下线"
120
+ ],
121
+ "positive_signals": [
122
+ "启用应用",
123
+ "停用应用",
124
+ "上线应用",
125
+ "下线应用"
126
+ ],
127
+ "negative_signals": [
128
+ "发布页面",
129
+ "更新应用信息",
130
+ "禁用集成自动化",
131
+ "关闭公开访问"
132
+ ],
133
+ "command_ids": [
134
+ "app-online",
135
+ "app-offline"
136
+ ],
137
+ "done_when": "CLI 返回 success:true 且 action 与用户明确意图一致;app-offline 执行前已确认目标 appType,失败时不得宣称状态改变。"
138
+ },
105
139
  {
106
140
  "name": "yida-basic-info",
107
141
  "path": "skills/yida-basic-info/SKILL.md",
@@ -1160,6 +1194,10 @@
1160
1194
  "创建应用",
1161
1195
  "完整应用",
1162
1196
  "管理系统",
1197
+ "启用应用",
1198
+ "停用应用",
1199
+ "上线应用",
1200
+ "下线应用",
1163
1201
  "导航分组",
1164
1202
  "多语言"
1165
1203
  ]