openyida 2026.10.20 → 2026.10.21-2

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 (53) hide show
  1. package/README.md +5 -2
  2. package/bin/yida.js +9 -0
  3. package/lib/app/agent-app-type.js +12 -0
  4. package/lib/app/cool-card.js +5 -0
  5. package/lib/app/upgrade-app-theme.js +2 -1
  6. package/lib/core/command-manifest.js +19 -8
  7. package/lib/core/locales/en.js +28 -2
  8. package/lib/core/locales/zh.js +28 -2
  9. package/lib/core/query-data.js +40 -2
  10. package/lib/core/sample.js +1 -0
  11. package/lib/core/task-center.js +3 -1
  12. package/lib/core/update.js +1 -1
  13. package/lib/feedback/feedback.js +1 -0
  14. package/lib/feedback/github.js +130 -0
  15. package/lib/integration/integration-triggers.js +8 -3
  16. package/lib/print-template/builder.js +232 -0
  17. package/lib/print-template/codes.js +46 -0
  18. package/lib/print-template/contract.js +31 -0
  19. package/lib/print-template/detail.js +36 -0
  20. package/lib/print-template/model.js +97 -0
  21. package/lib/print-template/print-template.js +302 -0
  22. package/lib/print-template/scenes.js +29 -0
  23. package/lib/process/configure-process.js +8 -2
  24. package/lib/process/process-tasks.js +175 -0
  25. package/lib/process/services/process-actor-config.js +3 -0
  26. package/lib/process/services/process-compiler.js +15 -0
  27. package/lib/process/services/process-dynamic-actors.js +165 -0
  28. package/lib/samples/yida-print-template/approval.json +14 -0
  29. package/lib/samples/yida-print-template/codes.json +12 -0
  30. package/lib/samples/yida-print-template/delivery.json +14 -0
  31. package/lib/samples/yida-print-template/order.json +14 -0
  32. package/lib/samples/yida-print-template/quotation.json +13 -0
  33. package/lib/samples/yida-print-template/receipt.json +13 -0
  34. package/lib/task-center/lookups.js +11 -4
  35. package/package.json +1 -1
  36. package/scripts/postinstall.js +1 -0
  37. package/yida-skills/SKILL.md +4 -2
  38. package/yida-skills/skills/yida-cool-card/SKILL.md +3 -1
  39. package/yida-skills/skills/yida-data-management/SKILL.md +24 -3
  40. package/yida-skills/skills/yida-data-management/references/process-task-transfer.md +53 -0
  41. package/yida-skills/skills/yida-feedback/SKILL.md +1 -1
  42. package/yida-skills/skills/yida-feedback/references/github-contribution.md +19 -2
  43. package/yida-skills/skills/yida-flow-node-config/SKILL.md +1 -1
  44. package/yida-skills/skills/yida-flow-node-config/references/actors.md +4 -0
  45. package/yida-skills/skills/yida-flow-node-config/references/dynamic-actors.md +84 -0
  46. package/yida-skills/skills/yida-integration/SKILL.md +1 -0
  47. package/yida-skills/skills/yida-integration/references/triggers.md +14 -1
  48. package/yida-skills/skills/yida-print-template/SKILL.md +134 -0
  49. package/yida-skills/skills/yida-print-template/references/detail.md +40 -0
  50. package/yida-skills/skills/yida-print-template/references/guide.md +35 -0
  51. package/yida-skills/skills/yida-print-template/references/scenarios.md +72 -0
  52. package/yida-skills/skills/yida-task-center/references/task-filters.md +2 -0
  53. package/yida-skills/skills-index.json +27 -5
package/README.md CHANGED
@@ -446,6 +446,8 @@ openyida feedback report --input summary.json --output-dir feedback-draft-001
446
446
 
447
447
  Your AI prepares the summary from observed evidence and selected reproduction screenshots. PRs include before/after test comparisons. Before anything is published, review the final text and images, confirm sensitive information, and remove anything you do not want to share. See the [report input format](yida-skills/skills/yida-feedback/references/report-input.md). Review business information before sharing. With a GitHub account, authorize your AI to submit an Issue or contribute a verified public OpenYida fix through your personal Fork. Without an account, create a GitHub account first. If that is not possible, share the report in the AI开发者群 (AI developer group).
448
448
 
449
+ When you choose to submit an OpenYida Issue, the feedback Skill can check your signed-in GitHub account with `openyida feedback github status --json`. Star and a personal Fork are optional: `feedback github star --confirm` and `feedback github fork --confirm` run only after you choose them. Existing actions are reused. This check is separate from installation and automatic updates; neither action is required to submit an Issue.
450
+
449
451
  <!-- OPENYIDA_COMMANDS_START -->
450
452
  <!-- This section is generated by `npm run docs:commands`. Do not edit command rows by hand. -->
451
453
 
@@ -509,6 +511,7 @@ Your AI prepares the summary from observed evidence and selected reproduction sc
509
511
  | `openyida create-form add-option <appType> <formUuid> <fieldLabel> <option1> [option2] ...` | Update a form page |
510
512
  | `openyida list-forms <appType> [--keyword <text>]` | List forms/pages in an app |
511
513
  | `openyida aggregate-table <list\|create-empty\|inspect\|preview\|save\|publish\|status> <appType> ...` | Manage aggregate tables (virtualView) |
514
+ | `openyida print-template <list\|inspect\|fields\|build\|create\|copy\|save\|restore\|settings\|status\|order\|render\|files> <appType> <formUuid> [templateId] [--config <file>] [--scene <order\|quotation\|delivery\|receipt\|approval\|codes>] [--bindings <file>] [--name <title>] [--expected-hash <hash>] [--backup <file>] [--out <file>] [--status START\|STOP] [--instance <id>] [--page <n>] [--size <n>] [--allow-permission-change] [--json] \| print-template <list\|render> --detail-url <url> [--template-id <id>] [--json]` | Manage native YiDA print templates, generate document layouts, back up, restore and request PDFs |
512
515
  | `openyida form-view <list\|inspect\|save\|create\|order> <appType> <formUuid> [viewUuid] [--config <file>] [--name <title>] [--with-config] [--expected-hash <hash>] [--backup <file>] [--replace] [--json]` | Native form views: list, inspect and configure columns, widths, frozen columns and filters |
