openyida 2026.9.11 → 2026.9.13
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 +7 -5
- package/bin/yida.js +1 -0
- package/lib/ai/ai.js +2 -0
- package/lib/app/canvas-compile.js +29 -26
- package/lib/app/compile.js +39 -1
- package/lib/app/services/canvas-page-compiler.js +3 -3
- package/lib/app/update-app.js +17 -2
- package/lib/asset/ai-image.js +37 -65
- package/lib/asset/asset-cmd.js +151 -110
- package/lib/asset/asset-plan.js +105 -0
- package/lib/asset/asset-resolve.js +343 -225
- package/lib/asset/asset-status.js +20 -31
- package/lib/asset/attachment-upload.js +29 -0
- package/lib/asset/host-capabilities.js +91 -0
- package/lib/asset/image-metadata.js +104 -0
- package/lib/asset/url-verify.js +90 -130
- package/lib/core/agent-capabilities.js +11 -0
- package/lib/core/command-manifest.js +25 -11
- package/lib/core/locales/en.js +6 -2
- package/lib/core/locales/zh.js +6 -2
- package/lib/design-plan/materialize.js +7 -9
- package/lib/design-plan/normalize.js +11 -1
- package/lib/process/services/process-actions.js +145 -0
- package/lib/process/services/process-compiler.js +4 -30
- package/lib/process/services/process-view-verifier.js +31 -0
- package/package.json +1 -1
- package/scripts/postinstall.js +1 -1
- package/yida-skills/SKILL.md +3 -2
- package/yida-skills/skills/yida-app/SKILL.md +1 -1
- package/yida-skills/skills/yida-app/workflow/step-2-design.md +11 -1
- package/yida-skills/skills/yida-app/workflow/step-3-create-or-reuse-app.md +21 -1
- package/yida-skills/skills/yida-app/workflow/step-5-seed-records.md +11 -7
- package/yida-skills/skills/yida-app/workflow/step-7-page-code.md +4 -0
- package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +5 -3
- package/yida-skills/skills/yida-canvas-custom-page/references/component-library-guide.md +1 -1
- package/yida-skills/skills/yida-canvas-custom-page/references/page-generation-guide.md +3 -27
- package/yida-skills/skills/yida-canvas-table-form/SKILL.md +1 -1
- package/yida-skills/skills/yida-create-app/SKILL.md +4 -4
- package/yida-skills/skills/yida-create-process/SKILL.md +2 -0
- package/yida-skills/skills/yida-custom-page/references/assets-guide.md +9 -12
- package/yida-skills/skills/yida-design/SKILL.md +1 -0
- package/yida-skills/skills/yida-design/references/ask-human-interaction-contract.md +4 -4
- package/yida-skills/skills/yida-design/references/asset-workflow.md +14 -53
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/build-plan-compact-schema.md +1 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/build-plan-schema.md +21 -4
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/scripts/render_build_plan.py +1 -2
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/scripts/validate_design_themes.py +1 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/README.md +1 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/airy-media-grid.md +1 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/airy-modular-clarity.md +1 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/airy-structured-clarity.md +1 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/ambient-halo-layered.md +1 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/dark-focus-layered.md +1 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/dark-luminous-modular.md +1 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/deep-stage-duotone.md +1 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/hairline-runway-clarity.md +1 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/high-contrast-modular.md +1 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/interlocked-vivid-modules.md +1 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/matrix-grid-focus.md +1 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/media-rail-inspector.md +1 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/mist-layered-signal.md +1 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/modular-rail-signal.md +1 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/mono-grid-signal.md +2 -2
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/ribbon-ledger-lift.md +1 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/segmented-meter-clarity.md +1 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/split-rail-precision.md +1 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/status-framed-media-grid.md +1 -1
- package/yida-skills/skills/yida-design/workflow/output-design.md +4 -0
- package/yida-skills/skills/yida-design/workflow/step-4-wireframe-interaction.md +1 -1
- package/yida-skills/skills/yida-design/workflow/step-5-visual-states.md +2 -1
- package/yida-skills/skills/yida-image-assets/SKILL.md +91 -0
- package/yida-skills/skills/yida-image-assets/references/manifest-contract.md +87 -0
- package/yida-skills/skills/yida-image-assets/references/source-policy.md +19 -0
- package/yida-skills/skills/yida-nav-shell/references/nav-shell-patterns.md +1 -1
- package/yida-skills/skills/yida-prd/workflow/output-prd.md +2 -2
- package/yida-skills/skills/yida-process-rule/SKILL.md +6 -1
- package/yida-skills/skills/yida-process-rule/references/approval-actions.md +48 -0
- package/yida-skills/skills/yida-publish-page/SKILL.md +5 -4
- package/yida-skills/skills/yida-rechart/SKILL.md +1 -1
- package/yida-skills/skills/yida-requirement-analysis/SKILL.md +1 -1
- package/yida-skills/skills/yida-requirement-analysis/workflow/prepare-brief.md +22 -13
- package/yida-skills/skills-index.json +18 -1
|
@@ -8,6 +8,7 @@ const { t } = require('./i18n');
|
|
|
8
8
|
const { buildCommandManifest } = require('./command-manifest');
|
|
9
9
|
const { buildEnvironmentSnapshot } = require('./env');
|
|
10
10
|
const coreUtils = require('./utils');
|
|
11
|
+
const { buildHostAssetCapabilities } = require('../asset/host-capabilities');
|
|
11
12
|
const { findProjectRoot, getAuthStatus } = coreUtils;
|
|
12
13
|
|
|
13
14
|
function redactLogin(login) {
|
|
@@ -127,6 +128,10 @@ function buildRuntimeSnapshot(projectRoot) {
|
|
|
127
128
|
};
|
|
128
129
|
}
|
|
129
130
|
|
|
131
|
+
function buildAssetCapabilities(runtime, env = process.env) {
|
|
132
|
+
return buildHostAssetCapabilities({ runtime, env });
|
|
133
|
+
}
|
|
134
|
+
|
|
130
135
|
const BUILDER_CORE_COMMAND_IDS = Object.freeze([
|
|
131
136
|
'agent-capabilities',
|
|
132
137
|
'commands',
|
|
@@ -461,6 +466,7 @@ function buildFullAppArtifactRoute(manifest) {
|
|
|
461
466
|
orchestrator_skill_id: workflow.orchestrator_skill_id,
|
|
462
467
|
requirement_analysis_skill_id: workflow.requirement_analysis_skill_id,
|
|
463
468
|
requirement_brief_path: workflow.requirement_brief_path,
|
|
469
|
+
optional_asset_branch: workflow.optional_asset_branch,
|
|
464
470
|
design_mode_policy: workflow.design_mode_policy,
|
|
465
471
|
navigation_policy: workflow.navigation_policy,
|
|
466
472
|
plan_command_ids: workflow.plan_command_ids,
|
|
@@ -572,6 +578,7 @@ function buildAgentCapabilitiesSummary() {
|
|
|
572
578
|
const skillsDiagnostics = compactSkillsDiagnostics(buildSkillsDiagnosticsCompat(projectResolution));
|
|
573
579
|
const loginStatus = getAuthStatus({ projectRoot, includeSecrets: false });
|
|
574
580
|
const runtime = buildRuntimeSnapshot(projectRoot);
|
|
581
|
+
const assetCapabilities = buildAssetCapabilities(runtime);
|
|
575
582
|
const builderPath = compactBuilderPath(
|
|
576
583
|
buildBuilderPath(loginStatus, projectRoot, manifest, process.env, runtime)
|
|
577
584
|
);
|
|
@@ -598,6 +605,7 @@ function buildAgentCapabilitiesSummary() {
|
|
|
598
605
|
full_app_artifact_route: buildFullAppArtifactRoute(manifest),
|
|
599
606
|
application_entry_policy: applicationEntryPolicy,
|
|
600
607
|
runtime,
|
|
608
|
+
asset_capabilities: assetCapabilities,
|
|
601
609
|
builder_path: builderPath,
|
|
602
610
|
};
|
|
603
611
|
}
|
|
@@ -615,6 +623,7 @@ function buildAgentCapabilities() {
|
|
|
615
623
|
const skillsDiagnostics = buildSkillsDiagnosticsCompat(projectResolution);
|
|
616
624
|
const loginStatus = redactLogin(getAuthStatus({ projectRoot, includeSecrets: false }));
|
|
617
625
|
const runtime = buildRuntimeSnapshot(projectRoot);
|
|
626
|
+
const assetCapabilities = buildAssetCapabilities(runtime);
|
|
618
627
|
const builderPath = buildBuilderPath(loginStatus, projectRoot, manifest, process.env, runtime);
|
|
619
628
|
const applicationEntryPolicy = buildApplicationEntryPolicy(builderPath, process.env);
|
|
620
629
|
const manifestDigest = buildCommandManifestDigest(manifest);
|
|
@@ -633,6 +642,7 @@ function buildAgentCapabilities() {
|
|
|
633
642
|
system: envSnapshot.system,
|
|
634
643
|
active: envSnapshot.active,
|
|
635
644
|
runtime,
|
|
645
|
+
asset_capabilities: assetCapabilities,
|
|
636
646
|
login: loginStatus,
|
|
637
647
|
application_entry_policy: applicationEntryPolicy,
|
|
638
648
|
recommended: {
|
|
@@ -710,6 +720,7 @@ module.exports = {
|
|
|
710
720
|
buildAgentCapabilities,
|
|
711
721
|
buildAgentCapabilitiesSummary,
|
|
712
722
|
buildApplicationEntryPolicy,
|
|
723
|
+
buildAssetCapabilities,
|
|
713
724
|
compactBuilderPath,
|
|
714
725
|
buildCommandManifestDigest,
|
|
715
726
|
buildIdentity,
|
|
@@ -422,10 +422,10 @@ const COMMAND_SIDE_EFFECTS = new Map([
|
|
|
422
422
|
})],
|
|
423
423
|
|
|
424
424
|
['asset', sideEffect('mixed', {
|
|
425
|
-
mutates_yida:
|
|
425
|
+
mutates_yida: true,
|
|
426
426
|
mutates_local: true,
|
|
427
|
-
read_actions: ['status', '
|
|
428
|
-
mutating_actions: ['resolve --
|
|
427
|
+
read_actions: ['status', 'sources', 'resolve --offline'],
|
|
428
|
+
mutating_actions: ['resolve', 'resolve --manifest', 'resolve --upload-assets'],
|
|
429
429
|
})],
|
|
430
430
|
|
|
431
431
|
...sideEffectEntries([
|
|
@@ -757,7 +757,7 @@ const COMMAND_PERMISSIONS = new Map([
|
|
|
757
757
|
...permissionEntries([
|
|
758
758
|
'asset',
|
|
759
759
|
], actionDependentPermission({
|
|
760
|
-
preauthorized_actions: ['
|
|
760
|
+
preauthorized_actions: ['resolve', 'resolve --manifest', 'resolve --upload-assets'],
|
|
761
761
|
})),
|
|
762
762
|
|
|
763
763
|
...permissionEntries([
|
|
@@ -1251,7 +1251,7 @@ const COMMAND_GROUPS = [
|
|
|
1251
1251
|
command('create-page', ['create-page'], 'create-page <appType> "<name>" [--mode dashboard] [--hide-nav] [--locale zh_CN|en_US|ja_JP] [--open|--no-open]', 'help.cmd_create_page'),
|
|
1252
1252
|
command('build-page', ['build-page'], 'build-page <sourceFile> [--output file|--write]', 'help.cmd_build_page', { requiresLogin: false }),
|
|
1253
1253
|
command('check-page', ['check-page'], 'check-page <src> [--compat]', 'help.cmd_check_page', { output: 'text|json' }),
|
|
1254
|
-
command('compile', ['compile'], 'compile <src>', 'help.cmd_compile', { requiresLogin: false }),
|
|
1254
|
+
command('compile', ['compile'], 'compile <src> [--canvas] [--json]', 'help.cmd_compile', { requiresLogin: false, output: 'text|json' }),
|
|
1255
1255
|
command('publish', ['publish'], 'publish <src> <appType> <formUuid> [--health-check] [--force] [--canvas] [--auto-nav-order] [--open|--no-open]', 'help.cmd_publish'),
|
|
1256
1256
|
command('update-form-config', ['update-form-config'], 'update-form-config <appType> <formUuid> <true|false|keep> "<title>" [--locale zh_CN|en_US|ja_JP]', 'help.cmd_update_form_config'),
|
|
1257
1257
|
command('get-form-config', ['get-form-config'], 'get-form-config <appType> <formUuid> [--json]', 'help.cmd_get_form_config', { output: 'json' }),
|
|
@@ -1292,8 +1292,15 @@ const COMMAND_GROUPS = [
|
|
|
1292
1292
|
id: 'process',
|
|
1293
1293
|
titleKey: 'help.group_process',
|
|
1294
1294
|
commands: [
|
|
1295
|
-
command('configure-process', ['configure-process'], 'configure-process <appType> <formUuid> <definition> [processCode] [--replace]', 'help.cmd_configure_process'
|
|
1296
|
-
|
|
1295
|
+
command('configure-process', ['configure-process'], 'configure-process <appType> <formUuid> <definition> [processCode] [--replace]', 'help.cmd_configure_process', {
|
|
1296
|
+
examples: ['openyida configure-process APP_XXX FORM_XXX .cache/openyida/process/process-with-actions.json'],
|
|
1297
|
+
}),
|
|
1298
|
+
command('create-process', ['create-process'], 'create-process <appType> ... [--replace]', 'help.cmd_create_process', {
|
|
1299
|
+
examples: [
|
|
1300
|
+
'openyida create-process APP_XXX "Approval Form" .cache/openyida/process/fields.json .cache/openyida/process/process-with-actions.json',
|
|
1301
|
+
'openyida create-process APP_XXX --formUuid FORM_XXX .cache/openyida/process/process-with-actions.json',
|
|
1302
|
+
],
|
|
1303
|
+
}),
|
|
1297
1304
|
command('ai-form-setting', ['ai-form-setting'], 'ai-form-setting <get|fields|models|enable|disable|save> <appType> ...', 'help.cmd_ai_form_setting', {
|
|
1298
1305
|
output: 'json',
|
|
1299
1306
|
aliases: ['ai-approve', 'aiFormSetting'],
|
|
@@ -1433,7 +1440,7 @@ const COMMAND_GROUPS = [
|
|
|
1433
1440
|
command('ai', ['ai'], 'ai <text|image> [options]', 'help.cmd_ai', {
|
|
1434
1441
|
output: 'text|json',
|
|
1435
1442
|
}),
|
|
1436
|
-
command('asset', ['asset'], 'asset <status|resolve|
|
|
1443
|
+
command('asset', ['asset'], 'asset <status|resolve|sources> [options]', 'help.cmd_asset', {
|
|
1437
1444
|
requiresLogin: false,
|
|
1438
1445
|
output: 'text|json',
|
|
1439
1446
|
}),
|
|
@@ -1539,6 +1546,13 @@ function summarizeLocalizedCommands(commands) {
|
|
|
1539
1546
|
default_ui_guidance_skill_id: 'yida-design',
|
|
1540
1547
|
requirement_analysis_skill_id: 'yida-requirement-analysis',
|
|
1541
1548
|
requirement_brief_path: '.cache/openyida/<project>/requirement-brief.json',
|
|
1549
|
+
optional_asset_branch: {
|
|
1550
|
+
skill_id: 'yida-image-assets',
|
|
1551
|
+
trigger: 'Any page is imageNeed=required, or imageNeed=beneficial with declared image slots.',
|
|
1552
|
+
output_path: 'prd/<project>/asset-manifest.json',
|
|
1553
|
+
skip: 'All pages are imageNeed=none.',
|
|
1554
|
+
dependency_policy: 'Only blocks pages that consume the declared image slots.',
|
|
1555
|
+
},
|
|
1542
1556
|
artifact_generation: {
|
|
1543
1557
|
mode: 'parallel',
|
|
1544
1558
|
audience: 'internal',
|
|
@@ -1555,10 +1569,10 @@ function summarizeLocalizedCommands(commands) {
|
|
|
1555
1569
|
plan_command_ids: ['design-plan.init', 'design-plan.preview', 'design-plan.materialize', 'design-plan.patch'],
|
|
1556
1570
|
theme_command_ids: ['sample', 'create-app', 'update-app'],
|
|
1557
1571
|
navigation_command_ids: { platform: ['update-app', 'nav-group'], custom: ['update-app', 'update-form-config', 'get-form-config'] },
|
|
1558
|
-
navigation_policy: 'Before PRD planning, reuse explicit navigation choices. During first-time intake, ask only when unknown: platform
|
|
1559
|
-
design_mode_policy: 'Analyze requirements first. First-time builds include new apps and existing apps without business pages. Reuse detailed supplied plans; if the mode is unspecified, ask whether to prepare a PRD for confirmation (Plan, more detailed and slower) or build from the supplied requirements (Fast). Without detailed requirements, offer Fast and Plan neutrally. Confirm unresolved navigation
|
|
1572
|
+
navigation_policy: 'Before PRD planning, reuse explicit navigation choices. During first-time intake, ask only when ownership is unknown and offer exactly two neutral options with no preselection: "宜搭原生导航" (使用宜搭自带的导航菜单。) and "自定义导航" (在自定义页面里定制菜单的样式和操作方式,替代宜搭自带的导航菜单。). Native means platform navigation. The agent chooses layout from module count, hierarchy, switching frequency, content width and target device; do not ask layout or presentation-style questions. Prefer top for few shallow modules and wide content, side for many frequently accessed modules, L-shaped/mixed for business domains with child modules, and custom dock for lightweight mobile entries. Preserve user-specified layouts. Store resolved type/source/reason/variant in the brief, distinguishing user ownership from agent layout reasoning. Platform navigation uses update-app --layout top|side|l_shape --show-app-nav, which writes layoutDirection=top|side|l_shape and hideAppNav=n. Preserve stored navType unchanged; do not derive or invent it and do not add a --nav-type option. Without --layout, normalize stored legacy layoutDirection and navType using the yc-utils application rules (hoz plus top_side means l_shape; missing layout uses top_fold/top_side for top/l_shape). Shell page-level top_fold/none overrides do not belong in app settings. Custom side/top/mixed/dock is a page layout and requires app and per-page navigation hiding with readback. Verify persisted layoutDirection and hideAppNav; updatedFields and themeVerification do not prove navigation persistence. Navigation tone is separate from layout.',
|
|
1573
|
+
design_mode_policy: 'Analyze requirements first. First-time builds include new apps and existing apps without business pages. Reuse detailed supplied plans; if the mode is unspecified, ask whether to prepare a PRD for confirmation (Plan, more detailed and slower) or build from the supplied requirements (Fast). Without detailed requirements, offer Fast and Plan neutrally. Confirm unresolved navigation ownership, visual style and page scope before planning or resource creation; the agent determines navigation layout from the business context without a layout question. Existing business apps only clarify the current change. A named resource-only request with explicitScope.allowInferredResources=false skips unrelated navigation and visual questions. Standard Plan uses design-plan init parallelTasks, then executes the returned materialize.command exactly once with business-file and visual-file; preview and --from-preview are only for explicitly incremental large plans. Confirm the displayed revision before building, and do not materialize or patch again after confirmation.',
|
|
1560
1574
|
product_design_policy: 'yida-requirement-analysis owns shared facts and first-time intake. yida-prd owns business planning; yida-design owns visual design. Reuse the same confirmed brief and supplied details. Prepare business and base visuals concurrently, then bind visuals to settled page tasks. yida-app merges and checks the artifacts before creating resources. Plan uses the compact authoring contract and selected theme context; the CLI reads full templates and renders all artifacts.',
|
|
1561
|
-
ui_guidance_policy: 'Page implementation consumes yida-prd prd.md for positioning, information architecture, page prototype, native form entry policy, material strategy, business-specific checks, resource creation order, page implementation delivery order, navigation order, and acceptance criteria; it consumes yida-design design.md for app custom theme CSS delivery, themeColor/navTheme, visual states, visualScaffold, surface material, rounded rules, density rules, components, and
|
|
1575
|
+
ui_guidance_policy: 'Page implementation consumes yida-prd prd.md for positioning, information architecture, page prototype, native form entry policy, material strategy, business-specific checks, resource creation order, page implementation delivery order, navigation order, and acceptance criteria; it consumes yida-design design.md for app custom theme CSS delivery, themeColor/navTheme, visual states, visualScaffold, surface material, rounded rules, density rules, components, state styling, and page-level imageNeed. When a page is imageNeed=required, or beneficial with declared image slots, yida-image-assets prepares a traceable asset manifest before that page is implemented; imageNeed=none skips the branch. prd.md and design.md remain the only design sources of truth. Page implementation may extract page-spec.json as a derived implementation handoff from prd.md + design.md; conflicts are resolved by sending business conflicts to yida-prd and visual conflicts to yida-design before regenerating the spec. Core normal forms default to 1-3 business sample records before page implementation, followed by query readback. An explicit opt-out, configuration dictionary, sensitive data, or lack of safely constructible values requires a recorded skip reason. Screenshots, public sharing, data-source deep binding, and fine navigation grouping are optional after explicit user request or PRD acceptance criteria.',
|
|
1562
1576
|
default_nav_order_policy: 'For custom navigation, implement PRD navigation order in the custom shell and verify app/page navigation hiding; skip platform nav-group ordering. For platform navigation: after the primary page is successfully published, perform exactly one navigation order operation. If the PRD names a navigation order, publish without --auto-nav-order and then call openyida nav-group order <appType> <items...>. If the PRD only gives broad groups or is missing navigation order, use openyida publish ... --auto-nav-order and do not call nav-group order or auto-order afterward. Explicit and automatic ordering are mutually exclusive; never generate per-item move loops. The fallback priority is portal/home/workbench entry > business handling > data management > business analytics > system configuration.',
|
|
1563
1577
|
final_link_policy: 'Return exactly one user-visible application entry group, never one artifact or link card per form, process, report, schema, manifest, PRD, design file, or intermediate artifact. The group always contains the app workbench URL. Add the clean custom page URL only when PRD entryMode=standalone and get-form-config readback confirms isRenderNav=false. Add the admin URL only when agent-capabilities application_entry_policy.entries.admin=include. Summarize other business resources in prose by default, but every resource count, seed-record count, and completed/verified claim must come from that resource\'s own successful result or readback. When the user or caller explicitly requests a resource manifest, resource UUIDs/IDs, publish status, or test-data summary, include one concise verified delivery manifest in the final prose and do not substitute link cards for it.',
|
|
1564
1578
|
application_entry_policy: {
|
package/lib/core/locales/en.js
CHANGED
|
@@ -64,8 +64,8 @@ module.exports = {
|
|
|
64
64
|
cmd_corp_manager: 'Manage platform admins and address book permissions',
|
|
65
65
|
cmd_agent_center: 'Manage process and departure delegation',
|
|
66
66
|
group_process: 'Process',
|
|
67
|
-
cmd_configure_process: 'Configure and publish process rules',
|
|
68
|
-
cmd_create_process: 'Create process form (all-in-one)',
|
|
67
|
+
cmd_configure_process: 'Configure and publish process rules; Supports append/forward via JSON nodes[].actions.normalActions/appendActions',
|
|
68
|
+
cmd_create_process: 'Create process form (all-in-one); Supports append/forward via JSON nodes[].actions.normalActions/appendActions',
|
|
69
69
|
cmd_ai_form_setting: 'Manage process form AI approval prompts',
|
|
70
70
|
cmd_process_preview: 'Preview process instance (visual flowchart)',
|
|
71
71
|
group_share: 'Page Config & Sharing',
|
|
@@ -2070,3 +2070,7 @@ module.exports.connector_e2e = {
|
|
|
2070
2070
|
test_contract_unverified: 'Connector testing did not prove the controlled fixture, marker, ownership, and auth runtime contract.',
|
|
2071
2071
|
action_mutated: 'Connector testing mutated the persisted action definition.',
|
|
2072
2072
|
};
|
|
2073
|
+
|
|
2074
|
+
Object.assign(module.exports.process_errors || (module.exports.process_errors = {}), {
|
|
2075
|
+
action_config_invalid: 'Invalid approval action configuration for node {0}: {1}',
|
|
2076
|
+
});
|
package/lib/core/locales/zh.js
CHANGED
|
@@ -64,8 +64,8 @@ module.exports = {
|
|
|
64
64
|
cmd_corp_manager: '管理平台管理员与通讯录权限',
|
|
65
65
|
cmd_agent_center: '管理流程代理和离职代理',
|
|
66
66
|
group_process: '流程',
|
|
67
|
-
cmd_configure_process: '
|
|
68
|
-
cmd_create_process: '
|
|
67
|
+
cmd_configure_process: '配置并发布流程规则; 支持加签/转交,配置位于 JSON nodes[].actions.normalActions/appendActions',
|
|
68
|
+
cmd_create_process: '创建流程表单(一体化); 支持加签/转交,配置位于 JSON nodes[].actions.normalActions/appendActions',
|
|
69
69
|
cmd_ai_form_setting: '管理流程表单 AI 审批提示',
|
|
70
70
|
cmd_process_preview: '预览流程实例(可视化流程图)',
|
|
71
71
|
group_share: '页面配置 & 分享',
|
|
@@ -2024,3 +2024,7 @@ module.exports.connector_e2e = {
|
|
|
2024
2024
|
test_contract_unverified: '连接器测试未能证明受控 fixture、标记、归属和鉴权运行时契约。',
|
|
2025
2025
|
action_mutated: '连接器测试改变了持久化动作定义。',
|
|
2026
2026
|
};
|
|
2027
|
+
|
|
2028
|
+
Object.assign(module.exports.process_errors || (module.exports.process_errors = {}), {
|
|
2029
|
+
action_config_invalid: '节点 {0} 的审批动作配置无效:{1}',
|
|
2030
|
+
});
|
|
@@ -590,14 +590,11 @@ function renderPageApplications(applications) {
|
|
|
590
590
|
|
|
591
591
|
function assetSummary(assetStrategy) {
|
|
592
592
|
const strategy = assetStrategy || {};
|
|
593
|
-
const
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
values.push(`${key}: ${text(value)}`);
|
|
599
|
-
}
|
|
600
|
-
return values.join(';') || '无现成品牌素材';
|
|
593
|
+
const pages = Array.isArray(strategy.pages) ? strategy.pages : [];
|
|
594
|
+
return pages.map((page) => {
|
|
595
|
+
const slotCount = Array.isArray(page.slots) ? page.slots.length : 0;
|
|
596
|
+
return `${page.pageId || '未命名页面'}: ${page.imageNeed || 'none'},${slotCount} 个槽位`;
|
|
597
|
+
}).join(';') || '无图片需求';
|
|
601
598
|
}
|
|
602
599
|
|
|
603
600
|
function componentReferences(markdown) {
|
|
@@ -653,7 +650,7 @@ function renderDesign(plan) {
|
|
|
653
650
|
PRODUCT_TOPOLOGY_APPLICATION: text(forDesignMd.productTopologyApplication),
|
|
654
651
|
PAGE_PATTERN_SUMMARY: renderPagePatterns(plan.pages || {}),
|
|
655
652
|
PAGE_APPLICATIONS: renderPageApplications(forUser.pageApplications),
|
|
656
|
-
|
|
653
|
+
PAGE_IMAGE_NEEDS: assetSummary(forUser.assetStrategy),
|
|
657
654
|
ASSET_GAPS: text((forUser.assetStrategy || {}).missingAssets, '无'),
|
|
658
655
|
};
|
|
659
656
|
let output = template.replace(/\{\{([A-Z_]+)\}\}/g, (match, key) => {
|
|
@@ -746,6 +743,7 @@ function renderDesign(plan) {
|
|
|
746
743
|
}
|
|
747
744
|
output = output.replace(/^---\n/, () => [
|
|
748
745
|
'---',
|
|
746
|
+
`assetStrategy: ${JSON.stringify({ pages: [], ...forUser.assetStrategy })}`,
|
|
749
747
|
`themeProfile: ${JSON.stringify({ themeColor: primaryColor, navTheme: navigationStyle.tone, ...navigationConfig(plan), logoSource: 'appIcon', themeDelivery: 'app-custom-theme-file' })}`,
|
|
750
748
|
`sceneRecipes: ${JSON.stringify(scenes)}`,
|
|
751
749
|
`components: ${JSON.stringify(references.components)}`,
|
|
@@ -302,7 +302,17 @@ function ensureVisual(plan) {
|
|
|
302
302
|
forUser.stateSummary = forUser.stateSummary || '默认、悬停、按下、聚焦、禁用、加载、空态、错误、无权限和选中状态保持一致。';
|
|
303
303
|
forUser.responsiveSummary = forUser.responsiveSummary || '响应式断点、重排和触控规则保持统一,并维持页面主任务顺序。';
|
|
304
304
|
forUser.iconSummary = forUser.iconSummary || '图标风格、尺寸和语义保持一致。';
|
|
305
|
-
forUser.assetStrategy = forUser.assetStrategy || {
|
|
305
|
+
forUser.assetStrategy = forUser.assetStrategy || {
|
|
306
|
+
materialStatus: 'none',
|
|
307
|
+
pages: list((plan.pages || {}).customPageDetails).map(page => ({
|
|
308
|
+
pageId: page.pageId,
|
|
309
|
+
imageNeed: 'none',
|
|
310
|
+
reason: '无图片槽位。',
|
|
311
|
+
slots: [],
|
|
312
|
+
})),
|
|
313
|
+
missingAssets: [],
|
|
314
|
+
notes: '需要图片时使用 yida-image-assets。',
|
|
315
|
+
};
|
|
306
316
|
forUser.designMdReady = forUser.designMdReady || 'materialize 将从所选完整主题模板生成 design.md。';
|
|
307
317
|
|
|
308
318
|
const forDesignMd = visual.forDesignMd = visual.forDesignMd || {};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { buildYidaI18n } = require('../../core/yida-i18n');
|
|
4
|
+
const { t } = require('../../core/i18n');
|
|
5
|
+
|
|
6
|
+
function buildActions() {
|
|
7
|
+
const actionDefs = [
|
|
8
|
+
{ action: 'agree', zh: '同意', en: 'Agree', ja: '同意', hidden: false },
|
|
9
|
+
{ action: 'disagree', zh: '拒绝', en: 'Disagree', ja: '拒否', hidden: false },
|
|
10
|
+
{ action: 'save', zh: '保存', en: 'Save', ja: '保存', hidden: true },
|
|
11
|
+
{ action: 'forward', zh: '转交', en: 'Forward', ja: '転送', hidden: true },
|
|
12
|
+
{ action: 'append', zh: '加签', en: 'Append', ja: '承認者を追加', hidden: true },
|
|
13
|
+
{ action: 'return', zh: '退回', en: 'Return', ja: '差し戻し', hidden: true },
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
return actionDefs.map(function (def) {
|
|
17
|
+
return {
|
|
18
|
+
hidden: def.hidden,
|
|
19
|
+
name: buildYidaI18n(def.zh, { en_US: def.en, ja_JP: def.ja }),
|
|
20
|
+
action: def.action,
|
|
21
|
+
text: buildYidaI18n(def.zh, { en_US: def.en, ja_JP: def.ja }),
|
|
22
|
+
alias: buildYidaI18n(def.zh, { en_US: def.en, ja_JP: def.ja }),
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function invalid(nodeName, field) {
|
|
28
|
+
const error = new TypeError(t('process_errors.action_config_invalid', nodeName, field));
|
|
29
|
+
error.code = 'PROCESS_COMPILE_ACTION_CONFIG_INVALID';
|
|
30
|
+
error.details = { nodeName, field };
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function isObject(value) {
|
|
35
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function clone(value) {
|
|
39
|
+
return JSON.parse(JSON.stringify(value));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Merge partial button settings without changing unspecified permissions. */
|
|
43
|
+
function normalizeActions(value, field, nodeName, complete = false) {
|
|
44
|
+
const defaults = buildActions();
|
|
45
|
+
if (value === undefined) { return defaults; }
|
|
46
|
+
if (!Array.isArray(value)) { invalid(nodeName, field); }
|
|
47
|
+
const seen = new Set();
|
|
48
|
+
const overrides = value.map(action => {
|
|
49
|
+
if (!isObject(action) || typeof action.action !== 'string' || !action.action.trim()
|
|
50
|
+
|| (!complete && !['agree', 'disagree', 'save', 'forward', 'append', 'return', 'recall'].includes(action.action))
|
|
51
|
+
|| seen.has(action.action) || (action.hidden !== undefined && typeof action.hidden !== 'boolean')) {
|
|
52
|
+
invalid(nodeName, field);
|
|
53
|
+
}
|
|
54
|
+
seen.add(action.action);
|
|
55
|
+
return clone(action);
|
|
56
|
+
});
|
|
57
|
+
const merge = (base, override) => {
|
|
58
|
+
const result = { ...base, ...override };
|
|
59
|
+
if (override && override.name !== undefined && override.alias === undefined) { result.alias = clone(override.name); }
|
|
60
|
+
if (override && override.alias !== undefined && override.name === undefined) { result.name = clone(override.alias); }
|
|
61
|
+
return result;
|
|
62
|
+
};
|
|
63
|
+
// Raw processProps arrays are complete lists, not partial overrides. Do not add
|
|
64
|
+
// agree/disagree permissions to a legacy list that intentionally omitted them.
|
|
65
|
+
if (complete) {
|
|
66
|
+
// NewProcessAdapter treats an omitted hidden field in a raw action as visible.
|
|
67
|
+
return overrides.map(item => merge({ ...defaults.find(action => action.action === item.action), hidden: false }, item));
|
|
68
|
+
}
|
|
69
|
+
const result = defaults.map(action => merge(action, overrides.find(item => item.action === action.action)));
|
|
70
|
+
// Native versions may include the additional recall button.
|
|
71
|
+
overrides.filter(item => item.action === 'recall').forEach(item => result.push({ hidden: true, ...item }));
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Compile one shared action contract into designer and engine representations.
|
|
77
|
+
* Native node.actions takes precedence; legacy processProps lists remain accepted.
|
|
78
|
+
* Missing append settings use the same defaults as ActionSetter; invalid explicit
|
|
79
|
+
* settings fail before publishing. No config retains historical hidden defaults.
|
|
80
|
+
* @param {object|undefined} config native normalActions / appendActions overrides
|
|
81
|
+
* @param {object} rawProps legacy approver process properties
|
|
82
|
+
* @param {string} nodeName diagnostic node name
|
|
83
|
+
* @returns {{viewActions: object, processProps: object}} independent JSON values
|
|
84
|
+
*/
|
|
85
|
+
function buildNodeActions(config, rawProps = {}, nodeName = '') {
|
|
86
|
+
if (config !== undefined && (!isObject(config)
|
|
87
|
+
|| Object.keys(config).some(key => !['normalActions', 'appendActions'].includes(key)))) {
|
|
88
|
+
invalid(nodeName, 'actions');
|
|
89
|
+
}
|
|
90
|
+
const input = config || {};
|
|
91
|
+
const normalActions = normalizeActions(input.normalActions === undefined ? rawProps.actions : input.normalActions,
|
|
92
|
+
'actions.normalActions', nodeName, input.normalActions === undefined);
|
|
93
|
+
const appendActions = normalizeActions(input.appendActions === undefined ? rawProps.appendActions : input.appendActions,
|
|
94
|
+
'actions.appendActions', nodeName, input.appendActions === undefined);
|
|
95
|
+
const append = normalActions.find(item => item.action === 'append') || { hidden: true };
|
|
96
|
+
const appendedAppend = appendActions.find(item => item.action === 'append') || { hidden: true };
|
|
97
|
+
const processProps = {};
|
|
98
|
+
|
|
99
|
+
// These engine fields are node-wide: the designer derives them from normalActions.
|
|
100
|
+
if (!appendedAppend.hidden && append.hidden) {
|
|
101
|
+
invalid(nodeName, 'actions.normalActions.append.hidden');
|
|
102
|
+
}
|
|
103
|
+
if (!append.hidden) {
|
|
104
|
+
if (append.appendPosition === undefined) {
|
|
105
|
+
append.appendPosition = rawProps.moldList === undefined ? ['BEFORE_APPEND'] : clone(rawProps.moldList);
|
|
106
|
+
}
|
|
107
|
+
if (append.appendResult === undefined) {
|
|
108
|
+
if (rawProps.isConsiderAppendedAction !== undefined && typeof rawProps.isConsiderAppendedAction !== 'boolean') {
|
|
109
|
+
invalid(nodeName, 'processProps.isConsiderAppendedAction');
|
|
110
|
+
}
|
|
111
|
+
append.appendResult = rawProps.isConsiderAppendedAction === undefined
|
|
112
|
+
? 'valid' : (rawProps.isConsiderAppendedAction === true ? 'valid' : 'invalid');
|
|
113
|
+
}
|
|
114
|
+
if (!Array.isArray(append.appendPosition) || append.appendPosition.length === 0
|
|
115
|
+
|| append.appendPosition.some(position => !['BEFORE_APPEND', 'AFTER_APPEND'].includes(position))
|
|
116
|
+
|| new Set(append.appendPosition).size !== append.appendPosition.length) {
|
|
117
|
+
invalid(nodeName, 'actions.normalActions.append.appendPosition');
|
|
118
|
+
}
|
|
119
|
+
if (!['valid', 'invalid'].includes(append.appendResult)) {
|
|
120
|
+
invalid(nodeName, 'actions.normalActions.append.appendResult');
|
|
121
|
+
}
|
|
122
|
+
Object.assign(processProps, {
|
|
123
|
+
allowTaskAppend: true,
|
|
124
|
+
moldList: clone(append.appendPosition),
|
|
125
|
+
isConsiderAppendedAction: append.appendResult === 'valid',
|
|
126
|
+
isNeedEndTaskGroupChain: append.appendResult === 'valid',
|
|
127
|
+
});
|
|
128
|
+
} else if (['allowTaskAppend', 'moldList', 'isConsiderAppendedAction', 'isNeedEndTaskGroupChain']
|
|
129
|
+
.some(key => rawProps[key] !== undefined)) {
|
|
130
|
+
// Clear stale engine flags when the action is explicitly disabled.
|
|
131
|
+
Object.assign(processProps, {
|
|
132
|
+
allowTaskAppend: false, moldList: [], isConsiderAppendedAction: false, isNeedEndTaskGroupChain: false,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
const viewActions = { normalActions, appendActions };
|
|
136
|
+
// Retain existing return settings in both representations.
|
|
137
|
+
['realBackOriginator', 'triggerRule', 'backScope'].forEach(key => {
|
|
138
|
+
if (rawProps[key] !== undefined) { viewActions[key] = clone(rawProps[key]); }
|
|
139
|
+
});
|
|
140
|
+
processProps.actions = clone(normalActions);
|
|
141
|
+
processProps.appendActions = clone(appendActions);
|
|
142
|
+
return { viewActions, processProps };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
module.exports = { buildNodeActions };
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
const { buildYidaI18n } = require('../../core/yida-i18n');
|
|
10
10
|
const { t } = require('../../core/i18n');
|
|
11
|
+
const { buildNodeActions } = require('./process-actions');
|
|
11
12
|
|
|
12
13
|
const KEY_PATTERN = /^[A-Za-z][A-Za-z0-9_]*$/;
|
|
13
14
|
|
|
@@ -649,29 +650,6 @@ function buildFriendlyApproverConfig(node, approver) {
|
|
|
649
650
|
return null;
|
|
650
651
|
}
|
|
651
652
|
|
|
652
|
-
// ── 构建审批/抄送动作列表 ────────────────────────────
|
|
653
|
-
|
|
654
|
-
function buildActions() {
|
|
655
|
-
const actionDefs = [
|
|
656
|
-
{ action: 'agree', zh: '同意', en: 'Agree', ja: '同意', hidden: false },
|
|
657
|
-
{ action: 'disagree', zh: '拒绝', en: 'Disagree', ja: '拒否', hidden: false },
|
|
658
|
-
{ action: 'save', zh: '保存', en: 'Save', ja: '保存', hidden: true },
|
|
659
|
-
{ action: 'forward', zh: '转交', en: 'Forward', ja: '転送', hidden: true },
|
|
660
|
-
{ action: 'append', zh: '加签', en: 'Append', ja: '承認者を追加', hidden: true },
|
|
661
|
-
{ action: 'return', zh: '退回', en: 'Return', ja: '差し戻し', hidden: true },
|
|
662
|
-
];
|
|
663
|
-
|
|
664
|
-
return actionDefs.map(function (def) {
|
|
665
|
-
return {
|
|
666
|
-
hidden: def.hidden,
|
|
667
|
-
name: i18n(def.zh, def.en, def.ja),
|
|
668
|
-
action: def.action,
|
|
669
|
-
text: i18n(def.zh, def.en, def.ja),
|
|
670
|
-
alias: i18n(def.zh, def.en, def.ja),
|
|
671
|
-
};
|
|
672
|
-
});
|
|
673
|
-
}
|
|
674
|
-
|
|
675
653
|
// ── 构建条件规则(严格匹配宜搭真实格式)─────────────
|
|
676
654
|
|
|
677
655
|
function buildConditionRules(rules, logic) {
|
|
@@ -1162,10 +1140,9 @@ function buildApprovalNode(node, nextNodeId, nameToIdMap, nodeType) {
|
|
|
1162
1140
|
formConfig = { behaviorList: behaviorList };
|
|
1163
1141
|
}
|
|
1164
1142
|
|
|
1143
|
+
const nodeActions = buildNodeActions(node.actions, approverConfig.processProps, displayName);
|
|
1165
1144
|
const processNodeProps = {
|
|
1166
1145
|
conditionalMode: 'conditional',
|
|
1167
|
-
actions: buildActions(),
|
|
1168
|
-
appendActions: buildActions(),
|
|
1169
1146
|
openDigitalSign: false,
|
|
1170
1147
|
noActionersType: 'stopProcess',
|
|
1171
1148
|
routeRule: routeRule,
|
|
@@ -1173,7 +1150,7 @@ function buildApprovalNode(node, nextNodeId, nameToIdMap, nodeType) {
|
|
|
1173
1150
|
if (approverConfig.approvals !== undefined) {
|
|
1174
1151
|
processNodeProps.approvals = approverConfig.approvals;
|
|
1175
1152
|
}
|
|
1176
|
-
Object.assign(processNodeProps, approverConfig.processProps);
|
|
1153
|
+
Object.assign(processNodeProps, approverConfig.processProps, nodeActions.processProps);
|
|
1177
1154
|
let multiApproverRules;
|
|
1178
1155
|
if (approvalNodeType === 'multiApproval') {
|
|
1179
1156
|
const multiMode = node.approvalMode
|
|
@@ -1220,10 +1197,7 @@ function buildApprovalNode(node, nextNodeId, nameToIdMap, nodeType) {
|
|
|
1220
1197
|
nodeName: componentName,
|
|
1221
1198
|
name: i18n(displayName, titleText[1], displayName),
|
|
1222
1199
|
description: nodeDescription,
|
|
1223
|
-
actions:
|
|
1224
|
-
normalActions: buildActions(),
|
|
1225
|
-
appendActions: buildActions(),
|
|
1226
|
-
},
|
|
1200
|
+
actions: nodeActions.viewActions,
|
|
1227
1201
|
routeRule: routeRule,
|
|
1228
1202
|
};
|
|
1229
1203
|
if (multiApproverRules) {
|
|
@@ -125,6 +125,7 @@ function verifyPlatformView(response, expectedViewJson, expectedFormUuid) {
|
|
|
125
125
|
actual: actualNodes,
|
|
126
126
|
});
|
|
127
127
|
}
|
|
128
|
+
verifyActionSettings(expectedViewJson.schema.children, actualView.schema.children, errors);
|
|
128
129
|
return {
|
|
129
130
|
verificationLevel: errors.length === 0 ? 'PLATFORM_VIEW_VERIFIED' : 'PUBLISHED_UNVERIFIED',
|
|
130
131
|
valid: errors.length === 0,
|
|
@@ -133,6 +134,36 @@ function verifyPlatformView(response, expectedViewJson, expectedFormUuid) {
|
|
|
133
134
|
};
|
|
134
135
|
}
|
|
135
136
|
|
|
137
|
+
/** Compare permissions and append semantics, tolerating platform-added metadata. */
|
|
138
|
+
function verifyActionSettings(expectedNodes, actualNodes, errors, parentPath = '') {
|
|
139
|
+
(expectedNodes || []).forEach((node, index) => {
|
|
140
|
+
const actual = (actualNodes || [])[index];
|
|
141
|
+
const path = parentPath + '/' + index;
|
|
142
|
+
const expectedActions = node.props && node.props.actions;
|
|
143
|
+
const actualActions = actual && actual.props && actual.props.actions;
|
|
144
|
+
if (isPlainObject(expectedActions)) {
|
|
145
|
+
['normalActions', 'appendActions'].forEach(group => {
|
|
146
|
+
if (!Array.isArray(expectedActions[group])) { return; }
|
|
147
|
+
expectedActions[group].forEach(action => {
|
|
148
|
+
const matches = actualActions && Array.isArray(actualActions[group])
|
|
149
|
+
? actualActions[group].filter(item => item && item.action === action.action) : [];
|
|
150
|
+
const found = matches[0];
|
|
151
|
+
const keys = ['hidden'];
|
|
152
|
+
if (group === 'normalActions' && action.action === 'append' && !action.hidden) {
|
|
153
|
+
keys.push('appendPosition', 'appendResult');
|
|
154
|
+
}
|
|
155
|
+
if (matches.length !== 1 || keys.some(key => JSON.stringify(action[key]) !== JSON.stringify(found[key]))) {
|
|
156
|
+
errors.push({ code: 'PROCESS_PLATFORM_VIEW_ACTION_MISMATCH', path, group, action: action.action });
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
if (Array.isArray(node.children)) {
|
|
162
|
+
verifyActionSettings(node.children, actual && actual.children, errors, path);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
136
167
|
module.exports = {
|
|
137
168
|
extractPlatformView,
|
|
138
169
|
verifyPlatformView,
|
package/package.json
CHANGED
package/scripts/postinstall.js
CHANGED
|
@@ -311,7 +311,7 @@ openyida copy
|
|
|
311
311
|
| --- | --- | --- |
|
|
312
312
|
| \`yida-skills/context\` | 登录、退出、组织信息、Schema、fieldId、只读预检 | \`yida-login\`, \`yida-logout\`, \`yida-basic-info\`, \`yida-get-schema\`, \`yida-corp-efficiency\` |
|
|
313
313
|
| \`yida-skills/app\` | 从零搭应用、导航、多语言 | \`yida-app\`, \`yida-create-app\`, \`yida-nav-group\`, \`yida-i18n\` |
|
|
314
|
-
| \`yida-skills/design\` | 完整应用需求分析、产品 PRD、单页 UI
|
|
314
|
+
| \`yida-skills/design\` | 完整应用需求分析、产品 PRD、单页 UI 改造、主页面视觉设计、应用主题色、全局换肤、图片素材 | \`yida-requirement-analysis\`, \`yida-prd\`, \`yida-design\`, \`yida-image-assets\` |
|
|
315
315
|
| \`yida-skills/form\` | 表单字段、公式、校验、业务规则、批量录入、数据记录 | \`yida-create-form-page\`, \`yida-formula\`, \`yida-formula-evaluate\`, \`yida-business-rule\`, \`yida-canvas-table-form\`, \`yida-table-form\`, \`yida-data-management\` |
|
|
316
316
|
| \`yida-skills/process\` | 审批、流程表单、流程规则、代理人 | \`yida-create-process\`, \`yida-process-rule\`, \`yida-agent-center\` |
|
|
317
317
|
| \`yida-skills/page\` | 自定义展示页、YidaCodeCanvas 组件、历史平台 JSX 组件页面维护、发布、导航壳、PPT | \`yida-create-page\`, \`yida-canvas-custom-page\`, \`yida-custom-page\`, \`yida-canvas-data-binding\`, \`yida-canvas-upgrade\`, \`yida-publish-page\`, \`yida-openyida-publish-guard\`, \`yida-density\`, \`yida-nav-shell\`, \`yida-ppt-slider\` |
|
package/yida-skills/SKILL.md
CHANGED
|
@@ -101,7 +101,7 @@ description: >
|
|
|
101
101
|
| --- | --- | --- |
|
|
102
102
|
| `yida-skills/context` | 登录、退出、切换组织、组织版本/容量、Schema、fieldId、执行前检查 | `yida-login`、`yida-logout`、`yida-basic-info`、`yida-get-schema`、`yida-corp-efficiency` |
|
|
103
103
|
| `yida-skills/app` | 从零搭应用、完整系统、应用启停、应用导航、多语言 | `yida-app`、`yida-create-app`、`yida-app-lifecycle`、`yida-nav-group`、`yida-i18n` |
|
|
104
|
-
| `yida-skills/design` | 完整应用需求分析、PRD、视觉设计、单页 UI
|
|
104
|
+
| `yida-skills/design` | 完整应用需求分析、PRD、视觉设计、单页 UI 改造、应用主题色、全局换肤、图片素材 | `yida-requirement-analysis`、`yida-prd`、`yida-design`、`yida-image-assets` |
|
|
105
105
|
| `yida-skills/form` | 表单字段、公式、校验、业务关联规则、批量录入、数据记录 | `yida-create-form-page`、`yida-formula`、`yida-formula-evaluate`、`yida-business-rule`、`yida-canvas-table-form`、`yida-table-form`、`yida-data-management` |
|
|
106
106
|
| `yida-skills/process` | 审批、流程表单、流程规则、节点/分支/字段权限、流程代理 | `yida-create-process`、`yida-process-rule`、`yida-agent-center` |
|
|
107
107
|
| `yida-skills/page` | 自定义展示页、页面源码开发、平台 JSX 组件页面维护、页面发布、页面内导航、PPT 页面 | `yida-create-page`、`yida-canvas-custom-page`、`yida-custom-page`、`yida-canvas-data-binding`、`yida-canvas-upgrade`、`yida-publish-page`、`yida-openyida-publish-guard`、`yida-density`、`yida-nav-shell`、`yida-ppt-slider` |
|
|
@@ -128,7 +128,7 @@ description: >
|
|
|
128
128
|
| 创建自定义展示页资源 | `yida-create-page`,之后交给 `yida-canvas-custom-page` 编写页面源码,再交给 `yida-publish-page` 发布 |
|
|
129
129
|
| 开发表单字段结构 / 增删改字段 | 使用 `yida-create-form-page` 落地字段结构 |
|
|
130
130
|
| 创建带审批的流程表单 | `yida-create-process` |
|
|
131
|
-
|
|
|
131
|
+
| 修改已有流程节点/分支/字段权限,配置加签/转交操作权限 | `yida-process-rule`;加签/转交先读其 `references/approval-actions.md` |
|
|
132
132
|
| 查字段 ID / 保存 Schema 证据 | `yida-get-schema`;凡涉及 fieldId 的数据、流程、公式、页面代码先取证 |
|
|
133
133
|
| 改表单数据记录 | `yida-data-management`,不是 `yida-create-form-page` |
|
|
134
134
|
| 配字段默认值、计算、校验 | `yida-formula`;静态检查用 `yida-formula-evaluate` |
|
|
@@ -145,6 +145,7 @@ description: >
|
|
|
145
145
|
| 批量录入、表格填写、多行编辑 | 默认 `yida-canvas-table-form`;已检测到平台 JSX 组件页面、native 页面或存量源码使用 `this.utils.yida.saveFormData` 时用 `yida-table-form` |
|
|
146
146
|
| 页面视觉方向、页面美化、去 AI 味 | `yida-design` 只产出或更新 `prd/<项目名>/design.md`;若业务/页面契约也变化,由 `yida-prd` 更新 `prd.md`;实现阶段默认交给 `yida-canvas-custom-page` |
|
|
147
147
|
| 应用级主题、品牌色、全局换肤 | `yida-design` |
|
|
148
|
+
| 图片需求、搜图、生图 | `yida-image-assets`;完整应用按 `design.md.assetStrategy` 加载 |
|
|
148
149
|
| 平台左侧导航树分组/排序 | `yida-nav-group` |
|
|
149
150
|
| 应用导航隐藏后自绘导航壳 | `yida-nav-shell` |
|
|
150
151
|
| 普通报表/统计 | `yida-report` |
|
|
@@ -64,7 +64,7 @@ Plan 模式只读取 `workflow/step-1-resource-context.md`、`workflow/step-2-de
|
|
|
64
64
|
| 4 | [创建或更新业务资源](workflow/step-4-forms-processes.md) | 执行 `use_skill("yida-create-form-page")`;按 PRD 执行 `use_skill("yida-create-process")`、`use_skill("yida-get-schema")`、`use_skill("yida-report")` 和 `use_skill("yida-integration")` | 真实 `formUuid`、`processCode`、必要 `fieldId/reportId` |
|
|
65
65
|
| 5 | [写入初始表单数据](workflow/step-5-seed-records.md) | 执行 `use_skill("yida-data-management")`,为核心普通表单写入 1-3 条业务化 seed records 并 query 抽查 | 真实表单记录或明确跳过原因 |
|
|
66
66
|
| 6 | [创建或复用主页面](workflow/step-6-main-page.md) | 已有 display 页面直接复用;缺少主页面且允许创建时执行 `use_skill("yida-create-page")` | 真实主页面 `formUuid` |
|
|
67
|
-
| 7 | [编写或更新页面](workflow/step-7-page-code.md) |
|
|
67
|
+
| 7 | [编写或更新页面](workflow/step-7-page-code.md) | 按 `design.md.assetStrategy` 加载素材、页面、看板和数据绑定技能 | 素材状态明确;页面源码和 dataBinding 通过校验 |
|
|
68
68
|
| 8 | [发布页面并排序导航](workflow/step-8-publish-navigation.md) | 执行 `use_skill("yida-publish-page")`,发布本轮源码到主页面并执行轻量导航排序 | 已发布主页面 URL |
|
|
69
69
|
| 9 | [输出与收尾](workflow/step-9-output-finish.md) | 核对完成条件,按业务语言输出结果 | 2-3 句业务总结 + 一组应用访问入口 |
|
|
70
70
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
## 2.0 先分析并确认需求
|
|
10
10
|
|
|
11
|
-
调用 `yida-requirement-analysis`,按 [需求分析与首次搭建确认](../../yida-requirement-analysis/workflow/prepare-brief.md) 整理来源、复用资源及用户已有计划,在同一轮一次性确认尚未明确的 Fast / Plan
|
|
11
|
+
调用 `yida-requirement-analysis`,按 [需求分析与首次搭建确认](../../yida-requirement-analysis/workflow/prepare-brief.md) 整理来源、复用资源及用户已有计划,在同一轮一次性确认尚未明确的 Fast / Plan、业务模块、页面与表单、导航归属及风格。导航 `ask_human` 仅提供“宜搭原生导航”和“自定义导航”两个选项,原生导航就是平台导航,并按 [导航选项说明](../../yida-requirement-analysis/workflow/prepare-brief.md#导航选项说明) 备注实现方式,不标记“推荐”。顶部、侧边、L 型等布局在用户所选归属内根据场景确定,不询问布局或样式;用户已明确的要求优先,后续阶段复用归属选择和布局依据。首次搭建在必要回答写回、`intake.confirmed=true` 后继续。
|
|
12
12
|
|
|
13
13
|
回答齐全后直接保存内部需求记录并进入 2.1;不把“生成需求简报”列为独立任务,不再扩写或展示简报请用户确认。已有确认记录且需求未变化时直接复用。记录粒度、保存和校验规则统一遵守上述需求分析流程。
|
|
14
14
|
|
|
@@ -50,6 +50,16 @@ Plan 分支从已加载 `yida-app` 的 Available Files 读取精确路径 `workf
|
|
|
50
50
|
|
|
51
51
|
校验未通过时 Step 2 未完成,不得进入资源创建。校验通过后,后续页面实现以 `prd.md` 和 `design.md` 为准;`page-spec.json` 只用于把要求传给页面实现阶段。
|
|
52
52
|
|
|
53
|
+
## 2.4 条件式素材分支
|
|
54
|
+
|
|
55
|
+
`design.md.assetStrategy` 按页面分级:
|
|
56
|
+
|
|
57
|
+
- 商品目录、品牌、营销和媒体展示页通常为 `required`;
|
|
58
|
+
- 门户、工作台、档案、知识库和引导页有图片槽位时为 `beneficial`;
|
|
59
|
+
- 表单、审批、台账、设置和库存流水默认 `none`。
|
|
60
|
+
|
|
61
|
+
存在 `required` 或带槽位的 `beneficial` 时启动 `yida-image-assets`,先选图并保存 `prd/<项目名>/manifest-draft.json`。宜搭附件上传需要真实 `appType`;已有应用可直接上传,否则等 Step 3 创建应用后再落地,不因缺少 appType 阻塞应用创建。素材只阻塞使用它的页面;Step 7 通过 `--design design.md --app-type <真实appType>` 上传并校验,以输出清单的页面级状态判断能否继续。
|
|
62
|
+
|
|
53
63
|
## 主题文件实现指令
|
|
54
64
|
|
|
55
65
|
在设计中确定配色、导航明暗和布局。未禁止 `theme-file` 时,Plan 使用 CLI 返回的 `outputs.theme`,Fast 按 [主题文件生成与更新](../../yida-design/workflow/output-design.md#cli-token-契约fast--plan-共用) 准备主题 CSS;用户确认计划或主题后即可启动 CSS 生成,不等待表单或页面开发。Plan 已生成当前版本的 CSS 时直接复用。拿到真实 appType 后,在应用级配置同一份主题文件,与表单创建和页面开发并行;页面组件按已确认契约消费主题 token。若 `theme-file` 被禁止,跳过生成、复制、修改和上传,沿用现有平台主题并在交付中说明未更改主题。详见 [主题与业务资源的依赖](parallel-work.md#主题与业务资源的依赖)。
|