@sun-asterisk/sungen 3.2.32 → 3.2.34-beta.1
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/dist/cli/commands/audit.d.ts +5 -0
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/audit.js +64 -11
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/capability.d.ts.map +1 -1
- package/dist/cli/commands/capability.js +40 -18
- package/dist/cli/commands/capability.js.map +1 -1
- package/dist/cli/commands/changed.d.ts.map +1 -1
- package/dist/cli/commands/changed.js +2 -3
- package/dist/cli/commands/changed.js.map +1 -1
- package/dist/cli/commands/dashboard.d.ts.map +1 -1
- package/dist/cli/commands/dashboard.js +2 -28
- package/dist/cli/commands/dashboard.js.map +1 -1
- package/dist/cli/commands/defect.d.ts +7 -0
- package/dist/cli/commands/defect.d.ts.map +1 -0
- package/dist/cli/commands/defect.js +68 -0
- package/dist/cli/commands/defect.js.map +1 -0
- package/dist/cli/commands/delivery.d.ts.map +1 -1
- package/dist/cli/commands/delivery.js +113 -59
- package/dist/cli/commands/delivery.js.map +1 -1
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +14 -7
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/commands/results-merge.d.ts +9 -0
- package/dist/cli/commands/results-merge.d.ts.map +1 -1
- package/dist/cli/commands/results-merge.js +9 -12
- package/dist/cli/commands/results-merge.js.map +1 -1
- package/dist/cli/commands/results-sanitize.d.ts.map +1 -1
- package/dist/cli/commands/results-sanitize.js +2 -13
- package/dist/cli/commands/results-sanitize.js.map +1 -1
- package/dist/cli/commands/select.d.ts +12 -0
- package/dist/cli/commands/select.d.ts.map +1 -0
- package/dist/cli/commands/select.js +122 -0
- package/dist/cli/commands/select.js.map +1 -0
- package/dist/cli/commands/triage.d.ts +7 -0
- package/dist/cli/commands/triage.d.ts.map +1 -0
- package/dist/cli/commands/triage.js +98 -0
- package/dist/cli/commands/triage.js.map +1 -0
- package/dist/cli/commands/update.d.ts.map +1 -1
- package/dist/cli/commands/update.js +3 -0
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/commands/viewpoint.d.ts +7 -0
- package/dist/cli/commands/viewpoint.d.ts.map +1 -0
- package/dist/cli/commands/viewpoint.js +70 -0
- package/dist/cli/commands/viewpoint.js.map +1 -0
- package/dist/cli/index.js +13 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/dashboard/snapshot-builder.d.ts.map +1 -1
- package/dist/dashboard/snapshot-builder.js +6 -10
- package/dist/dashboard/snapshot-builder.js.map +1 -1
- package/dist/dashboard/templates/index.html +1 -1
- package/dist/dashboard/types.d.ts +1 -0
- package/dist/dashboard/types.d.ts.map +1 -1
- package/dist/exporters/csv-exporter.d.ts +4 -0
- package/dist/exporters/csv-exporter.d.ts.map +1 -1
- package/dist/exporters/csv-exporter.js +12 -11
- package/dist/exporters/csv-exporter.js.map +1 -1
- package/dist/exporters/feature-parser.d.ts +29 -0
- package/dist/exporters/feature-parser.d.ts.map +1 -1
- package/dist/exporters/feature-parser.js +44 -1
- package/dist/exporters/feature-parser.js.map +1 -1
- package/dist/exporters/json-exporter.d.ts.map +1 -1
- package/dist/exporters/json-exporter.js +7 -0
- package/dist/exporters/json-exporter.js.map +1 -1
- package/dist/exporters/locale-variants.d.ts +7 -1
- package/dist/exporters/locale-variants.d.ts.map +1 -1
- package/dist/exporters/locale-variants.js +23 -16
- package/dist/exporters/locale-variants.js.map +1 -1
- package/dist/exporters/manual-hybrid-oracle.d.ts +54 -0
- package/dist/exporters/manual-hybrid-oracle.d.ts.map +1 -0
- package/dist/exporters/manual-hybrid-oracle.js +114 -0
- package/dist/exporters/manual-hybrid-oracle.js.map +1 -0
- package/dist/exporters/matrix/build.d.ts.map +1 -1
- package/dist/exporters/matrix/build.js +68 -19
- package/dist/exporters/matrix/build.js.map +1 -1
- package/dist/exporters/matrix/carry-manual-results.d.ts +89 -0
- package/dist/exporters/matrix/carry-manual-results.d.ts.map +1 -0
- package/dist/exporters/matrix/carry-manual-results.js +302 -0
- package/dist/exporters/matrix/carry-manual-results.js.map +1 -0
- package/dist/exporters/matrix/export.d.ts +9 -1
- package/dist/exporters/matrix/export.d.ts.map +1 -1
- package/dist/exporters/matrix/export.js +21 -3
- package/dist/exporters/matrix/export.js.map +1 -1
- package/dist/exporters/matrix/gates.js +6 -0
- package/dist/exporters/matrix/gates.js.map +1 -1
- package/dist/exporters/matrix/render-csv.js +1 -1
- package/dist/exporters/matrix/render-csv.js.map +1 -1
- package/dist/exporters/matrix/render-testcase-sheet.d.ts.map +1 -1
- package/dist/exporters/matrix/render-testcase-sheet.js +10 -4
- package/dist/exporters/matrix/render-testcase-sheet.js.map +1 -1
- package/dist/exporters/matrix/render-xlsx.d.ts.map +1 -1
- package/dist/exporters/matrix/render-xlsx.js +3 -0
- package/dist/exporters/matrix/render-xlsx.js.map +1 -1
- package/dist/exporters/matrix/types.d.ts +13 -1
- package/dist/exporters/matrix/types.d.ts.map +1 -1
- package/dist/exporters/matrix/types.js.map +1 -1
- package/dist/exporters/matrix/wording.d.ts +8 -1
- package/dist/exporters/matrix/wording.d.ts.map +1 -1
- package/dist/exporters/matrix/wording.js +37 -2
- package/dist/exporters/matrix/wording.js.map +1 -1
- package/dist/exporters/playwright-report-parser.d.ts.map +1 -1
- package/dist/exporters/playwright-report-parser.js +1 -0
- package/dist/exporters/playwright-report-parser.js.map +1 -1
- package/dist/exporters/run-environment.d.ts +32 -0
- package/dist/exporters/run-environment.d.ts.map +1 -0
- package/dist/exporters/run-environment.js +125 -0
- package/dist/exporters/run-environment.js.map +1 -0
- package/dist/exporters/scenario-merger.d.ts +18 -0
- package/dist/exporters/scenario-merger.d.ts.map +1 -1
- package/dist/exporters/scenario-merger.js +49 -3
- package/dist/exporters/scenario-merger.js.map +1 -1
- package/dist/exporters/test-data-resolver.d.ts +0 -4
- package/dist/exporters/test-data-resolver.d.ts.map +1 -1
- package/dist/exporters/test-data-resolver.js +0 -7
- package/dist/exporters/test-data-resolver.js.map +1 -1
- package/dist/exporters/types.d.ts +5 -0
- package/dist/exporters/types.d.ts.map +1 -1
- package/dist/exporters/xlsx-exporter.d.ts +2 -0
- package/dist/exporters/xlsx-exporter.d.ts.map +1 -1
- package/dist/exporters/xlsx-exporter.js +7 -2
- package/dist/exporters/xlsx-exporter.js.map +1 -1
- package/dist/generators/gherkin-parser/index.d.ts +11 -4
- package/dist/generators/gherkin-parser/index.d.ts.map +1 -1
- package/dist/generators/gherkin-parser/index.js +49 -19
- package/dist/generators/gherkin-parser/index.js.map +1 -1
- package/dist/generators/test-generator/adapters/adapter-interface.d.ts +4 -0
- package/dist/generators/test-generator/adapters/adapter-interface.d.ts.map +1 -1
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/reinstall-app-action.hbs +2 -2
- package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/label-value-assertion.hbs +8 -2
- package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/visible-with-role-variable-assertion.hbs +7 -3
- package/dist/generators/test-generator/adapters/appium/templates/test-file.hbs +68 -4
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/click-select-action.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/select-action.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/label-value-assertion.hbs +7 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-role-variable-assertion.hbs +8 -4
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/pick-option.hbs +13 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/url-assertion.hbs +5 -1
- package/dist/generators/test-generator/adapters/playwright/templates/test-file.hbs +16 -0
- package/dist/generators/test-generator/code-generator.d.ts +2 -1
- package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
- package/dist/generators/test-generator/code-generator.js +90 -5
- package/dist/generators/test-generator/code-generator.js.map +1 -1
- package/dist/generators/test-generator/diagnostics.d.ts +36 -5
- package/dist/generators/test-generator/diagnostics.d.ts.map +1 -1
- package/dist/generators/test-generator/diagnostics.js +35 -4
- package/dist/generators/test-generator/diagnostics.js.map +1 -1
- package/dist/generators/test-generator/patterns/index.d.ts +12 -2
- package/dist/generators/test-generator/patterns/index.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/index.js +15 -9
- package/dist/generators/test-generator/patterns/index.js.map +1 -1
- package/dist/generators/test-generator/patterns/types.d.ts +15 -0
- package/dist/generators/test-generator/patterns/types.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/with-parent-scope.d.ts +5 -0
- package/dist/generators/test-generator/patterns/with-parent-scope.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/with-parent-scope.js +6 -0
- package/dist/generators/test-generator/patterns/with-parent-scope.js.map +1 -1
- package/dist/generators/test-generator/step-mapper.d.ts +46 -0
- package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
- package/dist/generators/test-generator/step-mapper.js +84 -9
- package/dist/generators/test-generator/step-mapper.js.map +1 -1
- package/dist/generators/test-generator/utils/data-resolver.d.ts +25 -0
- package/dist/generators/test-generator/utils/data-resolver.d.ts.map +1 -1
- package/dist/generators/test-generator/utils/data-resolver.js +39 -8
- package/dist/generators/test-generator/utils/data-resolver.js.map +1 -1
- package/dist/generators/test-generator/utils/selector-entry-fields.d.ts.map +1 -1
- package/dist/generators/test-generator/utils/selector-entry-fields.js +1 -0
- package/dist/generators/test-generator/utils/selector-entry-fields.js.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.d.ts +37 -4
- package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.js +212 -79
- package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
- package/dist/harness/audit.d.ts +3 -0
- package/dist/harness/audit.d.ts.map +1 -1
- package/dist/harness/audit.js +60 -19
- package/dist/harness/audit.js.map +1 -1
- package/dist/harness/capability.d.ts +7 -1
- package/dist/harness/capability.d.ts.map +1 -1
- package/dist/harness/capability.js +15 -12
- package/dist/harness/capability.js.map +1 -1
- package/dist/harness/catalog/universal-viewpoints.yaml +5 -5
- package/dist/harness/config-file.d.ts +17 -0
- package/dist/harness/config-file.d.ts.map +1 -0
- package/dist/harness/config-file.js +100 -0
- package/dist/harness/config-file.js.map +1 -0
- package/dist/harness/counted-assertions.d.ts +2 -0
- package/dist/harness/counted-assertions.d.ts.map +1 -0
- package/dist/harness/counted-assertions.js +38 -0
- package/dist/harness/counted-assertions.js.map +1 -0
- package/dist/harness/data-driven-lint.d.ts.map +1 -1
- package/dist/harness/data-driven-lint.js +69 -27
- package/dist/harness/data-driven-lint.js.map +1 -1
- package/dist/harness/defect-draft.d.ts +14 -0
- package/dist/harness/defect-draft.d.ts.map +1 -0
- package/dist/harness/defect-draft.js +143 -0
- package/dist/harness/defect-draft.js.map +1 -0
- package/dist/harness/defects.d.ts +24 -0
- package/dist/harness/defects.d.ts.map +1 -0
- package/dist/harness/defects.js +118 -0
- package/dist/harness/defects.js.map +1 -0
- package/dist/harness/depth-lint.d.ts.map +1 -1
- package/dist/harness/depth-lint.js +2 -1
- package/dist/harness/depth-lint.js.map +1 -1
- package/dist/harness/flow-check.d.ts.map +1 -1
- package/dist/harness/flow-check.js +6 -2
- package/dist/harness/flow-check.js.map +1 -1
- package/dist/harness/keyword-match.d.ts +59 -0
- package/dist/harness/keyword-match.d.ts.map +1 -0
- package/dist/harness/keyword-match.js +86 -0
- package/dist/harness/keyword-match.js.map +1 -0
- package/dist/harness/manifest.d.ts.map +1 -1
- package/dist/harness/manifest.js +2 -2
- package/dist/harness/manifest.js.map +1 -1
- package/dist/harness/next-step.d.ts +2 -4
- package/dist/harness/next-step.d.ts.map +1 -1
- package/dist/harness/next-step.js +50 -5
- package/dist/harness/next-step.js.map +1 -1
- package/dist/harness/parse.d.ts +45 -0
- package/dist/harness/parse.d.ts.map +1 -1
- package/dist/harness/parse.js +142 -24
- package/dist/harness/parse.js.map +1 -1
- package/dist/harness/perf.d.ts +7 -1
- package/dist/harness/perf.d.ts.map +1 -1
- package/dist/harness/perf.js +13 -10
- package/dist/harness/perf.js.map +1 -1
- package/dist/harness/quality-gates.d.ts +9 -2
- package/dist/harness/quality-gates.d.ts.map +1 -1
- package/dist/harness/quality-gates.js +22 -8
- package/dist/harness/quality-gates.js.map +1 -1
- package/dist/harness/query-catalog.js +0 -0
- package/dist/harness/query-catalog.js.map +1 -1
- package/dist/harness/read-text.d.ts +21 -0
- package/dist/harness/read-text.d.ts.map +1 -1
- package/dist/harness/read-text.js +32 -1
- package/dist/harness/read-text.js.map +1 -1
- package/dist/harness/script-check.d.ts.map +1 -1
- package/dist/harness/script-check.js +7 -1
- package/dist/harness/script-check.js.map +1 -1
- package/dist/harness/secret-scan.d.ts +27 -1
- package/dist/harness/secret-scan.d.ts.map +1 -1
- package/dist/harness/secret-scan.js +57 -4
- package/dist/harness/secret-scan.js.map +1 -1
- package/dist/harness/select-by-ids.d.ts +31 -0
- package/dist/harness/select-by-ids.d.ts.map +1 -0
- package/dist/harness/select-by-ids.js +106 -0
- package/dist/harness/select-by-ids.js.map +1 -0
- package/dist/harness/sensors.d.ts +20 -1
- package/dist/harness/sensors.d.ts.map +1 -1
- package/dist/harness/sensors.js +133 -39
- package/dist/harness/sensors.js.map +1 -1
- package/dist/harness/spec-branches.d.ts +0 -18
- package/dist/harness/spec-branches.d.ts.map +1 -1
- package/dist/harness/spec-branches.js +24 -3
- package/dist/harness/spec-branches.js.map +1 -1
- package/dist/harness/spec-coverage.d.ts.map +1 -1
- package/dist/harness/spec-coverage.js +14 -4
- package/dist/harness/spec-coverage.js.map +1 -1
- package/dist/harness/triage-signals.d.ts +20 -0
- package/dist/harness/triage-signals.d.ts.map +1 -0
- package/dist/harness/triage-signals.js +30 -0
- package/dist/harness/triage-signals.js.map +1 -0
- package/dist/harness/triage-unit.d.ts +23 -0
- package/dist/harness/triage-unit.d.ts.map +1 -0
- package/dist/harness/triage-unit.js +142 -0
- package/dist/harness/triage-unit.js.map +1 -0
- package/dist/harness/triage.d.ts +28 -0
- package/dist/harness/triage.d.ts.map +1 -0
- package/dist/harness/triage.js +99 -0
- package/dist/harness/triage.js.map +1 -0
- package/dist/harness/ui-inventory.d.ts +40 -0
- package/dist/harness/ui-inventory.d.ts.map +1 -0
- package/dist/harness/ui-inventory.js +191 -0
- package/dist/harness/ui-inventory.js.map +1 -0
- package/dist/harness/viewpoint-baseline.d.ts.map +1 -1
- package/dist/harness/viewpoint-baseline.js +7 -1
- package/dist/harness/viewpoint-baseline.js.map +1 -1
- package/dist/harness/viewpoint-draft-header.d.ts +7 -0
- package/dist/harness/viewpoint-draft-header.d.ts.map +1 -0
- package/dist/harness/viewpoint-draft-header.js +100 -0
- package/dist/harness/viewpoint-draft-header.js.map +1 -0
- package/dist/harness/viewpoint-ledger.d.ts +13 -3
- package/dist/harness/viewpoint-ledger.d.ts.map +1 -1
- package/dist/harness/viewpoint-ledger.js +106 -19
- package/dist/harness/viewpoint-ledger.js.map +1 -1
- package/dist/harness/viewpoint-mode.d.ts +9 -0
- package/dist/harness/viewpoint-mode.d.ts.map +1 -0
- package/dist/harness/viewpoint-mode.js +52 -0
- package/dist/harness/viewpoint-mode.js.map +1 -0
- package/dist/harness/viewpoint-priority.d.ts +19 -0
- package/dist/harness/viewpoint-priority.d.ts.map +1 -0
- package/dist/harness/viewpoint-priority.js +36 -0
- package/dist/harness/viewpoint-priority.js.map +1 -0
- package/dist/harness/viewpoint-review-open.d.ts +6 -0
- package/dist/harness/viewpoint-review-open.d.ts.map +1 -0
- package/dist/harness/viewpoint-review-open.js +90 -0
- package/dist/harness/viewpoint-review-open.js.map +1 -0
- package/dist/harness/viewpoint-scan-refs.d.ts +50 -0
- package/dist/harness/viewpoint-scan-refs.d.ts.map +1 -0
- package/dist/harness/viewpoint-scan-refs.js +200 -0
- package/dist/harness/viewpoint-scan-refs.js.map +1 -0
- package/dist/harness/viewpoint-scan.d.ts +41 -0
- package/dist/harness/viewpoint-scan.d.ts.map +1 -0
- package/dist/harness/viewpoint-scan.js +118 -0
- package/dist/harness/viewpoint-scan.js.map +1 -0
- package/dist/harness/write-atomic.d.ts +2 -0
- package/dist/harness/write-atomic.d.ts.map +1 -0
- package/dist/harness/write-atomic.js +62 -0
- package/dist/harness/write-atomic.js.map +1 -0
- package/dist/orchestrator/ai-skills/writer.d.ts.map +1 -1
- package/dist/orchestrator/ai-skills/writer.js +15 -7
- package/dist/orchestrator/ai-skills/writer.js.map +1 -1
- package/dist/orchestrator/assets-drift.d.ts.map +1 -1
- package/dist/orchestrator/assets-drift.js +11 -6
- package/dist/orchestrator/assets-drift.js.map +1 -1
- package/dist/orchestrator/flow-manager.d.ts +0 -1
- package/dist/orchestrator/flow-manager.d.ts.map +1 -1
- package/dist/orchestrator/flow-manager.js +3 -52
- package/dist/orchestrator/flow-manager.js.map +1 -1
- package/dist/orchestrator/project-deps-sync.d.ts.map +1 -1
- package/dist/orchestrator/project-deps-sync.js +22 -1
- package/dist/orchestrator/project-deps-sync.js.map +1 -1
- package/dist/orchestrator/project-initializer.d.ts +8 -0
- package/dist/orchestrator/project-initializer.d.ts.map +1 -1
- package/dist/orchestrator/project-initializer.js +49 -7
- package/dist/orchestrator/project-initializer.js.map +1 -1
- package/dist/orchestrator/screen-manager.d.ts.map +1 -1
- package/dist/orchestrator/screen-manager.js +8 -62
- package/dist/orchestrator/screen-manager.js.map +1 -1
- package/dist/orchestrator/security-overrides-catalog.d.ts +39 -0
- package/dist/orchestrator/security-overrides-catalog.d.ts.map +1 -0
- package/dist/orchestrator/security-overrides-catalog.js +63 -0
- package/dist/orchestrator/security-overrides-catalog.js.map +1 -0
- package/dist/orchestrator/security-overrides.d.ts +51 -0
- package/dist/orchestrator/security-overrides.d.ts.map +1 -0
- package/dist/orchestrator/security-overrides.js +165 -0
- package/dist/orchestrator/security-overrides.js.map +1 -0
- package/dist/orchestrator/templates/ai-src/agents/discovery.md +11 -3
- package/dist/orchestrator/templates/ai-src/agents/reviewer.md +8 -0
- package/dist/orchestrator/templates/ai-src/commands/create-test.md +32 -24
- package/dist/orchestrator/templates/ai-src/commands/review.md +2 -2
- package/dist/orchestrator/templates/ai-src/commands/run-test.md +78 -15
- package/dist/orchestrator/templates/ai-src/skills/sungen-capture/mode-local.md +2 -2
- package/dist/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +14 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +25 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +26 -8
- package/dist/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +5 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +58 -14
- package/dist/orchestrator/templates/ai-src/skills/sungen-selector-keys/SKILL.md +13 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +42 -2
- package/dist/orchestrator/templates/ai-src/skills/sungen-tc-review/SKILL.md +7 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-viewpoint/SKILL.md +18 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-viewpoint/review-checklist.md +63 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-viewpoint/viewpoint-template.md +158 -0
- package/dist/orchestrator/templates/playwright.config.ts +4 -2
- package/dist/orchestrator/templates/specs-locale-fixture.ts +21 -9
- package/dist/orchestrator/templates/specs-pw-shape-reporter.ts +0 -0
- package/dist/orchestrator/templates/specs-url-assert.d.ts +17 -1
- package/dist/orchestrator/templates/specs-url-assert.d.ts.map +1 -1
- package/dist/orchestrator/templates/specs-url-assert.js +38 -4
- package/dist/orchestrator/templates/specs-url-assert.js.map +1 -1
- package/dist/orchestrator/templates/specs-url-assert.ts +47 -4
- package/dist/orchestrator/templates/wdio.conf.ts +24 -1
- package/dist/orchestrator/trace-mode-install.d.ts +14 -0
- package/dist/orchestrator/trace-mode-install.d.ts.map +1 -0
- package/dist/orchestrator/trace-mode-install.js +132 -0
- package/dist/orchestrator/trace-mode-install.js.map +1 -0
- package/dist/orchestrator/viewpoint-pattern-catalog.d.ts +23 -0
- package/dist/orchestrator/viewpoint-pattern-catalog.d.ts.map +1 -0
- package/dist/orchestrator/viewpoint-pattern-catalog.js +48 -0
- package/dist/orchestrator/viewpoint-pattern-catalog.js.map +1 -0
- package/dist/orchestrator/viewpoint-scaffold.d.ts +3 -0
- package/dist/orchestrator/viewpoint-scaffold.d.ts.map +1 -0
- package/dist/orchestrator/viewpoint-scaffold.js +70 -0
- package/dist/orchestrator/viewpoint-scaffold.js.map +1 -0
- package/package.json +3 -3
- package/src/cli/commands/audit.ts +59 -12
- package/src/cli/commands/capability.ts +54 -19
- package/src/cli/commands/changed.ts +2 -4
- package/src/cli/commands/dashboard.ts +1 -26
- package/src/cli/commands/defect.ts +49 -0
- package/src/cli/commands/delivery.ts +106 -56
- package/src/cli/commands/generate.ts +15 -7
- package/src/cli/commands/results-merge.ts +9 -9
- package/src/cli/commands/results-sanitize.ts +2 -9
- package/src/cli/commands/select.ts +88 -0
- package/src/cli/commands/triage.ts +57 -0
- package/src/cli/commands/update.ts +3 -0
- package/src/cli/commands/viewpoint.ts +58 -0
- package/src/cli/index.ts +13 -2
- package/src/dashboard/snapshot-builder.ts +6 -8
- package/src/dashboard/templates/index.html +1 -1
- package/src/dashboard/types.ts +1 -0
- package/src/exporters/csv-exporter.ts +12 -11
- package/src/exporters/feature-parser.ts +44 -2
- package/src/exporters/json-exporter.ts +6 -1
- package/src/exporters/locale-variants.ts +23 -17
- package/src/exporters/manual-hybrid-oracle.ts +112 -0
- package/src/exporters/matrix/build.ts +71 -19
- package/src/exporters/matrix/carry-manual-results.ts +292 -0
- package/src/exporters/matrix/export.ts +24 -4
- package/src/exporters/matrix/gates.ts +6 -0
- package/src/exporters/matrix/render-csv.ts +1 -1
- package/src/exporters/matrix/render-testcase-sheet.ts +10 -4
- package/src/exporters/matrix/render-xlsx.ts +3 -0
- package/src/exporters/matrix/types.ts +13 -1
- package/src/exporters/matrix/wording.ts +36 -2
- package/src/exporters/playwright-report-parser.ts +1 -0
- package/src/exporters/run-environment.ts +89 -0
- package/src/exporters/scenario-merger.ts +51 -5
- package/src/exporters/test-data-resolver.ts +0 -6
- package/src/exporters/types.ts +5 -0
- package/src/exporters/xlsx-exporter.ts +7 -2
- package/src/generators/gherkin-parser/index.ts +50 -18
- package/src/generators/test-generator/adapters/adapter-interface.ts +6 -2
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/reinstall-app-action.hbs +2 -2
- package/src/generators/test-generator/adapters/appium/templates/steps/assertions/label-value-assertion.hbs +8 -2
- package/src/generators/test-generator/adapters/appium/templates/steps/assertions/visible-with-role-variable-assertion.hbs +7 -3
- package/src/generators/test-generator/adapters/appium/templates/test-file.hbs +68 -4
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/click-select-action.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/select-action.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/label-value-assertion.hbs +7 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-role-variable-assertion.hbs +8 -4
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/pick-option.hbs +13 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/url-assertion.hbs +5 -1
- package/src/generators/test-generator/adapters/playwright/templates/test-file.hbs +16 -0
- package/src/generators/test-generator/code-generator.ts +77 -5
- package/src/generators/test-generator/diagnostics.ts +36 -5
- package/src/generators/test-generator/patterns/index.ts +15 -8
- package/src/generators/test-generator/patterns/types.ts +15 -0
- package/src/generators/test-generator/patterns/with-parent-scope.ts +6 -0
- package/src/generators/test-generator/step-mapper.ts +90 -8
- package/src/generators/test-generator/utils/data-resolver.ts +41 -12
- package/src/generators/test-generator/utils/selector-entry-fields.ts +1 -0
- package/src/generators/test-generator/utils/selector-resolver.ts +238 -82
- package/src/harness/audit.ts +69 -24
- package/src/harness/capability.ts +23 -12
- package/src/harness/catalog/universal-viewpoints.yaml +5 -5
- package/src/harness/config-file.ts +66 -0
- package/src/harness/counted-assertions.ts +33 -0
- package/src/harness/data-driven-lint.ts +82 -24
- package/src/harness/defect-draft.ts +115 -0
- package/src/harness/defects.ts +94 -0
- package/src/harness/depth-lint.ts +2 -1
- package/src/harness/flow-check.ts +6 -2
- package/src/harness/keyword-match.ts +85 -0
- package/src/harness/manifest.ts +2 -2
- package/src/harness/next-step.ts +47 -5
- package/src/harness/parse.ts +151 -27
- package/src/harness/perf.ts +15 -7
- package/src/harness/quality-gates.ts +22 -8
- package/src/harness/query-catalog.ts +0 -0
- package/src/harness/read-text.ts +32 -1
- package/src/harness/script-check.ts +7 -1
- package/src/harness/secret-scan.ts +60 -4
- package/src/harness/select-by-ids.ts +83 -0
- package/src/harness/sensors.ts +141 -40
- package/src/harness/spec-branches.ts +6 -3
- package/src/harness/spec-coverage.ts +14 -4
- package/src/harness/triage-signals.ts +46 -0
- package/src/harness/triage-unit.ts +113 -0
- package/src/harness/triage.ts +127 -0
- package/src/harness/ui-inventory.ts +164 -0
- package/src/harness/viewpoint-baseline.ts +7 -1
- package/src/harness/viewpoint-draft-header.ts +55 -0
- package/src/harness/viewpoint-ledger.ts +113 -25
- package/src/harness/viewpoint-mode.ts +49 -0
- package/src/harness/viewpoint-priority.ts +38 -0
- package/src/harness/viewpoint-review-open.ts +51 -0
- package/src/harness/viewpoint-scan-refs.ts +154 -0
- package/src/harness/viewpoint-scan.ts +111 -0
- package/src/harness/write-atomic.ts +22 -0
- package/src/orchestrator/ai-skills/writer.ts +18 -3
- package/src/orchestrator/assets-drift.ts +10 -5
- package/src/orchestrator/flow-manager.ts +3 -53
- package/src/orchestrator/project-deps-sync.ts +23 -1
- package/src/orchestrator/project-initializer.ts +54 -6
- package/src/orchestrator/screen-manager.ts +7 -61
- package/src/orchestrator/security-overrides-catalog.ts +69 -0
- package/src/orchestrator/security-overrides.ts +149 -0
- package/src/orchestrator/templates/ai-src/agents/discovery.md +11 -3
- package/src/orchestrator/templates/ai-src/agents/reviewer.md +8 -0
- package/src/orchestrator/templates/ai-src/commands/create-test.md +32 -24
- package/src/orchestrator/templates/ai-src/commands/review.md +2 -2
- package/src/orchestrator/templates/ai-src/commands/run-test.md +78 -15
- package/src/orchestrator/templates/ai-src/skills/sungen-capture/mode-local.md +2 -2
- package/src/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +14 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +25 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +26 -8
- package/src/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +5 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +58 -14
- package/src/orchestrator/templates/ai-src/skills/sungen-selector-keys/SKILL.md +13 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +42 -2
- package/src/orchestrator/templates/ai-src/skills/sungen-tc-review/SKILL.md +7 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-viewpoint/SKILL.md +18 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-viewpoint/review-checklist.md +63 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-viewpoint/viewpoint-template.md +158 -0
- package/src/orchestrator/templates/playwright.config.ts +4 -2
- package/src/orchestrator/templates/specs-locale-fixture.ts +21 -9
- package/src/orchestrator/templates/specs-pw-shape-reporter.ts +0 -0
- package/src/orchestrator/templates/specs-url-assert.ts +47 -4
- package/src/orchestrator/templates/wdio.conf.ts +24 -1
- package/src/orchestrator/trace-mode-install.ts +94 -0
- package/src/orchestrator/viewpoint-pattern-catalog.ts +61 -0
- package/src/orchestrator/viewpoint-scaffold.ts +36 -0
|
@@ -17,6 +17,8 @@ import {
|
|
|
17
17
|
installMobileDriver,
|
|
18
18
|
} from './mobile-runtime-scaffolder';
|
|
19
19
|
import { emitAppiumEnvironment, runAppiumEnvironmentSetup, appiumEnvironmentRerunCommand } from './appium-environment-setup';
|
|
20
|
+
import { ensureSecurityOverrides, reportSecurityOverrides } from './security-overrides';
|
|
21
|
+
import { readTextFile } from '../harness/read-text';
|
|
20
22
|
|
|
21
23
|
export { MobileInitOptions };
|
|
22
24
|
|
|
@@ -94,6 +96,14 @@ export class ProjectInitializer {
|
|
|
94
96
|
private cwd: string;
|
|
95
97
|
private createdItems: string[] = [];
|
|
96
98
|
private skippedItems: string[] = [];
|
|
99
|
+
/**
|
|
100
|
+
* Actions the user asked for that could NOT be performed. Kept apart from `skippedItems`:
|
|
101
|
+
* that list renders under "Already exists", which is a statement of fact about the project —
|
|
102
|
+
* printing "package.json scripts (invalid JSON)" under it tells the user the opposite of what
|
|
103
|
+
* happened. An action that was not done needs its own heading, or the init summary reads as a
|
|
104
|
+
* clean success while `npm test` is missing.
|
|
105
|
+
*/
|
|
106
|
+
private notDoneItems: string[] = [];
|
|
97
107
|
/** set by createCodexMCPConfig when the project isn't Codex-trusted (config would never load) */
|
|
98
108
|
private codexTrustWarning = false;
|
|
99
109
|
private agents: AdapterKey[];
|
|
@@ -135,6 +145,7 @@ export class ProjectInitializer {
|
|
|
135
145
|
: this.baseCwd;
|
|
136
146
|
this.createdItems = [];
|
|
137
147
|
this.skippedItems = [];
|
|
148
|
+
this.notDoneItems = [];
|
|
138
149
|
|
|
139
150
|
console.log(`🚀 Initializing Sungen ${this.mobileOnly ? 'mobile-only ' : ''}project...\n`);
|
|
140
151
|
|
|
@@ -439,9 +450,17 @@ export class ProjectInitializer {
|
|
|
439
450
|
|
|
440
451
|
if (existed) {
|
|
441
452
|
try {
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
453
|
+
// via readTextFile: a UTF-8 BOM is the one thing `JSON.parse` rejects that every other tool
|
|
454
|
+
// reading this file ignores, and it is invisible in an editor. A config the rest of the
|
|
455
|
+
// toolchain loads fine must not cost the user their MCP servers here.
|
|
456
|
+
config = JSON.parse(readTextFile(filePath));
|
|
457
|
+
} catch (e) {
|
|
458
|
+
// Anything still unparseable is genuinely broken. Say WHERE — "is not valid JSON" alone
|
|
459
|
+
// leaves the user to find a missing comma in a file they did not know was the problem.
|
|
460
|
+
this.notDoneItems.push(
|
|
461
|
+
`${displayName} (${(e as Error).message.split('\n')[0]}) — MCP servers not registered; `
|
|
462
|
+
+ `fix the JSON and re-run \`sungen init\``,
|
|
463
|
+
);
|
|
445
464
|
return;
|
|
446
465
|
}
|
|
447
466
|
}
|
|
@@ -487,6 +506,13 @@ export class ProjectInitializer {
|
|
|
487
506
|
});
|
|
488
507
|
}
|
|
489
508
|
|
|
509
|
+
if (this.notDoneItems.length > 0) {
|
|
510
|
+
console.log('\n⚠ Not done — needs your attention:');
|
|
511
|
+
this.notDoneItems.forEach(item => {
|
|
512
|
+
console.log(` ✗ ${item}`);
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
|
|
490
516
|
if (this.codexTrustWarning) {
|
|
491
517
|
console.log('\n⚠ Codex: this project is not trusted yet, so .codex/config.toml (the MCP browser');
|
|
492
518
|
console.log(' config for run-test) will be SILENTLY IGNORED by Codex. To fix, either:');
|
|
@@ -685,6 +711,13 @@ export class ProjectInitializer {
|
|
|
685
711
|
// Ensure standard scripts exist in package.json
|
|
686
712
|
this.ensurePackageScripts(packageJsonPath);
|
|
687
713
|
|
|
714
|
+
// Pin the transitive packages that would otherwise make `npm audit` red here. This MUST happen
|
|
715
|
+
// before the install below: npm reads `overrides` at resolution time, so a lockfile written
|
|
716
|
+
// first would already hold the vulnerable versions. See security-overrides.ts for why the pins
|
|
717
|
+
// cannot simply live in sungen's own manifest.
|
|
718
|
+
const overridePlan = ensureSecurityOverrides(packageJsonPath);
|
|
719
|
+
reportSecurityOverrides(overridePlan);
|
|
720
|
+
|
|
688
721
|
// Mobile-only drops @playwright/test (no web runner needed). `ajv`/`ajv-formats` back the API
|
|
689
722
|
// Driver's `expect {{name.body}} matches schema [Ref]` (loaded lazily; harmless if unused).
|
|
690
723
|
// fast-xml-parser: the API driver's XML request/response support lazy-requires it
|
|
@@ -696,7 +729,7 @@ export class ProjectInitializer {
|
|
|
696
729
|
|
|
697
730
|
let missingDeps: string[] = requiredDeps;
|
|
698
731
|
try {
|
|
699
|
-
const packageJson = JSON.parse(
|
|
732
|
+
const packageJson = JSON.parse(readTextFile(packageJsonPath));
|
|
700
733
|
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
701
734
|
missingDeps = requiredDeps.filter(d => !deps[d]);
|
|
702
735
|
} catch {
|
|
@@ -705,6 +738,12 @@ export class ProjectInitializer {
|
|
|
705
738
|
|
|
706
739
|
if (missingDeps.length === 0) {
|
|
707
740
|
console.log('✓ All dependencies already installed\n');
|
|
741
|
+
// Nothing to install means nothing re-resolves, so overrides just written would sit in
|
|
742
|
+
// package.json while the lockfile keeps the vulnerable tree. Re-resolve once so they land.
|
|
743
|
+
if (overridePlan?.add.length) {
|
|
744
|
+
console.log('📦 Re-resolving the tree so the new security overrides take effect...\n');
|
|
745
|
+
execSync('npm install', execOpts);
|
|
746
|
+
}
|
|
708
747
|
} else {
|
|
709
748
|
console.log(`📦 Installing ${missingDeps.join(', ')}...\n`);
|
|
710
749
|
execSync(`npm install -D ${missingDeps.join(' ')}`, execOpts);
|
|
@@ -725,8 +764,17 @@ export class ProjectInitializer {
|
|
|
725
764
|
private ensurePackageScripts(packageJsonPath: string): void {
|
|
726
765
|
let packageJson: Record<string, any>;
|
|
727
766
|
try {
|
|
728
|
-
|
|
729
|
-
|
|
767
|
+
// via readTextFile: a package.json carrying a UTF-8 BOM is one npm reads without complaint,
|
|
768
|
+
// so it must not be treated as unparseable here. That was the trigger that actually reached
|
|
769
|
+
// this catch — genuinely broken JSON aborts `npm install` a few lines below instead.
|
|
770
|
+
packageJson = JSON.parse(readTextFile(packageJsonPath));
|
|
771
|
+
} catch (e) {
|
|
772
|
+
// Returning here used to add nothing and say nothing, so init reported success and the user
|
|
773
|
+
// met `npm error Missing script: "test"` later with nothing pointing back to this run.
|
|
774
|
+
this.notDoneItems.push(
|
|
775
|
+
`package.json scripts (${(e as Error).message.split('\n')[0]}) — `
|
|
776
|
+
+ `fix the JSON and re-run \`sungen init\`, or add the scripts by hand`,
|
|
777
|
+
);
|
|
730
778
|
return;
|
|
731
779
|
}
|
|
732
780
|
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
|
|
6
6
|
import * as fs from 'fs';
|
|
7
7
|
import * as path from 'path';
|
|
8
|
-
import { chromium } from '@playwright/test';
|
|
9
8
|
import { readCapabilities } from '../harness/capability';
|
|
10
9
|
import { testDataHeader, ensureTestDataGuideFiles } from './test-data-guide';
|
|
11
10
|
import { resolveWebBaseUrl } from '../exporters/env-qa';
|
|
11
|
+
import { viewpointScaffold } from './viewpoint-scaffold';
|
|
12
12
|
|
|
13
13
|
export interface ScreenOptions {
|
|
14
14
|
name: string;
|
|
@@ -158,68 +158,11 @@ export class ScreenManager {
|
|
|
158
158
|
fs.writeFileSync(specPath, this.generateSpecTemplate(options, screenName), 'utf-8');
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
-
// Generate requirements test-viewpoint.md (only on first screen creation)
|
|
161
|
+
// Generate requirements test-viewpoint.md (only on first screen creation): the QA template,
|
|
162
|
+
// samples inside comments, so an untouched file declares nothing (see viewpoint-scaffold.ts).
|
|
162
163
|
const viewpointPath = path.join(requirementsDir, 'test-viewpoint.md');
|
|
163
164
|
if (!fs.existsSync(viewpointPath)) {
|
|
164
|
-
fs.writeFileSync(viewpointPath,
|
|
165
|
-
`# ${options.name} — Test Viewpoints`,
|
|
166
|
-
'',
|
|
167
|
-
'## Edge Cases',
|
|
168
|
-
'',
|
|
169
|
-
'<!-- Sample — replace with actual edge cases for this screen:',
|
|
170
|
-
'- Paste emoji into text fields (e.g., 🎉👋) — should accept or sanitize?',
|
|
171
|
-
'- Input 10,000+ characters into free text — truncate or reject?',
|
|
172
|
-
'- Double-click Submit rapidly — should only create 1 record',
|
|
173
|
-
'- Browser back button after successful submit — should not re-submit',
|
|
174
|
-
'-->',
|
|
175
|
-
'',
|
|
176
|
-
'## Known Issues',
|
|
177
|
-
'',
|
|
178
|
-
'<!-- Sample — replace with actual known issues:',
|
|
179
|
-
'- [BUG-001] Date picker does not work on Safari < 16',
|
|
180
|
-
'- [BUG-002] File upload silently fails for files > 20MB (no error shown)',
|
|
181
|
-
'- Search does not handle Vietnamese accents correctly ("Nguyên" ≠ "Nguyen")',
|
|
182
|
-
'-->',
|
|
183
|
-
'',
|
|
184
|
-
'## Design Decisions',
|
|
185
|
-
'',
|
|
186
|
-
'<!-- Sample — replace with actual design decisions:',
|
|
187
|
-
'- Show all validation errors at once (not one at a time) — per UX review',
|
|
188
|
-
'- Cancel button resets form completely (no draft saving)',
|
|
189
|
-
'- Anonymous mode hides sender name but keeps department visible',
|
|
190
|
-
'-->',
|
|
191
|
-
'',
|
|
192
|
-
'## UI Patterns Identified',
|
|
193
|
-
'',
|
|
194
|
-
'<!-- Check applicable patterns for this screen (from sungen-viewpoint skill):',
|
|
195
|
-
'',
|
|
196
|
-
'| # | Pattern | Applicable? | Notes |',
|
|
197
|
-
'|---|---------|-------------|-------|',
|
|
198
|
-
'| 1 | Form & Inputs | ☐ | |',
|
|
199
|
-
'| 2 | Data Table | ☐ | |',
|
|
200
|
-
'| 3 | Create / Add | ☐ | |',
|
|
201
|
-
'| 4 | Update / Edit | ☐ | |',
|
|
202
|
-
'| 5 | Delete | ☐ | |',
|
|
203
|
-
'| 6 | Search | ☐ | |',
|
|
204
|
-
'| 7 | Filter | ☐ | |',
|
|
205
|
-
'| 8 | Pagination | ☐ | |',
|
|
206
|
-
'| 9 | Modal / Dialog | ☐ | |',
|
|
207
|
-
'| 10 | List / Card | ☐ | |',
|
|
208
|
-
'-->',
|
|
209
|
-
'',
|
|
210
|
-
'## Priority Viewpoints',
|
|
211
|
-
'',
|
|
212
|
-
'<!-- Rate importance for this screen (High / Medium / Low / Skip):',
|
|
213
|
-
'',
|
|
214
|
-
'| VP | Priority | Reason |',
|
|
215
|
-
'|---|----------|--------|',
|
|
216
|
-
'| VP-UI | High | Complex form with many states |',
|
|
217
|
-
'| VP-VAL | High | 14 validation rules from spec |',
|
|
218
|
-
'| VP-LOGIC | Medium | Standard CRUD, no complex business rules |',
|
|
219
|
-
'| VP-SEC | Low | Internal tool, basic auth only |',
|
|
220
|
-
'-->',
|
|
221
|
-
'',
|
|
222
|
-
].join('\n'), 'utf-8');
|
|
165
|
+
fs.writeFileSync(viewpointPath, viewpointScaffold(options.name, isMobile), 'utf-8');
|
|
223
166
|
}
|
|
224
167
|
|
|
225
168
|
// Auto-screenshot: capture page only when --capture is set and not mobile (requires --path)
|
|
@@ -272,6 +215,9 @@ export class ScreenManager {
|
|
|
272
215
|
|
|
273
216
|
let browser;
|
|
274
217
|
try {
|
|
218
|
+
// Loaded here, not at module top: @playwright/test is a peerDependency a mobile project never
|
|
219
|
+
// installs, and `sungen add` loads this module on every platform (#865).
|
|
220
|
+
const { chromium } = await import('@playwright/test');
|
|
275
221
|
browser = await chromium.launch();
|
|
276
222
|
const page = await browser.newPage({ viewport: { width: 1280, height: 720 } });
|
|
277
223
|
await page.goto(url, { waitUntil: 'networkidle', timeout: 15000 });
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* npm `overrides` a sungen project needs in order to pass `npm audit`.
|
|
3
|
+
*
|
|
4
|
+
* Why this lives in the CLI instead of in `packages/core/package.json`: npm honours `overrides`
|
|
5
|
+
* ONLY in the root `package.json` of the project doing the installing. A block declared by a
|
|
6
|
+
* DEPENDENCY is inert — it is not read, not merged, and not carried in the published tarball. So
|
|
7
|
+
* the monorepo root can (and does) pin these for itself while every consumer of the published
|
|
8
|
+
* packages still resolves the vulnerable versions. Repo green, install red, and nobody working in
|
|
9
|
+
* the repo ever sees what a consumer sees. Issue #764.
|
|
10
|
+
*
|
|
11
|
+
* Sungen already writes to the consuming project's `package.json` (standard scripts on `init`,
|
|
12
|
+
* family version pinning on `update`), so the overrides go in on the same two passes. That makes
|
|
13
|
+
* the fix reachable the ordinary way: a new project is clean from its first install, an existing
|
|
14
|
+
* one becomes clean on the next `sungen update`.
|
|
15
|
+
*
|
|
16
|
+
* Every entry below is here because NOTHING ELSE CLEARS IT — the offending package is either at its
|
|
17
|
+
* latest published version already, or is hard-pinned by an unmaintained parent. Bumping sungen's
|
|
18
|
+
* own declared ranges does not move any of them: `@sungen/driver-mobile` is already on the newest
|
|
19
|
+
* appium (3.x) and webdriverio (9.x), and npm's own `fix available` for that chain is a DOWNGRADE
|
|
20
|
+
* to appium 1.22.3 / webdriverio 8.14.6, not a fix.
|
|
21
|
+
*
|
|
22
|
+
* Measured on a clean-room install of the published 3.2.32 family (2026-09-23): 25 findings
|
|
23
|
+
* (12 moderate, 13 high) without this block, 0 with it.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
export interface SecurityOverride {
|
|
27
|
+
/** Package to pin, as it appears in `overrides`. */
|
|
28
|
+
pkg: string;
|
|
29
|
+
/** Range to pin it to — the lowest published version clear of the advisory. */
|
|
30
|
+
range: string;
|
|
31
|
+
/** Advisory + the path that drags the vulnerable copy in, so a reader can re-check the entry. */
|
|
32
|
+
why: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The pinned set. Keep it MINIMAL: an entry earns its place only while a clean install is red
|
|
37
|
+
* without it. When an upstream finally ships a fix inside its own declared range, delete the entry
|
|
38
|
+
* rather than raising it — a stale override silently holds a whole subtree back.
|
|
39
|
+
*/
|
|
40
|
+
export const SECURITY_OVERRIDES: SecurityOverride[] = [
|
|
41
|
+
{
|
|
42
|
+
pkg: 'uuid',
|
|
43
|
+
range: '^11.1.1',
|
|
44
|
+
// exceljs 4.4.0 IS the latest (published 2024-12-20) and hard-declares "uuid": "^8.3.0".
|
|
45
|
+
// There is no newer exceljs to bump to, which is why npm reports fixAvailable: false.
|
|
46
|
+
why: 'GHSA-w5hq-g745-h8pq (moderate) — uuid@8.3.2 via exceljs@4.4.0, which is unmaintained and pins ^8.3.0',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
pkg: 'morgan',
|
|
50
|
+
range: '^1.12.1',
|
|
51
|
+
// @appium/base-driver pins the exact version "1.11.0", so no resolution reaches 1.12.x on its own.
|
|
52
|
+
why: 'GHSA-jxfw-x594-9x9m (moderate) — morgan@1.11.0 exact-pinned by @appium/base-driver',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
pkg: 'serialize-javascript',
|
|
56
|
+
range: '^7.1.2',
|
|
57
|
+
why: 'GHSA-5c6j-r48x-rmvq (high) + GHSA-qj8w-gfj5-8c6v (moderate) — serialize-javascript@6.0.2 via mocha (^6.0.2)',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
pkg: '@puppeteer/browsers',
|
|
61
|
+
range: '^3.2.3',
|
|
62
|
+
// The vulnerable package is extract-zip, whose latest (2.0.1) IS the flagged version — there is
|
|
63
|
+
// nothing to pin it to. @puppeteer/browsers 3.x dropped extract-zip for modern-tar, so the pin
|
|
64
|
+
// goes on the parent instead. @wdio/utils asks for ^2.2.0 but imports only install, canDownload,
|
|
65
|
+
// resolveBuildId, detectBrowserPlatform, Browser, ChromeReleaseChannel and computeExecutablePath
|
|
66
|
+
// — all seven still exported by 3.2.3, verified against @wdio/utils@9.32.0.
|
|
67
|
+
why: 'GHSA-jmr9-qjv8-65gv + GHSA-7pqw-9j4j-h8q3 (high) — extract-zip@2.0.1 via @puppeteer/browsers@2.x ← @wdio/utils; extract-zip has no fixed release, 3.x replaced it with modern-tar',
|
|
68
|
+
},
|
|
69
|
+
];
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { SECURITY_OVERRIDES, SecurityOverride } from './security-overrides-catalog';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Merge the security-override catalog into a consuming project's `package.json`.
|
|
7
|
+
*
|
|
8
|
+
* The catalog itself — which packages, which ranges, and why each one cannot be cleared any other
|
|
9
|
+
* way — lives in `security-overrides-catalog.ts`. That is the file to edit when an advisory moves;
|
|
10
|
+
* this one holds only the merge, the write and the reporting, which do not change when it does.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export { SECURITY_OVERRIDES } from './security-overrides-catalog';
|
|
14
|
+
export type { SecurityOverride } from './security-overrides-catalog';
|
|
15
|
+
|
|
16
|
+
export interface OverridePlan {
|
|
17
|
+
/** Entries missing from the project, to be written. */
|
|
18
|
+
add: SecurityOverride[];
|
|
19
|
+
/** Entries the project already pins itself — left untouched, reported so the user can judge. */
|
|
20
|
+
existing: Array<{ pkg: string; declared: string; wanted: string }>;
|
|
21
|
+
/** Set when the pins were needed but the write failed — `add` is then empty, nothing was applied. */
|
|
22
|
+
writeFailed?: boolean;
|
|
23
|
+
/** Lockfile of a package manager that ignores `overrides`, when the project has one. */
|
|
24
|
+
foreignLockfile?: 'yarn' | 'pnpm';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Decide what a project's `overrides` block is missing. Pure — no I/O, so the tests and `--dry-run`
|
|
29
|
+
* can plan without touching anything.
|
|
30
|
+
*
|
|
31
|
+
* A pin the project already declares is NEVER rewritten, even when it differs from ours. Someone who
|
|
32
|
+
* typed a range into their own `package.json` had a reason (a private mirror, a pinned fork, a
|
|
33
|
+
* downgrade forced by another tool), and silently overwriting it would be the more surprising bug.
|
|
34
|
+
* It is reported instead, so a still-vulnerable pin is visible rather than swallowed.
|
|
35
|
+
*/
|
|
36
|
+
export function planSecurityOverrides(pkgJson: Record<string, any>): OverridePlan {
|
|
37
|
+
const current: Record<string, unknown> =
|
|
38
|
+
pkgJson.overrides && typeof pkgJson.overrides === 'object' ? pkgJson.overrides : {};
|
|
39
|
+
|
|
40
|
+
const add: SecurityOverride[] = [];
|
|
41
|
+
const existing: OverridePlan['existing'] = [];
|
|
42
|
+
|
|
43
|
+
for (const entry of SECURITY_OVERRIDES) {
|
|
44
|
+
const declared = current[entry.pkg];
|
|
45
|
+
if (typeof declared === 'string') {
|
|
46
|
+
if (declared !== entry.range) existing.push({ pkg: entry.pkg, declared, wanted: entry.range });
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
// A nested override object ({ "uuid": { ".": "^11" } }) is a deliberate, more specific shape —
|
|
50
|
+
// treat it as the project's own decision and leave it alone.
|
|
51
|
+
if (declared !== undefined) {
|
|
52
|
+
existing.push({ pkg: entry.pkg, declared: JSON.stringify(declared), wanted: entry.range });
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
add.push(entry);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return { add, existing };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Write the missing overrides into a project's `package.json`.
|
|
63
|
+
*
|
|
64
|
+
* Best-effort by design, exactly like the rest of the project-file touching in `init` / `update`: an
|
|
65
|
+
* unreadable or malformed `package.json` means we skip silently rather than fail the command the
|
|
66
|
+
* user actually ran. The audit gate is not worth losing a scaffold over.
|
|
67
|
+
*
|
|
68
|
+
* Must run BEFORE the project's `npm install`, or the first resolution pass writes a lockfile that
|
|
69
|
+
* already pins the vulnerable versions.
|
|
70
|
+
*
|
|
71
|
+
* @param dryRun plan only — report what would change and write nothing
|
|
72
|
+
* @returns the plan that was applied, or null when there was no `package.json` to apply it to
|
|
73
|
+
*/
|
|
74
|
+
export function ensureSecurityOverrides(packageJsonPath: string, dryRun = false): OverridePlan | null {
|
|
75
|
+
let pkgJson: Record<string, any>;
|
|
76
|
+
try {
|
|
77
|
+
pkgJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
78
|
+
} catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const plan = planSecurityOverrides(pkgJson);
|
|
83
|
+
plan.foreignLockfile = detectForeignLockfile(path.dirname(packageJsonPath));
|
|
84
|
+
|
|
85
|
+
if (plan.add.length && !dryRun) {
|
|
86
|
+
const overrides: Record<string, unknown> =
|
|
87
|
+
pkgJson.overrides && typeof pkgJson.overrides === 'object' ? pkgJson.overrides : {};
|
|
88
|
+
for (const entry of plan.add) overrides[entry.pkg] = entry.range;
|
|
89
|
+
pkgJson.overrides = overrides;
|
|
90
|
+
try {
|
|
91
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(pkgJson, null, 2) + '\n', 'utf-8');
|
|
92
|
+
} catch {
|
|
93
|
+
// Read-only checkout, root-owned file, read-only container mount. `sungen update` in
|
|
94
|
+
// particular has ALREADY reinstalled globally by the time it gets here, so throwing would
|
|
95
|
+
// abandon the AI-rules refresh and the family sync over a hardening step. Report and move on.
|
|
96
|
+
return { add: [], existing: plan.existing, foreignLockfile: plan.foreignLockfile, writeFailed: true };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return plan;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* npm is the only package manager that reads a top-level `overrides` block. Yarn wants
|
|
105
|
+
* `resolutions`, pnpm wants `pnpm.overrides` — so on those projects the block we write is inert and
|
|
106
|
+
* the install stays vulnerable. We do NOT guess at the equivalent field (getting a resolutions
|
|
107
|
+
* pattern subtly wrong is worse than not writing one), but silence would be the same class of bug
|
|
108
|
+
* as #764 itself: a fix that looks applied and is not. So: say so.
|
|
109
|
+
*/
|
|
110
|
+
function detectForeignLockfile(dir: string): 'yarn' | 'pnpm' | undefined {
|
|
111
|
+
if (fs.existsSync(path.join(dir, 'pnpm-lock.yaml'))) return 'pnpm';
|
|
112
|
+
if (fs.existsSync(path.join(dir, 'yarn.lock'))) return 'yarn';
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Print what `ensureSecurityOverrides` did, in the voice the surrounding commands already use. */
|
|
117
|
+
export function reportSecurityOverrides(plan: OverridePlan | null, dryRun = false): void {
|
|
118
|
+
if (!plan) return;
|
|
119
|
+
|
|
120
|
+
if (plan.writeFailed) {
|
|
121
|
+
console.warn(
|
|
122
|
+
'⚠️ Could not write the security overrides into package.json (read-only file?). Nothing else\n' +
|
|
123
|
+
' failed. Add this block by hand to keep `npm audit` clean:\n' +
|
|
124
|
+
` "overrides": ${JSON.stringify(Object.fromEntries(SECURITY_OVERRIDES.map((o) => [o.pkg, o.range])), null, 2).replace(/\n/g, '\n ')}\n`,
|
|
125
|
+
);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (plan.add.length) {
|
|
130
|
+
const verb = dryRun ? '[dry-run] would add' : 'Added';
|
|
131
|
+
console.log(`🔒 ${verb} ${plan.add.length} security override(s) to package.json — npm honours these only here, not from sungen's own manifest:`);
|
|
132
|
+
for (const entry of plan.add) console.log(` • ${entry.pkg}@${entry.range} — ${entry.why}`);
|
|
133
|
+
console.log('');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (plan.existing.length) {
|
|
137
|
+
console.log('🔒 Left your own overrides alone (sungen never rewrites a pin you declared):');
|
|
138
|
+
for (const e of plan.existing) console.log(` – ${e.pkg}: ${e.declared} (sungen would use ${e.wanted})`);
|
|
139
|
+
console.log(' If `npm audit` still flags one of these, raise it by hand.\n');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (plan.foreignLockfile && (plan.add.length || plan.existing.length)) {
|
|
143
|
+
const field = plan.foreignLockfile === 'pnpm' ? '"pnpm": { "overrides": … }' : '"resolutions"';
|
|
144
|
+
console.warn(
|
|
145
|
+
`⚠️ This project has a ${plan.foreignLockfile} lockfile. ${plan.foreignLockfile} ignores npm's "overrides" —\n` +
|
|
146
|
+
` mirror the block into ${field} as well, or the pins do nothing here.\n`,
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -9,7 +9,9 @@ You are a **test-design context explorer**. You run in an **isolated context** s
|
|
|
9
9
|
## Explore (do NOT ask the user to pick a source — read all that exist)
|
|
10
10
|
- `requirements/spec.md` — primary behavior source.
|
|
11
11
|
- `requirements/spec_figma.md` — Figma supplement (if present; do NOT call Figma MCP when this exists).
|
|
12
|
-
- `requirements/ui/*` images —
|
|
12
|
+
- `requirements/ui/*` images — read **every** image (group primary vs states/variants when there are many, but open them all).
|
|
13
|
+
- `requirements/ui/figma-meta.md` — Figma MCP capture: `## Components`, `## Text Content`.
|
|
14
|
+
- `requirements/ui-inventory.md` — an existing Design Inventory: keep its `UI-NNN` ids.
|
|
13
15
|
- Live page — only if a base URL is configured and reachable: `browser_navigate` + `browser_snapshot` for real element roles/names. Fall back gracefully if it requires login / fails.
|
|
14
16
|
|
|
15
17
|
## Cross-check
|
|
@@ -20,7 +22,13 @@ Flag any **conflicts** between sources (field names, labels, behavior, states th
|
|
|
20
22
|
SOURCES: spec=<yes/no, completeness high|med|low> | figma=<...> | ui=<n images> | live=<reached|offline>
|
|
21
23
|
PAGE TYPE: <e.g. ecommerce-list / form / auth / ...>
|
|
22
24
|
RECOMMENDED ROUTE: <spec-first | source-first | ...> — authoritative source: <which>
|
|
23
|
-
CONFLICTS: <list, or "none">
|
|
25
|
+
CONFLICTS: <list, or "none"> — each conflict on a design item also appears in UI INVENTORY with source `conflict`
|
|
26
|
+
UI INVENTORY: images read: <read>/<total> · figma-meta.md: <read|absent> · spec_figma.md: <read|absent>
|
|
27
|
+
| UI-001 | <item> | <component|column|button|field|state|annotation> | spec+design | <image> |
|
|
28
|
+
| UI-014 | <item> | column | design-only | <image> |
|
|
29
|
+
| UI-015 | <item> | column | conflict — <how spec and design disagree> | <image> |
|
|
30
|
+
→ one row per item the design shows (format and id rules: `sungen-tc-generation` § Design Inventory);
|
|
31
|
+
omit the block only when the unit has no design source
|
|
24
32
|
KEY FACTS (condensed):
|
|
25
33
|
- Sections: <list>
|
|
26
34
|
- Fields/validation: <key constraints + exact error messages>
|
|
@@ -29,4 +37,4 @@ KEY FACTS (condensed):
|
|
|
29
37
|
ASSUMPTIONS / MISSING INFO: <what's unknown — to be marked in output>
|
|
30
38
|
```
|
|
31
39
|
|
|
32
|
-
Keep it tight. Do not generate test cases — that is the orchestrator's job. Do not write files.
|
|
40
|
+
Keep it tight — except UI INVENTORY, which is listed in full: it is the checklist the orchestrator writes to `ui-inventory.md`. Do not generate test cases — that is the orchestrator's job. Do not write files.
|
|
@@ -10,6 +10,8 @@ You are an **independent Senior QA Reviewer**. You did **not** write these tests
|
|
|
10
10
|
- `qa/<screens|flows>/<name>/features/<name>.feature` — the scenarios under review.
|
|
11
11
|
- `qa/<screens|flows>/<name>/requirements/test-viewpoint.md` — the viewpoint overview (priority).
|
|
12
12
|
- `qa/<screens|flows>/<name>/requirements/spec.md` — source of truth for behavior.
|
|
13
|
+
- `qa/<screens|flows>/<name>/requirements/ui/*` images, `ui/figma-meta.md`, `spec_figma.md` — the design, when present. Open **every** image.
|
|
14
|
+
- `qa/<screens|flows>/<name>/requirements/ui-inventory.md` — the Design Inventory create-test wrote (`UI-NNN` rows).
|
|
13
15
|
- `.sungen/reports/<name>-audit.json` — the deterministic findings (don't repeat them; go deeper).
|
|
14
16
|
|
|
15
17
|
## What to judge (semantic — the gate misses these)
|
|
@@ -25,6 +27,7 @@ You are an **independent Senior QA Reviewer**. You did **not** write these tests
|
|
|
25
27
|
- **Flows self-clean.** A CRUD/auth chain deletes what it created (final `@api:delete_*`) or is `@cleanup`-tagged.
|
|
26
28
|
- **Idempotency uses the DB oracle.** A "no double-charge / exactly once" claim is proven by `@concurrent` + a `@query` count, not HTTP status alone (status can lie under a race).
|
|
27
29
|
- **Auth negatives** exist for protected mutations (401/403), not just the happy path.
|
|
30
|
+
7. **Design ↔ Feature** (only when the unit holds design sources). Read the design yourself — do not trust the inventory to be complete. Report: items the design shows that are **missing from `ui-inventory.md`**; inventory items **mislabelled** `spec+design` that `spec.md` never names (design-only) or names differently (conflict); and `design-only`/`conflict` items whose `@ui:` scenario does not actually prove them, or whose `# UI-DEFERRED:` reason does not hold. The audit only sees what the inventory lists — you are the check on the inventory itself.
|
|
28
31
|
|
|
29
32
|
## Output (do NOT edit any file)
|
|
30
33
|
Return a concise verdict:
|
|
@@ -38,6 +41,11 @@ ISSUES (most important first):
|
|
|
38
41
|
FIX: <the exact Gherkin step(s) to add/change>
|
|
39
42
|
2. ...
|
|
40
43
|
|
|
44
|
+
DESIGN DIFF (omit when the unit has no design source):
|
|
45
|
+
- not inventoried: <item> (<image>)
|
|
46
|
+
- mislabelled: UI-NNN <item> — is <design-only|conflict>, not spec+design
|
|
47
|
+
- unproven: UI-NNN <item> — <why the @ui scenario / deferral does not hold>
|
|
48
|
+
|
|
41
49
|
STRENGTHS: <1-2 lines, what is genuinely good>
|
|
42
50
|
```
|
|
43
51
|
|
|
@@ -64,7 +64,8 @@ restated from screen specs the project does not hold, say so: the audit reports
|
|
|
64
64
|
`SPEC-RESTATED-UNVERIFIED` because `specFR 100%` over a hand-copied list certifies the copy, not
|
|
65
65
|
the source.
|
|
66
66
|
|
|
67
|
-
**
|
|
67
|
+
**A viewpoint you draft (mode 2, step 3) carries BOTH classification axes** — on a QA-written one
|
|
68
|
+
(mode 1) a missing axis or guarantee line is a row in `viewpoint-review.md`, not an edit. `VP-LOGIC / VP-VAL / VP-SEC / VP-NAV` classify
|
|
68
69
|
by TECHNICAL RISK; `BF / AF / EF` classify by BUSINESS BRANCH. They answer different questions and
|
|
69
70
|
neither replaces the other — a reviewer needs to see both, so use the compound id
|
|
70
71
|
(`VP-SEC-EF02-001`) and give the viewpoint a section per flow as well as its priority table by
|
|
@@ -81,8 +82,8 @@ questions and only one of them is a yardstick:
|
|
|
81
82
|
| `flow-contract.yaml` | the USE CASE — actor · trigger · goal · precondition · both guarantees · the flow inventory | `flowCoverage` |
|
|
82
83
|
| `test-viewpoint.md` | the CLAIMS the suite must prove — cross-screen concerns, edge cases, design decisions, open questions, priorities | `atomicLedger` · `traceability` |
|
|
83
84
|
|
|
84
|
-
If `requirements/test-viewpoint.md` is missing, **
|
|
85
|
-
|
|
85
|
+
If `requirements/test-viewpoint.md` is missing or still the scaffold, **draft it before generating**
|
|
86
|
+
(mode 2, step 3 — `add-flow` scaffolds the template; a run that deletes or replaces it has removed the yardstick). Without it two scored
|
|
86
87
|
axes are excluded and four sensors cannot run at all — the atomic ledger, the
|
|
87
88
|
declaration-integrity checks, the browser-gesture check and the two-way continuity check — so the
|
|
88
89
|
audit reports `VIEWPOINT-MISSING` and the result is *unmeasured*, not passing. And the reason the
|
|
@@ -95,8 +96,8 @@ ordering choice: a yardstick derived from the scenarios reads 100% by constructi
|
|
|
95
96
|
dropped along the way stops being missing from anything. `sungen audit` now reports
|
|
96
97
|
`VIEWPOINT-ADOPTED-POST-HOC` on the first sighting of a viewpoint alongside an existing suite and
|
|
97
98
|
holds `atomicLedger` + `traceability` as unverified until a human accepts it — so the honest move
|
|
98
|
-
is to write the claims from `spec.md` and the contract, mark
|
|
99
|
-
|
|
99
|
+
is to write the claims from `spec.md` and the contract, mark the file `drafted-by: ai` (its first
|
|
100
|
+
line), and let the QA revise before `--accept-viewpoint`. **You never run `--accept-viewpoint` yourself** — `sungen next` lists it as a `⚖ decide` step for exactly this reason: an agent accepting the yardstick it wrote in the same session makes `atomicLedger` and `traceability` read 100% against its own checklist, and the Exception Flow it forgot stops being missing from anything. Present the acceptance to the QA in the hand-back (`AskUserQuestion`) with what the file declares — never as a question mid-run.
|
|
100
101
|
|
|
101
102
|
**When you give a claim an id, a scenario must carry that id.** The id is the contract: a claim
|
|
102
103
|
whose id no scenario carries is reported MISSING, and word overlap will not rescue it. Several
|
|
@@ -110,8 +111,9 @@ narrow the claim to what is actually proven.
|
|
|
110
111
|
|
|
111
112
|
**Priority comes from the declaration.** A scenario tagged `@high` under a viewpoint row that says
|
|
112
113
|
`Low` is `PRIORITY-CONTRADICTED` — a smoke run selects on the tag, so it picks up work the QA
|
|
113
|
-
deliberately deprioritised. Inherit the declared priority; if the tag is right,
|
|
114
|
-
|
|
114
|
+
deliberately deprioritised. Inherit the declared priority; if the tag is right, the declaration is
|
|
115
|
+
what is wrong — fix it in your own draft (mode 2), or report it in `viewpoint-review.md` for the QA
|
|
116
|
+
(mode 1). Never leave both on record silently.
|
|
115
117
|
|
|
116
118
|
---
|
|
117
119
|
|
|
@@ -205,26 +207,15 @@ If the unit is **api-first** (`qa/api/<name>/` or `qa/api/flows/<name>/`), the d
|
|
|
205
207
|
**Screen requirements** — check `<base>/${input:name}/requirements/`:
|
|
206
208
|
{{/cap}}
|
|
207
209
|
- If `spec.md` exists → read it as PRIMARY source (sections, fields, validation rules, business rules, states).
|
|
210
|
+
- `test-viewpoint.md` → **Viewpoint — review or draft** below, once every source is read. No question here.
|
|
208
211
|
{{#cap parallel-subagents}}
|
|
209
|
-
- If `test-viewpoint.md` exists → read it. If it only contains HTML comments (scaffold template), use `AskUserQuestion` to ask:
|
|
210
|
-
- **Fill test-viewpoint.md first** — I'll help you identify edge cases, known issues, and design decisions for this screen before generating tests
|
|
211
|
-
- **Continue without it** — generate tests from spec and other sources only
|
|
212
|
-
|
|
213
|
-
**A filled `test-viewpoint.md` is an INPUT — never an output.** Do NOT rewrite, re-order, or replace its viewpoint declarations as part of generating tests. It is the yardstick two scored axes measure the suite against (`traceability`, `atomicLedger`): rewrite it to match what you just generated and both read 100% by construction, while any viewpoint you quietly dropped stops being missing from anything. If the declared taxonomy genuinely does not fit the screen, **report the mismatch and ask** — propose the diff (ids added / removed and why) and let the QA decide. `sungen audit` reports `VIEWPOINT-BASELINE-CHANGED` and stops scoring both axes when this file moves, so an unannounced rewrite lowers the score rather than raising it.
|
|
214
212
|
|
|
215
213
|
**Context discovery (prefer an isolated agent).** Reading all sources here can flood this context. **Claude Code:** spawn the **`sungen-discovery`** sub-agent (Task tool, `subagent_type: sungen-discovery`) to read spec/figma/ui/live in isolation and return a **compact discovery report** (sources, completeness, conflicts, recommended route, key facts); use that report instead of pasting raw sources. **Copilot / no sub-agents:** do the reading inline as below.
|
|
216
214
|
{{/cap}}
|
|
217
|
-
{{^cap parallel-subagents}}
|
|
218
|
-
- If `test-viewpoint.md` exists → read it. If it only contains HTML comments (scaffold template), ask:
|
|
219
|
-
- **1) Fill test-viewpoint.md first** — identify edge cases, known issues, and design decisions before generating tests
|
|
220
|
-
- **2) Continue without it** — generate tests from spec and other sources only
|
|
221
|
-
|
|
222
|
-
**A filled `test-viewpoint.md` is an INPUT — never an output.** Do NOT rewrite, re-order, or replace its viewpoint declarations while generating tests. It is the yardstick two scored axes measure the suite against (`traceability`, `atomicLedger`): rewrite it to match what you just generated and both read 100% by construction, while any viewpoint you quietly dropped stops being missing from anything. If the declared taxonomy genuinely does not fit the screen, **report the mismatch and ask** — propose the diff (ids added / removed and why) and let the QA decide. `sungen audit` reports `VIEWPOINT-BASELINE-CHANGED` and stops scoring both axes when this file moves.
|
|
223
|
-
{{/cap}}
|
|
224
215
|
|
|
225
216
|
**Auto-detect visual source** — do NOT ask the user to pick a source. Instead, check what already exists and use it:
|
|
226
217
|
1. If `spec_figma.md` exists → read it as Figma supplement (PAT flow already completed during `add-screen`). Do NOT call any `mcp__figma__*` tool.
|
|
227
|
-
2. If `ui/` has images (`.png`, `.jpg`, etc.) → read them
|
|
218
|
+
2. If `ui/` has images (`.png`, `.jpg`, etc.) or `ui/figma-meta.md` → read **all** of them; they feed the Design Inventory (below), not just visual context.
|
|
228
219
|
{{#cap parallel-subagents}}
|
|
229
220
|
3. If neither exists → use `AskUserQuestion` to ask: *"No visual source found. Pick one:"* — then invoke the **`sungen-capture`** skill with the matching **mode** (read only that mode's file):
|
|
230
221
|
- **Figma PAT** — ask for URL, run `sungen add --screen <screen> --figma '<url>'` via Bash, then `sungen-capture` **mode figma-pat**
|
|
@@ -242,7 +233,19 @@ If the unit is **api-first** (`qa/api/<name>/` or `qa/api/flows/<name>/`), the d
|
|
|
242
233
|
|
|
243
234
|
(When `spec_figma.md` exists, that is also `sungen-capture` **mode figma-pat**; when `ui/` images exist, that is **mode local**.)
|
|
244
235
|
|
|
245
|
-
**Cross-check**:
|
|
236
|
+
**Cross-check + Design Inventory**: when the unit holds any design source (`ui/` images, `ui/figma-meta.md`, `spec_figma.md`), follow `sungen-tc-generation` § **Design Inventory** (reading order, one `UI-NNN` row per item, `spec+design` / `design-only` / `conflict`) and **write `requirements/ui-inventory.md`** before generating — from the discovery report's UI INVENTORY block when a sub-agent read the sources. Every `design-only` / `conflict` item must then be covered (`@ui:UI-NNN`) or deferred with a reason (`# UI-DEFERRED: UI-NNN — <reason>`) in the `.feature`; `sungen audit` reports `UI-ITEM-UNCOVERED` otherwise. Show the user the conflicts and design-only items — they are decisions, not details.
|
|
237
|
+
|
|
238
|
+
**Viewpoint — review or draft (no question asked).** Run `sungen viewpoint scan --screen <name> --json` (a flow: `--flow <name>`). It reads ids and item numbers only. Its `mode` (1 or 2) and `modeReason` name the row below — follow them; the table explains them:
|
|
239
|
+
|
|
240
|
+
| `requirements/test-viewpoint.md` | Mode | You |
|
|
241
|
+
|---|---|---|
|
|
242
|
+
| missing; nothing but the scaffold (headings, `<…>` placeholders, empty tables); or ONE OR MORE VP rows and every one of them lacks a `Kỳ vọng` | **2 — draft** | Write it from `sungen-viewpoint/viewpoint-template.md`, first line `drafted-by: ai`, keeping any row already there. Each row answers "test CÁI GÌ" and "kỳ vọng ra sao"; where the spec states the expected result, write it; only what the spec leaves open becomes a closed question in mục 5, never an invented expectation; every accepted-input class the spec names (whitelist, value list, conversion) gets an "accepted, no error" row, citing the list by name; a VP that needs a real device, account or time is `# MANUAL/ENV`. Then scan again. |
|
|
243
|
+
| first line `drafted-by: ai` | **2 — re-review** | Your draft, not yet accepted: you may revise it, from the spec and the review. |
|
|
244
|
+
| anything else — QA-written, with or without VP ids (a scaffold from an older sungen reads as this row too: delete the file to have it drafted) | **1 — review only** | Never edit it. Generate from it as written; a gap is reported, not filled. |
|
|
245
|
+
|
|
246
|
+
Then review it with `sungen-viewpoint/review-checklist.md` and the scan JSON (mode 2: fix your draft until only QA decisions remain) and write `requirements/viewpoint-review.md`, overwritten each run. Mode 2 also runs `sungen audit --screen <name> --no-baseline` before generating. Keep the review's row count for the hand-back.
|
|
247
|
+
|
|
248
|
+
**A filled `test-viewpoint.md` is an INPUT — never an output.** Do NOT rewrite, re-order, or replace its viewpoint declarations as part of generating tests — your own draft included: a draft is revised from the spec, never from the scenarios. It is the yardstick two scored axes measure the suite against (`traceability`, `atomicLedger`): rewrite it to match what you just generated and both read 100% by construction, while any viewpoint you quietly dropped stops being missing from anything. If the declared taxonomy genuinely does not fit the screen, **report the mismatch in `viewpoint-review.md`** — the diff (ids added / removed and why) — and let the QA decide. `sungen audit` reports `VIEWPOINT-BASELINE-CHANGED` and stops scoring both axes when this file moves, so an unannounced rewrite lowers the score rather than raising it.
|
|
246
249
|
|
|
247
250
|
Summarize what you found in requirements and present to the user.
|
|
248
251
|
|
|
@@ -284,6 +287,7 @@ If the unit is **api-first** (`qa/api/<name>/` or `qa/api/flows/<name>/`), the d
|
|
|
284
287
|
- **BALANCE** → stop expanding secondary viewpoints; add business-core scenarios first.
|
|
285
288
|
- **TRACE** → align `VP-` ids with the viewpoint-overview.
|
|
286
289
|
- Stop when the gate PASSes and findings clear, **or** the budget is exhausted → report residual gaps honestly (never fake a pass).
|
|
290
|
+
- **Repair never edits a QA-written viewpoint (mode 1).** A finding whose fix is an edit to `test-viewpoint.md` becomes a row in `viewpoint-review.md` for the QA when it cites one of the file's VP ids (the checklist's audit rule; anything else goes in the hand-back); in a mode-2 draft, fix the draft.
|
|
287
291
|
|
|
288
292
|
5.6. **Record (reuse + observability).** Build the manifest and report usage:
|
|
289
293
|
- `sungen manifest --screen <name>` — fingerprints for next-run change detection. On a **re-run**, start the whole command by `sungen manifest --screen <name> --diff` and only regenerate scenarios whose spec section changed (keep/regenerate/retire).
|
|
@@ -297,7 +301,7 @@ If the unit is **api-first** (`qa/api/<name>/` or `qa/api/flows/<name>/`), the d
|
|
|
297
301
|
> **No parallel fan-out here.** Copilot has no sub-agents, so generation is sequential (the Claude Code variant fans out one `sungen-generator` per viewpoint group and merges). Same output, no speedup.
|
|
298
302
|
5.3. **Standardize field test-data — Data Factory (when the unit has input fields).** For each input field, author the field-map `qa/data-factory/<name>.fields.yaml` (field → catalog `type` + real `constraints` + `errorMap`), then run `sungen data lint --screen ${input:name}` and `sungen data gen --screen ${input:name}` per the **`sungen-data-factory`** skill. `data gen` **MERGES** into `test-data.yaml` (replaces only its field keys, preserves the rest), so it is safe here. Weave the standardized boundary/invalid sets into `@cases` with `CHK-*` trace. Then `… data validate` (values correct) + `… data crosscheck` (testcase↔data agree); for a stateful precondition, `… data state --scaffold <name>` to auto-draft → fill entities + confirm with QA → `… data state`, weave the `@manual:data-setup` `Background` (works spec+viewpoint only). **Same standard as `/sungen:create-data-test`, applied inline — do NOT run that command separately afterwards.** No input fields (navigation/list) → skip.
|
|
299
303
|
5.4. **Depth self-check (deterministic — BEFORE the audit).** Run `sungen depth-lint --screen ${input:name}`. It splits every shallow business-critical scenario into **DEEPEN IN PLACE** (add a real value assertion — the printed `template` is a theme-keyed hint, apply judgment to the actual claim; never fake one onto a visibility/behavior scenario) and **CROSS-SCREEN** (route to a flow / tag `@manual:Mx` + reason — removes it from the depth denominator honestly). Act on both, re-run until `deepen` is empty (or only honest over-counts remain), THEN gate. Lifts first-pass `businessDepth` mechanically instead of via 2–3 repair rounds.
|
|
300
|
-
5.5. **Quality gate & repair (harness — always run).** Per `sungen-harness-audit`: run `sungen audit --screen ${input:name}` (structural), THEN do an **independent semantic review inline** using the `sungen-reviewer` criteria (does each scenario's steps PROVE its title/viewpoint? observable Thens? business-critical assertion depth?). Merge both sets of issues; if gate FAILs / findings exist, repair (budget 3) and re-audit — GATE missing theme → generate it (cross-screen → **automate it in the flow** via `/sungen:add-flow`, NOT a full `@manual` screen duplicate — `sungen audit` flags an automatable `@manual` as `MANUAL-AUTOMATABLE`; reserve `@manual:Mx` for true judgment/missing-capability); DEPTH → add data assertions; BALANCE → add business-core first; TRACE → align VP ids. Never fake a pass.
|
|
304
|
+
5.5. **Quality gate & repair (harness — always run).** Per `sungen-harness-audit`: run `sungen audit --screen ${input:name}` (structural), THEN do an **independent semantic review inline** using the `sungen-reviewer` criteria (does each scenario's steps PROVE its title/viewpoint? observable Thens? business-critical assertion depth?). Merge both sets of issues; if gate FAILs / findings exist, repair (budget 3) and re-audit — GATE missing theme → generate it (cross-screen → **automate it in the flow** via `/sungen:add-flow`, NOT a full `@manual` screen duplicate — `sungen audit` flags an automatable `@manual` as `MANUAL-AUTOMATABLE`; reserve `@manual:Mx` for true judgment/missing-capability); DEPTH → add data assertions; BALANCE → add business-core first; TRACE → align VP ids. Never fake a pass. Repair never edits a QA-written viewpoint (mode 1): a finding whose fix is an edit to `test-viewpoint.md` and cites one of its VP ids becomes a row in `viewpoint-review.md`; in a mode-2 draft, fix the draft.
|
|
301
305
|
5.6. **Record.** `sungen manifest --screen ${input:name}`. Ledger **each phase** (not just repair) — pick one `runId` at the start and pass it so `trace`/`ledger report` show THIS run, not a mix: `sungen ledger record --screen ${input:name} --run <runId> --step <discovery|viewpoint|gherkin|audit|repair:N> --ms <elapsed>`. On re-run, start with `sungen manifest --screen ${input:name} --diff` and only regenerate changed sections.
|
|
302
306
|
6. **Converge — show the trace.** Run `sungen trace --screen ${input:name}` and present: process map (phases + repair rounds), bottlenecks, **HUMAN-LOOP FOCUS** (@manual to verify), audit score + gate + residual gaps. Then offer next steps based on which tier was just generated:
|
|
303
307
|
{{/cap}}
|
|
@@ -363,9 +367,13 @@ Do not stop after writing the files. Close every run with, in this order:
|
|
|
363
367
|
1. **The traceability check below** — an untagged requirement becomes an uncovered gap at delivery.
|
|
364
368
|
2. **The harness result in one line** — score, gate verdict, and the axis the `SCORE-CAPPED` finding
|
|
365
369
|
names (that finding is the single answer to "how do I raise the score").
|
|
366
|
-
3.
|
|
370
|
+
3. **The viewpoint review in one line** — `Viewpoint review: N điểm cần QA xem` (N = the `[ ]` rows
|
|
371
|
+
of `requirements/viewpoint-review.md`).
|
|
372
|
+
4. **`AskUserQuestion` with the next actions** — never end with prose alone. Offer
|
|
367
373
|
`/sungen:run-test <name>` (recommended once the tiers are written), re-running `create-test` to
|
|
368
|
-
extend, and "Done for now".
|
|
374
|
+
extend, "Mở viewpoint-review.md" when N > 0, and "Done for now". After a mode-2 draft also list
|
|
375
|
+
the decision `sungen audit --screen <name> --accept-viewpoint` — for the QA to run once the draft
|
|
376
|
+
is reviewed; you never run it yourself. A run that ends without this leaves the operator guessing.
|
|
369
377
|
|
|
370
378
|
### Requirement traceability
|
|
371
379
|
|