513
516
  | `openyida custom-button <list\|inspect\|options\|create\|update\|delete> <appType> <formUuid> [buttonUuid] [--config <file>] [--expected-hash <hash>] [--backup <file>] [--yes] [--json]` | Native custom buttons: inspect and configure form edits, automation flows and page links |
514
517
  | `openyida get-schema <appType> <formUuid\|--all> [--summary-json\|--field-map-json\|--analysis-json]` | Get one form Schema or all form Schemas |
@@ -527,7 +530,7 @@ Your AI prepares the summary from observed evidence and selected reproduction sc
527
530
 
528
531
  | Command | Description |
529
532
  |---------|-------------|
530
- | `openyida data <query\|get\|create\|update> <resource> ... \| delete form <appType> <formUuid> --inst-id <id> --expect-form-name <name> --expect-form-type receipt --confirm [--json]` | Unified data management (form/process/task/subform) |
533
+ | `openyida data <query\|get\|create\|update\|transfer> <resource> ... \| delete form <appType> <formUuid> --inst-id <id> --expect-form-name <name> --expect-form-type receipt --confirm [--json]` | Unified data management (form/process/task/subform) |
531
534
  | `openyida task-center <todo\|created\|done\|cc\|proxy\|capabilities\|scaffold\|options\|inspect\|count> [--spec <file.json> --output <file.canvas.jsx>] [options]` | Global task center (todo/processed/cc etc.) |
532
535
  | `openyida basic-info <overview\|commodity\|grant\|capacity\|quota\|abs-path\|dataflow\|i18n\|domain>` | Query organization basic info, capacity, quotas, and domain settings |
533
536
  | `openyida read-dingtalk-doc <docUrl> [--output <file>] [--json]` | Fetch Markdown content from a DingTalk document |
@@ -628,7 +631,7 @@ Your AI prepares the summary from observed evidence and selected reproduction sc
628
631
  | `openyida formula test <appType> <formUuid> [formula\|file] [--data-file file \| --cases file] [--field fieldId] [--timezone-offset minutes] [--context form\|validation] [--binding platform\|numeric-literals] [--expect JSON] [--json]` | Evaluate a non-writing formula in Yida and compare its result |
629
632
  | `openyida update` | Check and update to latest version |
630
633
  | `openyida export-conversation [options]` | Export AI conversation records |
631
- | `openyida feedback <report\|setup\|url\|dismiss\|status> [options]` | Prepare local issue reports, configure feedback forms and reminders |
634
+ | `openyida feedback <report\|github\|setup\|url\|dismiss\|status> [options]` | Prepare local issue reports, configure feedback forms and reminders |
632
635
  | `openyida batch <file>\|--commands "cmd1 ; cmd2" [--stop-on-error] [--json]` | Run OpenYida commands in batch |
633
636
  | `openyida flash-to-prd --file <path> --name "<project>"` | Convert flash notes or meeting notes to a PRD prompt |
634
637
  | `openyida ai <text\|image> [options]` | Call Yida AI text and image recognition APIs |
package/bin/yida.js CHANGED
@@ -837,6 +837,11 @@ async function main() {
837
837
  await run(args);
838
838
  break;
839
839
  }
840
+ case 'print-template': {
841
+ const { run } = require('../lib/print-template/print-template');
842
+ await run(args);
843
+ break;
844
+ }
840
845
  case 'form-view': {
841
846
  const { run } = require('../lib/app/form-view');
842
847
  await run(args);
@@ -1333,6 +1338,10 @@ async function main() {
1333
1338
  }
1334
1339
 
1335
1340
  case 'feedback': {
1341
+ if (args[0] === 'github') {
1342
+ await require('../lib/feedback/github').run(args.slice(1));
1343
+ break;
1344
+ }
1336
1345
  const { run: runFeedback } = require('../lib/feedback/feedback');
1337
1346
  await runFeedback(args);
1338
1347
  break;
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+
3
+ // Server-derived provenance: channels may grow; only absence or "none" means non-AI.
4
+ function isAgentAppType(value) {
5
+ if (typeof value !== 'string') {
6
+ return false;
7
+ }
8
+ const type = value.trim().toLowerCase();
9
+ return type !== '' && type !== 'none';
10
+ }
11
+
12
+ module.exports = { isAgentAppType };
@@ -6,6 +6,7 @@ const crypto = require('crypto');
6
6
  const { CliError } = require('../core/cli-error');
7
7
  const { t } = require('../core/i18n');
8
8
  const { createAuthRef, createYidaClient } = require('../core/yida-client');
9
+ const { inferEnvironmentNameFromUrl } = require('../core/env-manager');
9
10
  const { buildApplicationSettingsUrls } = require('./application-entry-urls');
10
11
 
11
12
  const object = value => value !== null && typeof value === 'object' && !Array.isArray(value);
@@ -124,6 +125,10 @@ async function execute(parsed, client) {
124
125
  let { cardPageCode } = checked;
125
126
  if (flags['--out'] && fs.existsSync(path.resolve(flags['--out']))) { fail('OUTPUT_EXISTS', flags['--out']); }
126
127
  client = client || createYidaClient({ authRef: createAuthRef() });
128
+ // Use the authenticated target, not a global environment preference, before creating any resource.
129
+ if (action === 'create' && inferEnvironmentNameFromUrl(client.getAuthRef().baseUrl) === 'alibaba') {
130
+ fail('UNSUPPORTED_ENVIRONMENT', t('cool_card.unsupported_environment'), { environment: 'alibaba' });
131
+ }
127
132
  const prefix = `/${appType}/query/cardDesign/`;
128
133
  const get = async (name, params) => unwrap(await client.get(prefix + name + '.json', params), name);
129
134
  const base = { success: true, action, appType, resourceType: 'native-cool-card', capabilities };
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const querystring = require('querystring');
4
+ const { isAgentAppType } = require('./agent-app-type');
4
5
  const { httpGet, httpPost, requestWithAutoLogin } = require('../core/utils');
5
6
  const { createAuthRef } = require('../core/yida-client');
6
7
  const { throwCommandError, throwUsage } = require('../core/command-errors');
@@ -64,7 +65,7 @@ async function readThemeEligibility(appType, auth) {
64
65
  }
65
66
  // agentAppType is derived by Tianshu from FROM_BUILDER_AI and BUILDER_AI_SOURCE.
66
67
  // aiApp/FROM_AI is a separate feature flag and must not be used as provenance.
67
- if (!['local', 'cloud', 'qwenwork'].includes(context.agentAppType.trim().toLowerCase())) {
68
+ if (!isAgentAppType(context.agentAppType)) {
68
69
  throwCommandError(t('upgrade_app_theme.ai_only'), { code: 'APP_THEME_AI_APP_REQUIRED' });
69
70
  }
70
71
  return context;
@@ -8,6 +8,7 @@ const { getPageNavigationContract } = require('../design-plan/navigation-policy'
8
8
  const { ENTRY_MODES } = require('../design-plan/entry-navigation');
9
9
  const { DIVIDER_TYPES, DEFAULT_DIVIDER_TYPE } = require('../app/form-field-validator');
10
10
  const { FORMULA_COMMANDS } = require('../formula/cli-contract');
11
+ const { printTemplateCommand, printTemplateEffects, printTemplatePermission } = require('../print-template/contract');
11
12
 
12
13
  const SIDE_EFFECT_BASES = Object.freeze({
13
14
  local_read: Object.freeze({
@@ -550,6 +551,7 @@ const COMMAND_SIDE_EFFECTS = new Map([
550
551
  })],
551
552
  ['cool-card', sideEffect('mixed', { mutates_yida: true, mutates_local: true, read_actions: ['list', 'templates', 'get'], mutating_actions: ['create'] })],
552
553
  ['data-card', sideEffect('mixed', { mutates_yida: true, mutates_local: true, read_actions: ['list', 'get', 'probe', 'release-check', 'refs'], mutating_actions: ['create', 'save', 'publish', 'release-get', 'release-save', 'release-test'], note: 'release-get reads broadcast settings but the native backend may initialize the application cool app; classify it conservatively as a possible mutation.' })],
554
+ ['print-template', sideEffect('mixed', printTemplateEffects)],
553
555
  ['form-view', sideEffect('mixed', {
554
556
  mutates_yida: true,
555
557
  mutates_local: true,
@@ -610,7 +612,7 @@ const COMMAND_SIDE_EFFECTS = new Map([
610
612
  mutates_yida: true,
611
613
  mutates_local: false,
612
614
  read_actions: ['query', 'get'],
613
- mutating_actions: ['create', 'update', 'delete'],
615
+ mutating_actions: ['create', 'update', 'delete', 'transfer'],
614
616
  })],
615
617
  ['db-seq-fix', sideEffect('mixed', {
616
618
  mutates_yida: true,
@@ -645,8 +647,8 @@ const COMMAND_SIDE_EFFECTS = new Map([
645
647
  ['feedback', sideEffect('mixed', {
646
648
  mutates_yida: true,
647
649
  mutates_local: true,
648
- read_actions: ['url', 'status'],
649
- mutating_actions: ['setup', 'dismiss', 'report'],
650
+ read_actions: ['url', 'status', 'github status'],
651
+ mutating_actions: ['setup', 'dismiss', 'report', 'github star', 'github fork'],
650
652
  })],
651
653
  ['i18n', sideEffect('mixed', {
652
654
  mutates_yida: true,
@@ -845,6 +847,7 @@ const COMMAND_PERMISSIONS = new Map([
845
847
  ask_actions: ['connect', 'run', 'disconnect', 'logout'],
846
848
  })),
847
849
 
850
+ ...permissionEntries(['print-template'], actionDependentPermission(printTemplatePermission)),
848
851
  ...permissionEntries(['cool-card'], actionDependentPermission({ preauthorized_actions: ['create'] })),
849
852
  ...permissionEntries(['data-card'], actionDependentPermission({ preauthorized_actions: ['create', 'save', 'publish', 'release-get'], ask_actions: ['release-save', 'release-test'] })),
850
853
  ...permissionEntries([
@@ -947,7 +950,7 @@ const COMMAND_PERMISSIONS = new Map([
947
950
  ...permissionEntries([
948
951
  'data',
949
952
  ], actionDependentPermission({
950
- preauthorized_actions: ['create', 'update'],
953
+ preauthorized_actions: ['create', 'update', 'transfer'],
951
954
  ask_actions: ['delete'],
952
955
  })),
953
956
 
@@ -1383,7 +1386,7 @@ const COMMAND_GROUPS = [
1383
1386
  { name: 'json', type: 'boolean', source: 'option', builder_options: ['--json'] },
1384
1387
  { name: 'confirm', type: 'boolean', source: 'option', builder_options: ['--confirm'] },
1385
1388
  ],
1386
- notes: ['--prepare reads remote schemas/source bundles into a new local backup directory and produces a per-resource migration plan without remote writes; it requires explicit upgrade intent but no mutation confirmation. Before --confirm, use the independent upgrade Skill to prepare/review sources, migrate legacy JSX to Canvas without business/layout changes, and remove verified form-detail style injection. Only mutate after an explicit user request to upgrade an existing app to the modern theme AND an affirmative ask_human reply for that app. These flags attest to both checks; they do not replace human confirmation. If ask_human is unavailable, stop before mutation. The CLI itself checks server-derived agentAppType and app/corp identity before offering any confirmation or preparing backups. agentAppType comes from FROM_BUILDER_AI=y plus BUILDER_AI_SOURCE; source alone or FROM_AI does not qualify. Only local/cloud/qwenwork qualifies. Reject non-AI or unverified apps without offering an upgrade or exposing source fields. Skill guidance and confirmation flags cannot bypass this gate. Do not check V4, appThemeEnable, organization theme gray or upgrade gray. After ask_human approval, migrate legacy navigation layout and colors before persisting CREATED_WITH_MODERN_THEME=y and APP_THEME_MODE=modern, then read all changed settings back. Already modern navigation colors stay unchanged. Report partial/unknown writes on failure. Success verifies configuration only, not page migration or runtime rendering. appUpgradeComplete remains false until the Skill verifies all page/form migrations.'],
1389
+ notes: ['--prepare reads remote schemas/source bundles into a new local backup directory and produces a per-resource migration plan without remote writes; it requires explicit upgrade intent but no mutation confirmation. Before --confirm, use the independent upgrade Skill to prepare/review sources, migrate legacy JSX to Canvas without business/layout changes, and remove verified form-detail style injection. Only mutate after an explicit user request to upgrade an existing app to the modern theme AND an affirmative ask_human reply for that app. These flags attest to both checks; they do not replace human confirmation. If ask_human is unavailable, stop before mutation. The CLI itself checks server-derived agentAppType and app/corp identity before offering any confirmation or preparing backups. agentAppType comes from FROM_BUILDER_AI=y plus BUILDER_AI_SOURCE; source alone or FROM_AI does not qualify. Use the centralized server-derived AI application type check (including web_local). Reject non-AI or unverified apps without offering an upgrade or exposing source fields. Skill guidance and confirmation flags cannot bypass this gate. Do not check V4, appThemeEnable, organization theme gray or upgrade gray. After ask_human approval, migrate legacy navigation layout and colors before persisting CREATED_WITH_MODERN_THEME=y and APP_THEME_MODE=modern, then read all changed settings back. Already modern navigation colors stay unchanged. Report partial/unknown writes on failure. Success verifies configuration only, not page migration or runtime rendering. appUpgradeComplete remains false until the Skill verifies all page/form migrations.'],
1387
1390
  }),
1388
1391
  command('app-online', ['app-online'], 'app-online <appType> [--to-ding-app-center] [--show-app-center]', 'help.cmd_app_online', { managedRun: {'scope':'denied','reason':'scope_not_audited'} }),
1389
1392
  command('app-offline', ['app-offline'], 'app-offline <appType> [--to-ding-app-center] [--show-app-center]', 'help.cmd_app_offline', { managedRun: {'scope':'denied','reason':'scope_not_audited'} }),
@@ -1609,6 +1612,7 @@ const COMMAND_GROUPS = [
1609
1612
  },
1610
1613
  output: 'json',
1611
1614
  }),
1615
+ command(...printTemplateCommand),
1612
1616
  command('form-view', ['form-view'], 'form-view <list|inspect|save|create|order> <appType> <formUuid> [viewUuid] [--config <file>] [--name <title>] [--with-config] [--expected-hash <hash>] [--backup <file>] [--replace] [--json]', 'help.cmd_form_view', {
1613
1617
  managedRun: { scope: 'actions', actions: {
1614
1618
  list: { scope: 'app', appPosition: 1 },
@@ -1744,12 +1748,13 @@ const COMMAND_GROUPS = [
1744
1748
  id: 'data',
1745
1749
  titleKey: 'help.group_data',
1746
1750
  commands: [
1747
- command('data', ['data'], 'data <query|get|create|update> <resource> ... | delete form <appType> <formUuid> --inst-id <id> --expect-form-name <name> --expect-form-type receipt --confirm [--json]', 'help.cmd_data', {
1751
+ command('data', ['data'], 'data <query|get|create|update|transfer> <resource> ... | delete form <appType> <formUuid> --inst-id <id> --expect-form-name <name> --expect-form-type receipt --confirm [--json]', 'help.cmd_data', {
1748
1752
  managedRun: { scope: 'actions', actions: {
1749
1753
  query: { scope: 'actions', actions: {
1750
1754
  form: { scope: 'app', appPosition: 2 }, subform: { scope: 'app', appPosition: 2 },
1751
1755
  process: { scope: 'app', appPosition: 2 }, 'operation-records': { scope: 'app', appPosition: 2 },
1752
1756
  tasks: { scope: 'app', appPosition: 2 },
1757
+ 'process-tasks': { scope: 'app', appPosition: 2 },
1753
1758
  } },
1754
1759
  get: { scope: 'actions', actions: {
1755
1760
  form: { scope: 'app', appPosition: 2 }, subform: { scope: 'app', appPosition: 2 },
@@ -1769,6 +1774,9 @@ const COMMAND_GROUPS = [
1769
1774
  execute: { scope: 'actions', actions: {
1770
1775
  task: { scope: 'app', appPosition: 2, mutation: { operation: 'execute_task', formUuidOption: '--form-uuid' } },
1771
1776
  } },
1777
+ transfer: { scope: 'actions', actions: {
1778
+ task: { scope: 'app', appPosition: 2, mutation: { operation: 'execute_task', formUuidOption: '--form-uuid' } },
1779
+ } },
1772
1780
  } },
1773
1781
  output: 'json',
1774
1782
  noteKeys: ['help.data_notes', 'query_data.approver_query_help'],
@@ -1783,6 +1791,8 @@ const COMMAND_GROUPS = [
1783
1791
  'openyida data query form APP_XXX FORM_XXX --page 1 --size 20 --search-json \'[{"key":"dateField_due","componentName":"DateField","type":"DOUBLE","operator":"is","value":""}]\'',
1784
1792
  'openyida data create form APP_XXX FORM_XXX --expect-form-name 客户 --expect-form-type receipt --data-json \'{"textField_name":"客户 A","dateField_followUp":1787932800000}\'',
1785
1793
  'openyida data delete form APP_XXX FORM_XXX --inst-id FINST_XXX --expect-form-name 客户 --expect-form-type receipt --confirm --json',
1794
+ 'openyida data query process-tasks APP_XXX --process-inst-id PINST_XXX --json',
1795
+ 'openyida data transfer task APP_XXX --process-inst-id PINST_XXX --form-uuid FORM_XXX --to-user-id USER_ID --expect-form-name "Approval form" --expect-form-type process --json',
1786
1796
  ],
1787
1797
  }),
1788
1798
  command('task-center', ['task-center'], 'task-center <todo|created|done|cc|proxy|capabilities|scaffold|options|inspect|count> [--spec <file.json> --output <file.canvas.jsx>] [options]', 'help.cmd_task_center', {
@@ -2047,11 +2057,12 @@ const COMMAND_GROUPS = [
2047
2057
  command('export-conversation', ['export-conversation'], 'export-conversation [options]', 'help.cmd_export_conversation', { managedRun: { scope: 'denied', reason: 'scope_not_audited' },
2048
2058
  requiresLogin: false,
2049
2059
  }),
2050
- command('feedback', ['feedback'], 'feedback <report|setup|url|dismiss|status> [options]', 'help.cmd_feedback', { managedRun: { scope: 'actions', actions: { report: { scope: 'local' } } },
2060
+ command('feedback', ['feedback'], 'feedback <report|github|setup|url|dismiss|status> [options]', 'help.cmd_feedback', { managedRun: { scope: 'actions', actions: { report: { scope: 'local' } } },
2061
+ permission: actionDependentPermission({ preauthorized_actions: ['report', 'url', 'status', 'dismiss', 'github status'], ask_actions: ['setup', 'github star', 'github fork'] }),
2051
2062
  requiresLogin: false,
2052
2063
  output: 'text|json',
2053
2064
  examples: ['openyida feedback report --input summary.json --output-dir feedback-draft-001'],
2054
- notes: ['report prepares local review drafts only; no login, source checkout, update check or network submission.'],
2065
+ notes: ['report prepares local review drafts only; no login, source checkout, update check or network submission. github status [--json] checks the authenticated github.com user, Star and personal Fork through an existing gh installation; it performs no writes. github star|fork --confirm [--json] requires the user to explicitly choose that account action. Missing gh/login, unknown status and declined actions never block Issue submission. Already applied actions are reused; writes are single-attempt with readback. No auto-update/install hook, Issue submission, clone or git remote modification. Managed runs permit only offline report preparation.'],
2055
2066
  }),
2056
2067
  command('batch', ['batch'], 'batch <file>|--commands "cmd1 ; cmd2" [--stop-on-error] [--json]', 'help.cmd_batch', { managedRun: { scope: 'denied', reason: 'scope_not_audited' },
2057
2068
  output: 'text|json',
@@ -4,6 +4,11 @@
4
4
  'use strict';
5
5
 
6
6
  module.exports = {
7
+ print_template: {
8
+ 'description': 'Manage native YiDA print templates, generate document layouts, back up, restore and request PDFs',
9
+ 'error': 'Print template operation failed: {0}',
10
+ 'usage': 'Usage: openyida print-template <list|inspect|fields|build|create|copy|save|restore|settings|status|order|render|files> <appType> <formUuid> [templateId]. Use --config <file>, build --scene order|quotation|delivery|receipt|approval|codes --bindings <file>, create --config <file>, --name <title>, --expected-hash <inspect-hash>, --backup <file>, --out <file>, --status START|STOP, --instance <id>, --page <n>, --size <n>, --allow-permission-change, --json as documented. For native record links: list|render --detail-url <url> [--template-id <id>].'
11
+ },
7
12
  custom_button: {
8
13
  'usage': 'Usage: openyida custom-button <list|inspect|options|create|update|delete> <appType> <formUuid> [buttonUuid] [--config <file>] [--expected-hash <hash>] [--backup <file>] [--yes] [--json]',
9
14
  'invalid_config': 'Invalid configuration or argument: {0}',
@@ -15,7 +20,7 @@ module.exports = {
15
20
  'readback_mismatch': 'Saved custom button does not match readback. Keep the backup and inspect remote state.'
16
21
  },
17
22
  dws_external: {'note': 'dws is an independent external tool. OpenYida only shows installation instructions; it does not download or install it.', 'install_guide': 'Show official DingTalk CLI installation instructions'},
18
- cool_card: {'description': 'Create and read native YiDA cool cards (interactive and pinned)', 'usage': 'Usage: openyida cool-card <list|templates|create|get> <appType> [cardPageCode] [--type im|onebox] [--name <title>] [--page <n>] [--size <n>] [--search <text>] [--out <file>] [--json]', 'failed': 'Native cool card operation stopped: {0}'},
23
+ cool_card: {'unsupported_environment': 'The Alibaba Group edition does not support building cool cards.', 'description': 'Create and read native YiDA cool cards (interactive and pinned)', 'usage': 'Usage: openyida cool-card <list|templates|create|get> <appType> [cardPageCode] [--type im|onebox] [--name <title>] [--page <n>] [--size <n>] [--search <text>] [--out <file>] [--json]', 'failed': 'Native cool card operation stopped: {0}'},
19
24
  data_card: {'description':'Create, configure, publish and distribute native YiDA data cards','usage':'Usage: openyida data-card <list|create|get|save|publish|probe|release-get|release-save|release-check|release-test|refs> <appType> [cardCode] [--name <title>] [--description <text>] [--schema <file>|--config <file>] [--expected-hash <hash>] [--backup <file>] [--out <file>] [--published|--version <version>] [--page <n>] [--size <n>] [--search <text>] [--allow-send] [--json]','failed':'Native data card operation stopped: {0}','conflict':'The draft changed. Read it again before saving or publishing.','mismatch':'Readback does not match the expected schema or published state. Keep the backup and inspect the card before retrying.'},
20
25
  app_settings: {'description':'Read theme, frontend/backend, native data card and cool card management links','usage':'Usage: openyida app-settings <appType> [--section theme|basic|data-card|cool-card] [--json]','failed':'Application settings could not be read: {0}'},
21
26
  form_view: {
@@ -34,7 +39,10 @@ module.exports = {
34
39
  integration_update_v2: {'usage': 'integration update <appType> <formUuid> <processCode> --patch patch.json [--dry-run] [--expect fingerprint] [--publish]'},
35
40
 
36
41
  conditional_actors: { unavailable: 'Conditional actors are unavailable or could not be verified.', invalid: 'Invalid conditional actors: {0}' },
37
- integration_triggers: { invalid: 'Invalid automation trigger: {0}' },
42
+ integration_triggers: {
43
+ invalid: 'Invalid automation trigger: {0}',
44
+ end_required: 'Choose the timer end condition: set schedule.maxCount (1–100) for a run count or schedule.expireDate (expiry in milliseconds) for a specified time. For long-running schedules, choose a distant expiry and show the actual date in the configuration summary.',
45
+ },
38
46
  permission_conditions: { invalid: 'Invalid permission conditions: {0}' },
39
47
  agent: {
40
48
  preflight_cli_detected: 'CLI detected; runtime will discover and report login, protocol and model status.',
@@ -2326,6 +2334,16 @@ module.exports.app_theme = {
2326
2334
  module.exports.help.cmd_app_theme_snapshot = 'Archive application theme settings and CSS (read-only)';
2327
2335
  module.exports.help.cmd_app_theme_restore = 'Check or restore an application theme snapshot (supported exact values only)';
2328
2336
 
2337
+ Object.assign(module.exports.process_tasks || (module.exports.process_tasks = {}), {
2338
+ arguments_invalid: 'Invalid arguments: query requires appType and --process-inst-id; transfer also requires --form-uuid, --to-user-id, --expect-form-name and --expect-form-type process. taskId must be a positive integer; unknown options are not supported.',
2339
+ query_failed: 'Process task query failed; no transfer was performed.',
2340
+ response_invalid: 'The task response structure, task ID or process ownership could not be verified.',
2341
+ not_running: 'The specified task is not running in the target process, or no running task exists; no transfer was performed.',
2342
+ ambiguous: 'Multiple running tasks exist. Query the task list and specify --task-id; no transfer was performed.',
2343
+ rejected: 'The platform rejected the administrator transfer. Check permissions and task status.',
2344
+ result_unknown: 'The administrator transfer result is unknown. Use nextStep to read the tasks; do not automatically retry the transfer.',
2345
+ unverified: 'The transfer was accepted, but readback could not verify the recipient. Use nextStep to read the tasks; do not automatically retry the transfer.',
2346
+ });
2329
2347
  module.exports.data_manage_style = {
2330
2348
  'usage': 'openyida data-manage-style guide [--json]\nopenyida data-manage-style list [--json]\nopenyida data-manage-style generate --app APP_ID --form FORM-ID --style <id> --base-css <snapshot/theme.css> --output <new.css> [--focus balanced|actions] [--field-id <actualId>]... [--emphasize-field <actualId>]... [--tag-field <selectFieldId>]... [--follow-shell] [--json]',
2331
2349
  'data_style_invalid': 'Invalid style parameters; use actual app/form/field IDs and a style returned by list.',
@@ -2507,3 +2525,11 @@ module.exports.task_center = {
2507
2525
  'filter_carbonCreateFrom': 'Copied from',
2508
2526
  'filter_carbonCreateTo': 'Copied to'
2509
2527
  };
2528
+
2529
+ module.exports.feedback_github = {
2530
+ usage: 'Usage: openyida feedback github <status|star|fork> [--confirm] [--json]',
2531
+ confirmation: 'Star or Fork requires the user to explicitly choose that action before --confirm. Neither is required to submit an Issue.',
2532
+ failed: 'The GitHub action could not be verified. Inspect its status before retrying; this does not block Issue submission.',
2533
+ };
2534
+
2535
+ module.exports.process_dynamic_actors = { invalid: 'Invalid process actor configuration. Check details.reason, selection range and actual member fields.' };
@@ -4,6 +4,11 @@
4
4
  'use strict';
5
5
 
6
6
  module.exports = {
7
+ print_template: {
8
+ 'description': '管理宜搭原生打印模板、按字段生成多种单据、备份恢复与生成PDF',
9
+ 'error': '打印模板操作失败:{0}',
10
+ 'usage': 'Usage: openyida print-template <list|inspect|fields|build|create|copy|save|restore|settings|status|order|render|files> <appType> <formUuid> [templateId]. Use --config <file>, build --scene order|quotation|delivery|receipt|approval|codes --bindings <file>, create --config <file>, --name <title>, --expected-hash <inspect-hash>, --backup <file>, --out <file>, --status START|STOP, --instance <id>, --page <n>, --size <n>, --allow-permission-change, --json as documented. For native record links: list|render --detail-url <url> [--template-id <id>].'
11
+ },
7
12
  custom_button: {
8
13
  'usage': '用法:openyida custom-button <list|inspect|options|create|update|delete> <appType> <formUuid> [buttonUuid] [--config <file>] [--expected-hash <hash>] [--backup <file>] [--yes] [--json]',
9
14
  'invalid_config': '配置或参数无效:{0}',
@@ -15,7 +20,7 @@ module.exports = {
15
20
  'readback_mismatch': '保存后的配置与回读不一致,请保留备份并检查远端状态。'
16
21
  },
17
22
  dws_external: {'note': 'dws 是独立的外部工具;OpenYida 仅提供安装指引,不下载或安装它。', 'install_guide': '显示钉钉 CLI 官方安装指引'},
18
- cool_card: {'description': '创建和读取宜搭原生酷卡片(交互卡片与置顶卡片)', 'usage': '用法: openyida cool-card <list|templates|create|get> <appType> [cardPageCode] [--type im|onebox] [--name <title>] [--page <n>] [--size <n>] [--search <text>] [--out <file>] [--json]', 'failed': '原生酷卡片操作已停止:{0}'},
23
+ cool_card: {'unsupported_environment': '集团版不支持酷卡片搭建。', 'description': '创建和读取宜搭原生酷卡片(交互卡片与置顶卡片)', 'usage': '用法: openyida cool-card <list|templates|create|get> <appType> [cardPageCode] [--type im|onebox] [--name <title>] [--page <n>] [--size <n>] [--search <text>] [--out <file>] [--json]', 'failed': '原生酷卡片操作已停止:{0}'},
19
24
  data_card: {'description':'创建、配置、发布原生数据卡片并管理投放播报','usage':'用法: openyida data-card <list|create|get|save|publish|probe|release-get|release-save|release-check|release-test|refs> <appType> [cardCode] [--name <title>] [--description <text>] [--schema <file>|--config <file>] [--expected-hash <hash>] [--backup <file>] [--out <file>] [--published|--version <version>] [--page <n>] [--size <n>] [--search <text>] [--allow-send] [--json]','failed':'原生数据卡片操作已停止:{0}','conflict':'卡片草稿已发生变化,请重新读取后再保存或发布。','mismatch':'回读配置或发布状态与预期不一致,请保留备份并检查卡片后再重试。'},
20
25
  app_settings: {'description':'获取主题、业务前后台、原生数据卡片和酷卡片管理入口','usage':'用法: openyida app-settings <appType> [--section theme|basic|data-card|cool-card] [--json]','failed':'无法读取应用设置:{0}'},
21
26
  form_view: {
@@ -34,7 +39,10 @@ module.exports = {
34
39
  integration_update_v2: {'usage': 'integration update <appType> <formUuid> <processCode> --patch patch.json [--dry-run] [--expect fingerprint] [--publish]'},
35
40
 
36
41
  conditional_actors: { unavailable: 'Conditional actors are unavailable or could not be verified.', invalid: 'Invalid conditional actors: {0}' },
37
- integration_triggers: { invalid: 'Invalid automation trigger: {0}' },
42
+ integration_triggers: {
43
+ invalid: 'Invalid automation trigger: {0}',
44
+ end_required: '请选择定时任务的结束条件:触发次数填写 schedule.maxCount(1–100),指定时间填写 schedule.expireDate(截止时间的毫秒时间戳)。长期运行可选择较远的截止日期,并在配置摘要中展示实际日期。',
45
+ },
38
46
  permission_conditions: { invalid: '数据权限条件无效:{0}' },
39
47
  agent: {
40
48
  preflight_cli_detected: 'CLI 已发现;登录、协议和模型状态由 runtime 检测并上报。',
@@ -2280,6 +2288,16 @@ module.exports.app_theme = {
2280
2288
  module.exports.help.cmd_app_theme_snapshot = '保存应用主题配置与 CSS 快照(只读)';
2281
2289
  module.exports.help.cmd_app_theme_restore = '检查或恢复应用主题快照(仅支持可精确恢复的配置)';
2282
2290
 
2291
+ Object.assign(module.exports.process_tasks || (module.exports.process_tasks = {}), {
2292
+ arguments_invalid: '参数无效:查询需要 appType 和 --process-inst-id;转交还需要 --form-uuid、--to-user-id、--expect-form-name 和 --expect-form-type process。taskId 必须为正整数,不能使用未知参数。',
2293
+ query_failed: '流程任务查询失败,未执行转交。',
2294
+ response_invalid: '流程任务响应结构、任务 ID 或实例归属无法验证,未继续操作。',
2295
+ not_running: '指定任务不是目标流程的当前运行任务,或流程没有运行中任务,未执行转交。',
2296
+ ambiguous: '流程有多个运行中任务,请查询任务列表并明确传入 --task-id,未执行转交。',
2297
+ rejected: '平台拒绝了管理员转交请求,请核对权限与任务状态。',
2298
+ result_unknown: '管理员转交结果未知,请按 nextStep 只读查询,禁止自动重试转交。',
2299
+ unverified: '转交请求已被接受,但回读未能确认接收人,请按 nextStep 只读查询,禁止自动重试转交。',
2300
+ });
2283
2301
  module.exports.data_manage_style = {
2284
2302
  'usage': 'openyida data-manage-style guide [--json]\nopenyida data-manage-style list [--json]\nopenyida data-manage-style generate --app APP_ID --form FORM-ID --style <id> --base-css <snapshot/theme.css> --output <new.css> [--focus balanced|actions] [--field-id <actualId>]... [--emphasize-field <actualId>]... [--tag-field <selectFieldId>]... [--follow-shell] [--json]',
2285
2303
  'data_style_invalid': '数据管理样式参数无效;请使用真实应用、表单和字段 ID,以及 list 返回的样式。',
@@ -2461,3 +2479,11 @@ module.exports.task_center = {
2461
2479
  'filter_carbonCreateFrom': '抄送时间起',
2462
2480
  'filter_carbonCreateTo': '抄送时间止'
2463
2481
  };
2482
+
2483
+ module.exports.feedback_github = {
2484
+ usage: '用法:openyida feedback github <status|star|fork> [--confirm] [--json]',
2485
+ confirmation: 'Star 或 Fork 需要用户明确选择后再传入 --confirm;提交 Issue 不要求这两项操作。',
2486
+ failed: 'GitHub 操作未能核实完成,请先查询状态;这不影响提交 Issue。',
2487
+ };
2488
+
2489
+ module.exports.process_dynamic_actors = { invalid: '流程人员来源配置无效,请按 details.reason 检查来源、范围与真实成员字段。' };
@@ -8,6 +8,7 @@
8
8
  * query form / get form / create form / update form / delete form / query subform
9
9
  * query process / get process / create process / update process
10
10
  * query operation-records / execute task / query tasks
11
+ * query process-tasks / transfer task (administrator)
11
12
  */
12
13
 
13
14
  'use strict';
@@ -22,6 +23,7 @@ const { queryByCurrentApprover, validateApproverOptions } = require('./process-a
22
23
  const { buildComponentAliasMaps } = require('../app/get-schema');
23
24
  const { readFormMode } = require('../app/services/form-mode-service');
24
25
  const { fetchFormPageList } = require('../app/form-navigation');
26
+ const processTasks = require('../process/process-tasks');
25
27
 
26
28
  const USAGE = `openyida data - Unified Yida data CLI
27
29
 
@@ -39,6 +41,8 @@ Usage:
39
41
  openyida data create process <appType> <formUuid> --process-code <processCode> (--data-json <JSON>|--data-file .cache/openyida/data.json) --expect-form-name <name> --expect-form-type process [--dept-id ID] [--resolve-aliases]
40
42
  openyida data update process <appType> --process-inst-id <processInstanceId> --form-uuid <formUuid> (--data-json <JSON>|--data-file .cache/openyida/data.json) --expect-form-name <name> --expect-form-type process [--resolve-aliases]
41
43
  openyida data query operation-records <appType> --process-inst-id <processInstanceId>
44
+ openyida data query process-tasks <appType> --process-inst-id <processInstanceId> [--json]
45
+ openyida data transfer task <appType> --process-inst-id <processInstanceId> --form-uuid <formUuid> --to-user-id <userId> --expect-form-name <name> --expect-form-type process [--remark <text>] [--task-id <taskId>] [--json]
42
46
  openyida data execute task <appType> --task-id <taskId> --process-inst-id <processInstanceId> --form-uuid <formUuid> --expect-form-name <name> --expect-form-type process --out-result <AGREE|DISAGREE> --remark <text> [--data-json JSON|--data-file .cache/openyida/data.json] [--resolve-aliases] [--no-execute-expressions y]
43
47
 
44
48
  openyida data query tasks <appType> --type <todo|created|done|submitted|cc> [--transport app-v1|app-query] [--page N] [--size N] [--keyword TEXT] [--normalized] [--process-codes JSON] [--instance-status STATUS]
@@ -69,6 +73,8 @@ const SUPPORTED_DATA_COMMANDS = new Set([
69
73
  'query:operation-records',
70
74
  'execute:task',
71
75
  'query:tasks',
76
+ 'query:process-tasks',
77
+ 'transfer:task',
72
78
  ]);
73
79
 
74
80
  const MUTATION_DATA_COMMANDS = new Set([
@@ -78,6 +84,7 @@ const MUTATION_DATA_COMMANDS = new Set([
78
84
  'create:process',
79
85
  'update:process',
80
86
  'execute:task',
87
+ 'transfer:task',
81
88
  ]);
82
89
 
83
90
  function fail(message) {
@@ -149,6 +156,10 @@ function validateDataCommandBeforeAuth(action, resource, positionals, options) {
149
156
  );
150
157
  }
151
158
 
159
+ if ((action === 'query' && resource === 'process-tasks') || action === 'transfer') {
160
+ processTasks.validateArguments(positionals, options, action === 'transfer');
161
+ }
162
+
152
163
  if (MUTATION_DATA_COMMANDS.has(`${action}:${resource}`)) {
153
164
  requireOption(options, 'expect_form_name');
154
165
  requireOption(options, 'expect_form_type');
@@ -203,7 +214,7 @@ function ensureSession() {
203
214
  return authRef;
204
215
  }
205
216
 
206
- function parseCliOptions(tokens) {
217
+ function parseCliOptions(tokens, strict = false) {
207
218
  const positionals = [];
208
219
  const options = {};
209
220
 
@@ -211,6 +222,9 @@ function parseCliOptions(tokens) {
211
222
  const token = tokens[i];
212
223
  if (token.startsWith('--')) {
213
224
  const key = token.slice(2).replace(/-/g, '_');
225
+ if (strict && Object.prototype.hasOwnProperty.call(options, key)) {
226
+ parseError(t('process_tasks.arguments_invalid'));
227
+ }
214
228
  const next = tokens[i + 1];
215
229
  if (next && !next.startsWith('--')) {
216
230
  options[key] = next;
@@ -1512,6 +1526,24 @@ async function queryTasks(positionals, options, session) {
1512
1526
  printResult(options.normalized ? { success: true, content: normalized } : result);
1513
1527
  }
1514
1528
 
1529
+ async function transferProcessTask(positionals, options, session) {
1530
+ const [appType] = positionals;
1531
+ const target = await requireExpectedFormTarget(session, appType, options.form_uuid, options);
1532
+ const record = await readProcessInstance(session, appType, options.process_inst_id);
1533
+ requireInstanceTarget(record, target, options.process_inst_id,
1534
+ ['processInstanceId', 'processInstId', 'instanceId']);
1535
+ const instanceStatus = record.processInstanceStatus || record.instanceStatus;
1536
+ if (instanceStatus && instanceStatus !== 'RUNNING') {
1537
+ dataError('DATA_PROCESS_TASK_NOT_RUNNING', t('process_tasks.not_running'), {
1538
+ retryable: false, retrySafe: true, sideEffectState: 'none',
1539
+ });
1540
+ }
1541
+ printResult(await processTasks.transferTask(createYidaClient({ authRef: session }), {
1542
+ appType, formUuid: options.form_uuid, processInstanceId: options.process_inst_id,
1543
+ taskId: options.task_id, toUserId: options.to_user_id, remark: options.remark,
1544
+ }));
1545
+ }
1546
+
1515
1547
  async function run(args) {
1516
1548
  if (args.length < 2) {
1517
1549
  parseError('缺少必填参数 action 或 resource');
@@ -1519,7 +1551,8 @@ async function run(args) {
1519
1551
 
1520
1552
  const action = args[0];
1521
1553
  const resource = args[1];
1522
- const { positionals, options } = parseCliOptions(args.slice(2));
1554
+ const strict = action === 'transfer' || (action === 'query' && resource === 'process-tasks');
1555
+ const { positionals, options } = parseCliOptions(args.slice(2), strict);
1523
1556
 
1524
1557
  if (
1525
1558
  action === 'query' &&
@@ -1551,6 +1584,11 @@ async function run(args) {
1551
1584
  if (action === 'query' && resource === 'operation-records') {return queryOperationRecords(positionals, options, session);}
1552
1585
  if (action === 'execute' && resource === 'task') {return executeTask(positionals, options, session);}
1553
1586
  if (action === 'query' && resource === 'tasks') {return queryTasks(positionals, options, session);}
1587
+ if (action === 'query' && resource === 'process-tasks') {
1588
+ return printResult(await processTasks.queryProcessTasks(
1589
+ createYidaClient({ authRef: session }), positionals[0], options.process_inst_id));
1590
+ }
1591
+ if (action === 'transfer' && resource === 'task') {return transferProcessTask(positionals, options, session);}
1554
1592
 
1555
1593
  dataError('DATA_COMMAND_UNSUPPORTED', t('query_data.command_unsupported', action, resource));
1556
1594
  }
@@ -23,6 +23,7 @@ const { t } = require('./i18n');
23
23
  // ── Sample 索引表 ─────────────────────────────────────────────────────
24
24
 
25
25
  const SAMPLES = {
26
+ 'yida-print-template': Object.fromEntries(require('../print-template/scenes').names.map(name => [name, `${name}.json`])),
26
27
  'yida-chart': {
27
28
  'line-trend': 'line-trend.js',
28
29
  'multi-bar-compare': 'multi-bar-compare.js',
@@ -226,7 +226,9 @@ async function run(args) {
226
226
  const client = createYidaClient({ authRef });
227
227
  const params = auth => ({ _api: 'nattyFetch', _mock: 'false', _csrf_token: auth.csrfToken, ...request.params });
228
228
  const payload = request.method === 'POST' ? await client.postForm(request.path, params) : await client.get(request.path, params);
229
- const result = lookups.normalize(options.type, payload, { appType: positionals[1] });
229
+ const result = lookups.normalize(options.type, payload, {
230
+ appType: positionals[1], keyword: request.params.key, pageSize: request.params.pageSize,
231
+ });
230
232
  console.log(JSON.stringify(result, null, 2));
231
233
  return result;
232
234
  }
@@ -159,7 +159,7 @@ function getAutoUpdateIntervalMs(env = process.env) {
159
159
 
160
160
  function shouldSkipAutoUpdateCommand(command, args = []) {
161
161
  // Report preparation must work offline even in a global npm installation.
162
- if (command === 'feedback' && args[0] === 'report') {return true;}
162
+ if (command === 'feedback' && ['report', 'github'].includes(args[0])) {return true;}
163
163
  if (!command || ['--help', '-h', '--version', '-v'].includes(command)) {
164
164
  return true;
165
165
  }
@@ -51,6 +51,7 @@ function printUsage() {
51
51
  openyida feedback setup <appType> [--name "OpenYida 体验反馈"] [--path /o/openyida-feedback] [--open|--no-open]
52
52
  openyida feedback setup --create-app [--app-name "OpenYida 体验反馈"] [--name "OpenYida 体验反馈"]
53
53
  openyida feedback report --input <summary.json> --output-dir <new-directory>
54
+ openyida feedback github <status|star|fork> [--confirm] [--json]
54
55
  openyida feedback url [--tool Codex] [--model gpt-5] [--command publish] [--diagnostics "..."]
55
56
  openyida feedback dismiss --today|--forever|--reset
56
57
  openyida feedback status