@sun-asterisk/sungen 3.2.2 → 3.2.3-beta.3
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/capabilities/discover.d.ts.map +1 -1
- package/dist/capabilities/discover.js +26 -3
- package/dist/capabilities/discover.js.map +1 -1
- package/dist/cli/commands/add-flow.d.ts.map +1 -1
- package/dist/cli/commands/add-flow.js +2 -0
- package/dist/cli/commands/add-flow.js.map +1 -1
- package/dist/cli/commands/add.d.ts.map +1 -1
- package/dist/cli/commands/add.js +4 -0
- package/dist/cli/commands/add.js.map +1 -1
- package/dist/cli/commands/capability.d.ts.map +1 -1
- package/dist/cli/commands/capability.js +61 -0
- package/dist/cli/commands/capability.js.map +1 -1
- package/dist/cli/commands/delivery.d.ts.map +1 -1
- package/dist/cli/commands/delivery.js +89 -2
- package/dist/cli/commands/delivery.js.map +1 -1
- package/dist/cli/commands/eval.js +3 -3
- package/dist/cli/commands/eval.js.map +1 -1
- package/dist/cli/commands/gate.d.ts +3 -0
- package/dist/cli/commands/gate.d.ts.map +1 -0
- package/dist/cli/commands/gate.js +83 -0
- package/dist/cli/commands/gate.js.map +1 -0
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +2 -1
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +32 -2
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/journey.d.ts +3 -0
- package/dist/cli/commands/journey.d.ts.map +1 -0
- package/dist/cli/commands/journey.js +114 -0
- package/dist/cli/commands/journey.js.map +1 -0
- package/dist/cli/commands/update.d.ts.map +1 -1
- package/dist/cli/commands/update.js +10 -3
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/index.js +4 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/dashboard/snapshot-builder.d.ts.map +1 -1
- package/dist/dashboard/snapshot-builder.js +10 -1
- package/dist/dashboard/snapshot-builder.js.map +1 -1
- package/dist/exporters/csv-exporter.d.ts.map +1 -1
- package/dist/exporters/csv-exporter.js +3 -1
- package/dist/exporters/csv-exporter.js.map +1 -1
- package/dist/exporters/json-exporter.js +3 -1
- package/dist/exporters/json-exporter.js.map +1 -1
- package/dist/exporters/mobile-app-id.d.ts +22 -0
- package/dist/exporters/mobile-app-id.d.ts.map +1 -0
- package/dist/exporters/mobile-app-id.js +37 -0
- package/dist/exporters/mobile-app-id.js.map +1 -0
- package/dist/exporters/spec-parser.d.ts.map +1 -1
- package/dist/exporters/spec-parser.js +6 -2
- package/dist/exporters/spec-parser.js.map +1 -1
- package/dist/generators/test-generator/adapters/adapter-interface.d.ts +3 -0
- package/dist/generators/test-generator/adapters/adapter-interface.d.ts.map +1 -1
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/scroll-action.hbs +7 -4
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/toggle-action.hbs +20 -3
- package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/checked-assertion.hbs +4 -1
- package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/not-checked-assertion.hbs +4 -1
- package/dist/generators/test-generator/adapters/appium/templates/test-file.hbs +3 -0
- package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
- package/dist/generators/test-generator/code-generator.js +48 -9
- package/dist/generators/test-generator/code-generator.js.map +1 -1
- package/dist/generators/test-generator/template-engine.d.ts +3 -0
- package/dist/generators/test-generator/template-engine.d.ts.map +1 -1
- package/dist/generators/test-generator/template-engine.js +11 -1
- package/dist/generators/test-generator/template-engine.js.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.d.ts +11 -1
- package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.js +33 -0
- package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
- package/dist/harness/audit.d.ts.map +1 -1
- package/dist/harness/audit.js +8 -1
- package/dist/harness/audit.js.map +1 -1
- package/dist/harness/catalog/universal-viewpoints.yaml +15 -0
- package/dist/harness/eval/skill-lint.d.ts +3 -3
- package/dist/harness/eval/skill-lint.d.ts.map +1 -1
- package/dist/harness/eval/skill-lint.js +88 -68
- package/dist/harness/eval/skill-lint.js.map +1 -1
- package/dist/harness/journey.d.ts +88 -0
- package/dist/harness/journey.d.ts.map +1 -0
- package/dist/harness/journey.js +414 -0
- package/dist/harness/journey.js.map +1 -0
- package/dist/harness/quality-gates.d.ts +13 -0
- package/dist/harness/quality-gates.d.ts.map +1 -1
- package/dist/harness/quality-gates.js +23 -0
- package/dist/harness/quality-gates.js.map +1 -1
- package/dist/harness/sensors.d.ts +1 -1
- package/dist/harness/sensors.d.ts.map +1 -1
- package/dist/harness/sensors.js +32 -9
- package/dist/harness/sensors.js.map +1 -1
- package/dist/orchestrator/ai-rules-updater.d.ts +11 -3
- package/dist/orchestrator/ai-rules-updater.d.ts.map +1 -1
- package/dist/orchestrator/ai-rules-updater.js +44 -180
- package/dist/orchestrator/ai-rules-updater.js.map +1 -1
- package/dist/orchestrator/ai-skills/adapters.d.ts +28 -0
- package/dist/orchestrator/ai-skills/adapters.d.ts.map +1 -0
- package/dist/orchestrator/ai-skills/adapters.js +34 -0
- package/dist/orchestrator/ai-skills/adapters.js.map +1 -0
- package/dist/orchestrator/ai-skills/build.d.ts +10 -0
- package/dist/orchestrator/ai-skills/build.d.ts.map +1 -0
- package/dist/orchestrator/ai-skills/build.js +128 -0
- package/dist/orchestrator/ai-skills/build.js.map +1 -0
- package/dist/orchestrator/ai-skills/cap-stripper.d.ts +27 -0
- package/dist/orchestrator/ai-skills/cap-stripper.d.ts.map +1 -0
- package/dist/orchestrator/ai-skills/cap-stripper.js +78 -0
- package/dist/orchestrator/ai-skills/cap-stripper.js.map +1 -0
- package/dist/orchestrator/ai-skills/commands.d.ts +22 -0
- package/dist/orchestrator/ai-skills/commands.d.ts.map +1 -0
- package/dist/orchestrator/ai-skills/commands.js +109 -0
- package/dist/orchestrator/ai-skills/commands.js.map +1 -0
- package/dist/orchestrator/ai-skills/generator.d.ts +23 -0
- package/dist/orchestrator/ai-skills/generator.d.ts.map +1 -0
- package/dist/orchestrator/ai-skills/generator.js +79 -0
- package/dist/orchestrator/ai-skills/generator.js.map +1 -0
- package/dist/orchestrator/ai-skills/golden-skills.test.d.ts +2 -0
- package/dist/orchestrator/ai-skills/golden-skills.test.d.ts.map +1 -0
- package/dist/orchestrator/ai-skills/golden-skills.test.js +183 -0
- package/dist/orchestrator/ai-skills/golden-skills.test.js.map +1 -0
- package/dist/orchestrator/ai-skills/resolve-assistants.d.ts +8 -0
- package/dist/orchestrator/ai-skills/resolve-assistants.d.ts.map +1 -0
- package/dist/orchestrator/ai-skills/resolve-assistants.js +28 -0
- package/dist/orchestrator/ai-skills/resolve-assistants.js.map +1 -0
- package/dist/orchestrator/ai-skills/writer.d.ts +15 -0
- package/dist/orchestrator/ai-skills/writer.d.ts.map +1 -0
- package/dist/orchestrator/ai-skills/writer.js +129 -0
- package/dist/orchestrator/ai-skills/writer.js.map +1 -0
- package/dist/orchestrator/flow-manager.d.ts +11 -0
- package/dist/orchestrator/flow-manager.d.ts.map +1 -1
- package/dist/orchestrator/flow-manager.js +147 -29
- package/dist/orchestrator/flow-manager.js.map +1 -1
- package/dist/orchestrator/mobile-runtime-scaffolder.d.ts +59 -0
- package/dist/orchestrator/mobile-runtime-scaffolder.d.ts.map +1 -0
- package/dist/orchestrator/mobile-runtime-scaffolder.js +298 -0
- package/dist/orchestrator/mobile-runtime-scaffolder.js.map +1 -0
- package/dist/orchestrator/project-initializer.d.ts +44 -7
- package/dist/orchestrator/project-initializer.d.ts.map +1 -1
- package/dist/orchestrator/project-initializer.js +147 -79
- package/dist/orchestrator/project-initializer.js.map +1 -1
- package/dist/orchestrator/screen-manager.d.ts +30 -0
- package/dist/orchestrator/screen-manager.d.ts.map +1 -1
- package/dist/orchestrator/screen-manager.js +205 -22
- package/dist/orchestrator/screen-manager.js.map +1 -1
- package/dist/orchestrator/templates/ai-src/README.md +58 -0
- package/dist/orchestrator/templates/{ai-instructions/claude-cmd-add-flow.md → ai-src/commands/add-flow.md} +63 -2
- package/dist/orchestrator/templates/{ai-instructions/claude-cmd-add-screen.md → ai-src/commands/add-screen.md} +171 -6
- package/dist/orchestrator/templates/{ai-instructions/claude-cmd-create-test.md → ai-src/commands/create-test.md} +118 -4
- package/{src/orchestrator/templates/ai-instructions/claude-cmd-dashboard.md → dist/orchestrator/templates/ai-src/commands/dashboard.md} +25 -3
- package/{src/orchestrator/templates/ai-instructions/claude-cmd-delivery.md → dist/orchestrator/templates/ai-src/commands/delivery.md} +67 -3
- package/dist/orchestrator/templates/ai-src/commands/design.md +29 -0
- package/{src/orchestrator/templates/ai-instructions/claude-cmd-feedback.md → dist/orchestrator/templates/ai-src/commands/feedback.md} +34 -3
- package/dist/orchestrator/templates/{ai-instructions/claude-cmd-locale.md → ai-src/commands/locale.md} +56 -4
- package/{src/orchestrator/templates/ai-instructions/claude-cmd-review.md → dist/orchestrator/templates/ai-src/commands/review.md} +57 -2
- package/{src/orchestrator/templates/ai-instructions/claude-cmd-run-test.md → dist/orchestrator/templates/ai-src/commands/run-test.md} +116 -5
- package/dist/orchestrator/templates/ai-src/config/codex.md +8 -0
- package/{src/orchestrator/templates/ai-instructions/claude-skill-capture-mobile.md → dist/orchestrator/templates/ai-src/skills/sungen-capture-mobile/SKILL.md} +11 -0
- package/dist/orchestrator/templates/{ai-instructions/github-skill-sungen-error-mapping.md → ai-src/skills/sungen-error-mapping/SKILL.md} +49 -9
- package/{src/orchestrator/templates/ai-instructions/claude-skill-harness-audit.md → dist/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md} +5 -5
- package/{src/orchestrator/templates/ai-instructions/claude-skill-locale.md → dist/orchestrator/templates/ai-src/skills/sungen-locale/SKILL.md} +275 -3
- package/{src/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix.md → dist/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md} +17 -0
- package/dist/orchestrator/templates/{ai-instructions/claude-skill-selector-fix-mobile.md → ai-src/skills/sungen-selector-fix-mobile/SKILL.md} +5 -0
- package/dist/orchestrator/templates/{ai-instructions/claude-skill-tc-generation.md → ai-src/skills/sungen-tc-generation/SKILL.md} +5 -0
- package/dist/orchestrator/templates/playwright.config.ts +7 -4
- package/package.json +3 -3
- package/src/capabilities/discover.ts +29 -3
- package/src/cli/commands/add-flow.ts +2 -0
- package/src/cli/commands/add.ts +4 -0
- package/src/cli/commands/capability.ts +64 -1
- package/src/cli/commands/delivery.ts +89 -2
- package/src/cli/commands/eval.ts +3 -3
- package/src/cli/commands/gate.ts +44 -0
- package/src/cli/commands/generate.ts +2 -1
- package/src/cli/commands/init.ts +50 -3
- package/src/cli/commands/journey.ts +72 -0
- package/src/cli/commands/update.ts +14 -4
- package/src/cli/index.ts +4 -0
- package/src/dashboard/snapshot-builder.ts +10 -1
- package/src/exporters/csv-exporter.ts +3 -1
- package/src/exporters/json-exporter.ts +3 -1
- package/src/exporters/mobile-app-id.ts +34 -0
- package/src/exporters/spec-parser.ts +6 -2
- package/src/generators/test-generator/adapters/adapter-interface.ts +3 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/scroll-action.hbs +7 -4
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/toggle-action.hbs +20 -3
- package/src/generators/test-generator/adapters/appium/templates/steps/assertions/checked-assertion.hbs +4 -1
- package/src/generators/test-generator/adapters/appium/templates/steps/assertions/not-checked-assertion.hbs +4 -1
- package/src/generators/test-generator/adapters/appium/templates/test-file.hbs +3 -0
- package/src/generators/test-generator/code-generator.ts +49 -9
- package/src/generators/test-generator/template-engine.ts +14 -1
- package/src/generators/test-generator/utils/selector-resolver.ts +51 -1
- package/src/harness/audit.ts +9 -2
- package/src/harness/catalog/universal-viewpoints.yaml +15 -0
- package/src/harness/eval/skill-lint.ts +71 -60
- package/src/harness/journey.ts +434 -0
- package/src/harness/quality-gates.ts +20 -0
- package/src/harness/sensors.ts +25 -8
- package/src/orchestrator/ai-rules-updater.ts +35 -197
- package/src/orchestrator/ai-skills/adapters.ts +52 -0
- package/src/orchestrator/ai-skills/build.ts +103 -0
- package/src/orchestrator/ai-skills/cap-stripper.ts +85 -0
- package/src/orchestrator/ai-skills/commands.ts +112 -0
- package/src/orchestrator/ai-skills/generator.ts +47 -0
- package/src/orchestrator/ai-skills/golden-skills.test.ts +124 -0
- package/src/orchestrator/ai-skills/resolve-assistants.ts +18 -0
- package/src/orchestrator/ai-skills/writer.ts +92 -0
- package/src/orchestrator/flow-manager.ts +165 -29
- package/src/orchestrator/mobile-runtime-scaffolder.ts +277 -0
- package/src/orchestrator/project-initializer.ts +159 -86
- package/src/orchestrator/screen-manager.ts +237 -22
- package/src/orchestrator/templates/ai-src/README.md +58 -0
- package/src/orchestrator/templates/{ai-instructions/claude-cmd-add-flow.md → ai-src/commands/add-flow.md} +63 -2
- package/src/orchestrator/templates/{ai-instructions/claude-cmd-add-screen.md → ai-src/commands/add-screen.md} +171 -6
- package/src/orchestrator/templates/{ai-instructions/claude-cmd-create-test.md → ai-src/commands/create-test.md} +118 -4
- package/{dist/orchestrator/templates/ai-instructions/claude-cmd-dashboard.md → src/orchestrator/templates/ai-src/commands/dashboard.md} +25 -3
- package/{dist/orchestrator/templates/ai-instructions/claude-cmd-delivery.md → src/orchestrator/templates/ai-src/commands/delivery.md} +67 -3
- package/src/orchestrator/templates/ai-src/commands/design.md +29 -0
- package/{dist/orchestrator/templates/ai-instructions/claude-cmd-feedback.md → src/orchestrator/templates/ai-src/commands/feedback.md} +34 -3
- package/src/orchestrator/templates/{ai-instructions/claude-cmd-locale.md → ai-src/commands/locale.md} +56 -4
- package/{dist/orchestrator/templates/ai-instructions/claude-cmd-review.md → src/orchestrator/templates/ai-src/commands/review.md} +57 -2
- package/{dist/orchestrator/templates/ai-instructions/claude-cmd-run-test.md → src/orchestrator/templates/ai-src/commands/run-test.md} +116 -5
- package/src/orchestrator/templates/ai-src/config/codex.md +8 -0
- package/{dist/orchestrator/templates/ai-instructions/claude-skill-capture-mobile.md → src/orchestrator/templates/ai-src/skills/sungen-capture-mobile/SKILL.md} +11 -0
- package/{dist/orchestrator/templates/ai-instructions/claude-skill-error-mapping.md → src/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md} +49 -9
- package/{dist/orchestrator/templates/ai-instructions/claude-skill-harness-audit.md → src/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md} +5 -5
- package/{dist/orchestrator/templates/ai-instructions/claude-skill-locale.md → src/orchestrator/templates/ai-src/skills/sungen-locale/SKILL.md} +275 -3
- package/{dist/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix.md → src/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md} +17 -0
- package/src/orchestrator/templates/{ai-instructions/claude-skill-selector-fix-mobile.md → ai-src/skills/sungen-selector-fix-mobile/SKILL.md} +5 -0
- package/src/orchestrator/templates/{ai-instructions/claude-skill-tc-generation.md → ai-src/skills/sungen-tc-generation/SKILL.md} +5 -0
- package/src/orchestrator/templates/playwright.config.ts +7 -4
- package/dist/orchestrator/templates/ai-instructions/claude-cmd-design.md +0 -12
- package/dist/orchestrator/templates/ai-instructions/claude-skill-selector-fix.md +0 -347
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-add-flow.md +0 -86
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-add-screen.md +0 -131
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-create-test.md +0 -93
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-dashboard.md +0 -65
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-delivery.md +0 -83
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-design.md +0 -13
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-feedback.md +0 -24
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-locale.md +0 -70
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-review.md +0 -38
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-run-test.md +0 -155
- package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-capture-mobile.md +0 -184
- package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-harness-audit.md +0 -85
- package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-locale.md +0 -291
- package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix-mobile.md +0 -316
- package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-selector-keys.md +0 -221
- package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-tc-generation.md +0 -617
- package/src/orchestrator/templates/ai-instructions/claude-cmd-design.md +0 -12
- package/src/orchestrator/templates/ai-instructions/claude-skill-api-design.md +0 -62
- package/src/orchestrator/templates/ai-instructions/claude-skill-capture-mode-figma-mcp.md +0 -82
- package/src/orchestrator/templates/ai-instructions/claude-skill-capture-mode-figma-pat.md +0 -117
- package/src/orchestrator/templates/ai-instructions/claude-skill-capture-mode-live.md +0 -60
- package/src/orchestrator/templates/ai-instructions/claude-skill-capture-mode-local.md +0 -38
- package/src/orchestrator/templates/ai-instructions/claude-skill-capture.md +0 -35
- package/src/orchestrator/templates/ai-instructions/claude-skill-dashboard.md +0 -121
- package/src/orchestrator/templates/ai-instructions/claude-skill-delivery.md +0 -141
- package/src/orchestrator/templates/ai-instructions/claude-skill-error-mapping.md +0 -157
- package/src/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +0 -446
- package/src/orchestrator/templates/ai-instructions/claude-skill-ingest-legacy.md +0 -79
- package/src/orchestrator/templates/ai-instructions/claude-skill-mobile-gestures.md +0 -109
- package/src/orchestrator/templates/ai-instructions/claude-skill-selector-fix.md +0 -347
- package/src/orchestrator/templates/ai-instructions/claude-skill-tc-review.md +0 -320
- package/src/orchestrator/templates/ai-instructions/claude-skill-test-design-techniques.md +0 -118
- package/src/orchestrator/templates/ai-instructions/claude-skill-viewpoint-group-a-data-entry.md +0 -203
- package/src/orchestrator/templates/ai-instructions/claude-skill-viewpoint-group-b-data-ops.md +0 -179
- package/src/orchestrator/templates/ai-instructions/claude-skill-viewpoint-group-c-data-explore.md +0 -233
- package/src/orchestrator/templates/ai-instructions/claude-skill-viewpoint-group-d-display.md +0 -226
- package/src/orchestrator/templates/ai-instructions/claude-skill-viewpoint-group-e-identity.md +0 -177
- package/src/orchestrator/templates/ai-instructions/claude-skill-viewpoint.md +0 -118
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-add-flow.md +0 -86
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-add-screen.md +0 -131
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-create-test.md +0 -93
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-dashboard.md +0 -65
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-delivery.md +0 -83
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-design.md +0 -13
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-feedback.md +0 -24
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-locale.md +0 -70
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-review.md +0 -38
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-run-test.md +0 -155
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-api-design.md +0 -62
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-capture-mobile.md +0 -184
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-capture-mode-figma-mcp.md +0 -82
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-capture-mode-figma-pat.md +0 -117
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-capture-mode-live.md +0 -60
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-capture-mode-local.md +0 -38
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-capture.md +0 -35
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-dashboard.md +0 -121
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-delivery.md +0 -141
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-error-mapping.md +0 -157
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +0 -446
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-harness-audit.md +0 -85
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-ingest-legacy.md +0 -79
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-locale.md +0 -291
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-mobile-gestures.md +0 -109
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix-mobile.md +0 -316
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-selector-keys.md +0 -221
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-tc-generation.md +0 -617
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-tc-review.md +0 -320
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-test-design-techniques.md +0 -118
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-viewpoint-group-a-data-entry.md +0 -203
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-viewpoint-group-b-data-ops.md +0 -179
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-viewpoint-group-c-data-explore.md +0 -233
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-viewpoint-group-d-display.md +0 -226
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-viewpoint-group-e-identity.md +0 -177
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-viewpoint.md +0 -118
- /package/dist/orchestrator/templates/{ai-instructions/claude-agent-challenge.md → ai-src/agents/challenge.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-agent-discovery.md → ai-src/agents/discovery.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-agent-generator.md → ai-src/agents/generator.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-agent-reviewer.md → ai-src/agents/reviewer.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-config.md → ai-src/config/claude.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/copilot-config.md → ai-src/config/copilot.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-skill-api-design.md → ai-src/skills/sungen-api-design/SKILL.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-skill-capture.md → ai-src/skills/sungen-capture/SKILL.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-skill-capture-mode-figma-mcp.md → ai-src/skills/sungen-capture/mode-figma-mcp.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-skill-capture-mode-figma-pat.md → ai-src/skills/sungen-capture/mode-figma-pat.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-skill-capture-mode-live.md → ai-src/skills/sungen-capture/mode-live.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-skill-capture-mode-local.md → ai-src/skills/sungen-capture/mode-local.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-skill-dashboard.md → ai-src/skills/sungen-dashboard/SKILL.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-skill-delivery.md → ai-src/skills/sungen-delivery/SKILL.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-skill-gherkin-syntax.md → ai-src/skills/sungen-gherkin-syntax/SKILL.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-skill-ingest-legacy.md → ai-src/skills/sungen-ingest-legacy/SKILL.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-skill-mobile-gestures.md → ai-src/skills/sungen-mobile-gestures/SKILL.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-skill-selector-keys.md → ai-src/skills/sungen-selector-keys/SKILL.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-skill-tc-review.md → ai-src/skills/sungen-tc-review/SKILL.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-skill-test-design-techniques.md → ai-src/skills/sungen-test-design-techniques/SKILL.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-skill-viewpoint.md → ai-src/skills/sungen-viewpoint/SKILL.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-skill-viewpoint-group-a-data-entry.md → ai-src/skills/sungen-viewpoint/group-a-data-entry.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-skill-viewpoint-group-b-data-ops.md → ai-src/skills/sungen-viewpoint/group-b-data-ops.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-skill-viewpoint-group-c-data-explore.md → ai-src/skills/sungen-viewpoint/group-c-data-explore.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-skill-viewpoint-group-d-display.md → ai-src/skills/sungen-viewpoint/group-d-display.md} +0 -0
- /package/dist/orchestrator/templates/{ai-instructions/claude-skill-viewpoint-group-e-identity.md → ai-src/skills/sungen-viewpoint/group-e-identity.md} +0 -0
- /package/src/orchestrator/templates/{ai-instructions/claude-agent-challenge.md → ai-src/agents/challenge.md} +0 -0
- /package/src/orchestrator/templates/{ai-instructions/claude-agent-discovery.md → ai-src/agents/discovery.md} +0 -0
- /package/src/orchestrator/templates/{ai-instructions/claude-agent-generator.md → ai-src/agents/generator.md} +0 -0
- /package/src/orchestrator/templates/{ai-instructions/claude-agent-reviewer.md → ai-src/agents/reviewer.md} +0 -0
- /package/src/orchestrator/templates/{ai-instructions/claude-config.md → ai-src/config/claude.md} +0 -0
- /package/src/orchestrator/templates/{ai-instructions/copilot-config.md → ai-src/config/copilot.md} +0 -0
- /package/{dist/orchestrator/templates/ai-instructions/github-skill-sungen-api-design.md → src/orchestrator/templates/ai-src/skills/sungen-api-design/SKILL.md} +0 -0
- /package/{dist/orchestrator/templates/ai-instructions/github-skill-sungen-capture.md → src/orchestrator/templates/ai-src/skills/sungen-capture/SKILL.md} +0 -0
- /package/{dist/orchestrator/templates/ai-instructions/github-skill-sungen-capture-mode-figma-mcp.md → src/orchestrator/templates/ai-src/skills/sungen-capture/mode-figma-mcp.md} +0 -0
- /package/{dist/orchestrator/templates/ai-instructions/github-skill-sungen-capture-mode-figma-pat.md → src/orchestrator/templates/ai-src/skills/sungen-capture/mode-figma-pat.md} +0 -0
- /package/{dist/orchestrator/templates/ai-instructions/github-skill-sungen-capture-mode-live.md → src/orchestrator/templates/ai-src/skills/sungen-capture/mode-live.md} +0 -0
- /package/{dist/orchestrator/templates/ai-instructions/github-skill-sungen-capture-mode-local.md → src/orchestrator/templates/ai-src/skills/sungen-capture/mode-local.md} +0 -0
- /package/{dist/orchestrator/templates/ai-instructions/github-skill-sungen-dashboard.md → src/orchestrator/templates/ai-src/skills/sungen-dashboard/SKILL.md} +0 -0
- /package/{dist/orchestrator/templates/ai-instructions/github-skill-sungen-delivery.md → src/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md} +0 -0
- /package/{dist/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md → src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md} +0 -0
- /package/{dist/orchestrator/templates/ai-instructions/github-skill-sungen-ingest-legacy.md → src/orchestrator/templates/ai-src/skills/sungen-ingest-legacy/SKILL.md} +0 -0
- /package/{dist/orchestrator/templates/ai-instructions/github-skill-sungen-mobile-gestures.md → src/orchestrator/templates/ai-src/skills/sungen-mobile-gestures/SKILL.md} +0 -0
- /package/src/orchestrator/templates/{ai-instructions/claude-skill-selector-keys.md → ai-src/skills/sungen-selector-keys/SKILL.md} +0 -0
- /package/{dist/orchestrator/templates/ai-instructions/github-skill-sungen-tc-review.md → src/orchestrator/templates/ai-src/skills/sungen-tc-review/SKILL.md} +0 -0
- /package/{dist/orchestrator/templates/ai-instructions/github-skill-sungen-test-design-techniques.md → src/orchestrator/templates/ai-src/skills/sungen-test-design-techniques/SKILL.md} +0 -0
- /package/{dist/orchestrator/templates/ai-instructions/github-skill-sungen-viewpoint.md → src/orchestrator/templates/ai-src/skills/sungen-viewpoint/SKILL.md} +0 -0
- /package/{dist/orchestrator/templates/ai-instructions/github-skill-sungen-viewpoint-group-a-data-entry.md → src/orchestrator/templates/ai-src/skills/sungen-viewpoint/group-a-data-entry.md} +0 -0
- /package/{dist/orchestrator/templates/ai-instructions/github-skill-sungen-viewpoint-group-b-data-ops.md → src/orchestrator/templates/ai-src/skills/sungen-viewpoint/group-b-data-ops.md} +0 -0
- /package/{dist/orchestrator/templates/ai-instructions/github-skill-sungen-viewpoint-group-c-data-explore.md → src/orchestrator/templates/ai-src/skills/sungen-viewpoint/group-c-data-explore.md} +0 -0
- /package/{dist/orchestrator/templates/ai-instructions/github-skill-sungen-viewpoint-group-d-display.md → src/orchestrator/templates/ai-src/skills/sungen-viewpoint/group-d-display.md} +0 -0
- /package/{dist/orchestrator/templates/ai-instructions/github-skill-sungen-viewpoint-group-e-identity.md → src/orchestrator/templates/ai-src/skills/sungen-viewpoint/group-e-identity.md} +0 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Golden regression net for the single-source generator.
|
|
3
|
+
*
|
|
4
|
+
* Compares generated output for all adapters against committed fixtures under
|
|
5
|
+
* tests/golden/ai-skills/fixtures/. The fixtures were frozen from output that was proven
|
|
6
|
+
* byte-identical to the original per-assistant templates (see git history: the prior
|
|
7
|
+
* ai-instructions-based golden). From now on the fixtures ARE the contract — any change to
|
|
8
|
+
* a source skill/command must be reflected with `--update`, making every output change a
|
|
9
|
+
* reviewable diff.
|
|
10
|
+
*
|
|
11
|
+
* tsx .../golden-skills.test.ts # verify
|
|
12
|
+
* tsx .../golden-skills.test.ts --update # re-freeze fixtures after an intentional change
|
|
13
|
+
*
|
|
14
|
+
* Also runs source lint (decision 6A): required frontmatter + unique-ish command order,
|
|
15
|
+
* and a Codex flat-namespace collision check.
|
|
16
|
+
*/
|
|
17
|
+
import * as fs from 'fs';
|
|
18
|
+
import * as path from 'path';
|
|
19
|
+
import { buildOutputs } from './build';
|
|
20
|
+
import { parseCommandSource } from './commands';
|
|
21
|
+
|
|
22
|
+
const FIX = path.resolve(__dirname, '..', '..', '..', 'tests', 'golden', 'ai-skills', 'fixtures');
|
|
23
|
+
const SRC = path.resolve(__dirname, '..', 'templates', 'ai-src', 'skills');
|
|
24
|
+
const SRC_CMD = path.resolve(__dirname, '..', 'templates', 'ai-src', 'commands');
|
|
25
|
+
const UPDATE = process.argv.includes('--update');
|
|
26
|
+
|
|
27
|
+
function lint(): string[] {
|
|
28
|
+
const errs: string[] = [];
|
|
29
|
+
const fmKeys = (t: string): Set<string> => {
|
|
30
|
+
const s = new Set<string>();
|
|
31
|
+
if (!t.startsWith('---')) return s;
|
|
32
|
+
for (const l of t.slice(3, t.indexOf('\n---', 3)).split('\n')) { const m = l.match(/^([a-zA-Z_-]+):/); if (m) s.add(m[1]); }
|
|
33
|
+
return s;
|
|
34
|
+
};
|
|
35
|
+
for (const dir of fs.existsSync(SRC) ? fs.readdirSync(SRC) : []) {
|
|
36
|
+
const dp = path.join(SRC, dir);
|
|
37
|
+
if (!fs.statSync(dp).isDirectory()) continue;
|
|
38
|
+
const f = path.join(dp, 'SKILL.md');
|
|
39
|
+
if (!fs.existsSync(f)) continue;
|
|
40
|
+
const k = fmKeys(fs.readFileSync(f, 'utf8'));
|
|
41
|
+
if (!k.has('name')) errs.push(`${dir}/SKILL.md: missing frontmatter name`);
|
|
42
|
+
if (!k.has('description')) errs.push(`${dir}/SKILL.md: missing frontmatter description`);
|
|
43
|
+
}
|
|
44
|
+
const seen = new Map<string, string>();
|
|
45
|
+
for (const f of fs.existsSync(SRC_CMD) ? fs.readdirSync(SRC_CMD) : []) {
|
|
46
|
+
const c = parseCommandSource(fs.readFileSync(path.join(SRC_CMD, f), 'utf8'), f.replace(/\.md$/, ''));
|
|
47
|
+
if (!c.description) errs.push(`commands/${f}: missing description`);
|
|
48
|
+
if (c.order != null) { const k = String(c.order); if (seen.has(k)) { /* allowed: parallel entrypoints */ } else seen.set(k, f); }
|
|
49
|
+
}
|
|
50
|
+
return errs;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function run() {
|
|
54
|
+
// Guardrail: the retired per-assistant folder must never come back. Skills are authored
|
|
55
|
+
// ONCE in ai-src/. If a dev recreates ai-instructions/, fail loud with a pointer.
|
|
56
|
+
const legacyDir = path.resolve(__dirname, '..', 'templates', 'ai-instructions');
|
|
57
|
+
if (fs.existsSync(legacyDir)) {
|
|
58
|
+
console.error('GOLDEN FAILED — templates/ai-instructions/ exists again.');
|
|
59
|
+
console.error(' Author skills/commands in templates/ai-src/ ONLY (see ai-src/README.md).');
|
|
60
|
+
console.error(' The per-assistant duplicates are generated from ai-src by ai-skills/build.ts.');
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const lintErrs = lint();
|
|
65
|
+
// stripCaps throws on unknown cap tag / unclosed fence, so buildOutputs validates fences.
|
|
66
|
+
const outputs = buildOutputs(['claude', 'copilot', 'codex']);
|
|
67
|
+
|
|
68
|
+
// Codex has ONE flat .agents/skills/ namespace — every discovered SKILL.md `name:` must be
|
|
69
|
+
// unique, or `$name`/description selection is ambiguous (regression guard for the command vs
|
|
70
|
+
// backing-skill collision: dashboard/delivery/locale must be <name> vs <name>-guide).
|
|
71
|
+
const codexNames = new Map<string, string>();
|
|
72
|
+
for (const f of outputs) {
|
|
73
|
+
if (!f.outputPath.startsWith('.agents/skills/') || !f.outputPath.endsWith('/SKILL.md')) continue;
|
|
74
|
+
const m = f.content.match(/^name:\s*(\S+)/m);
|
|
75
|
+
if (!m) continue;
|
|
76
|
+
if (codexNames.has(m[1])) lintErrs.push(`codex duplicate skill name "${m[1]}" (${f.outputPath} & ${codexNames.get(m[1])})`);
|
|
77
|
+
else codexNames.set(m[1], f.outputPath);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (UPDATE) {
|
|
81
|
+
fs.rmSync(FIX, { recursive: true, force: true });
|
|
82
|
+
for (const f of outputs) {
|
|
83
|
+
const abs = path.join(FIX, f.outputPath);
|
|
84
|
+
fs.mkdirSync(path.dirname(abs), { recursive: true });
|
|
85
|
+
fs.writeFileSync(abs, f.content);
|
|
86
|
+
}
|
|
87
|
+
console.log(`✓ froze ${outputs.length} fixtures -> tests/golden/ai-skills/fixtures/`);
|
|
88
|
+
if (lintErrs.length) { console.error('source lint errors:'); lintErrs.forEach((e) => console.error(' ✗ ' + e)); process.exit(1); }
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
let pass = 0; const mismatches: string[] = []; const missing: string[] = [];
|
|
93
|
+
const expectedPaths = new Set(outputs.map((f) => f.outputPath));
|
|
94
|
+
for (const f of outputs) {
|
|
95
|
+
const abs = path.join(FIX, f.outputPath);
|
|
96
|
+
if (!fs.existsSync(abs)) { missing.push(f.outputPath); continue; }
|
|
97
|
+
if (fs.readFileSync(abs, 'utf8') === f.content) pass++;
|
|
98
|
+
else mismatches.push(f.outputPath);
|
|
99
|
+
}
|
|
100
|
+
// fixtures present but no longer generated => stale
|
|
101
|
+
const stale: string[] = [];
|
|
102
|
+
const walk = (d: string, base = '') => {
|
|
103
|
+
if (!fs.existsSync(d)) return;
|
|
104
|
+
for (const e of fs.readdirSync(d, { withFileTypes: true })) {
|
|
105
|
+
const rel = path.join(base, e.name);
|
|
106
|
+
if (e.isDirectory()) walk(path.join(d, e.name), rel);
|
|
107
|
+
else if (!expectedPaths.has(rel)) stale.push(rel);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
walk(FIX);
|
|
111
|
+
|
|
112
|
+
console.log(`GOLDEN — source lint: ${lintErrs.length === 0 ? 'PASS' : lintErrs.length + ' error(s)'}`);
|
|
113
|
+
lintErrs.forEach((e) => console.log(' ✗ ' + e));
|
|
114
|
+
console.log(`GOLDEN — fixtures: ${pass}/${outputs.length} match | mismatch ${mismatches.length} | missing ${missing.length} | stale ${stale.length}`);
|
|
115
|
+
[...mismatches.map((m) => 'MISMATCH ' + m), ...missing.map((m) => 'MISSING ' + m), ...stale.map((s) => 'STALE ' + s)].forEach((x) => console.log(' ✗ ' + x));
|
|
116
|
+
|
|
117
|
+
if (lintErrs.length || mismatches.length || missing.length || stale.length) {
|
|
118
|
+
console.error('GOLDEN FAILED — run with --update if the change was intentional, then review the diff.');
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
console.log('✓ GOLDEN PASS — all adapter output matches frozen fixtures.');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
run();
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { AdapterKey, ALL_ADAPTERS } from './adapters';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Resolve `--assistant` CLI values to adapter keys.
|
|
5
|
+
* Empty -> ['claude'] (decision T5: never silently install all into a single-assistant repo).
|
|
6
|
+
* 'all' -> every adapter. Unknown values throw.
|
|
7
|
+
*/
|
|
8
|
+
export function resolveAssistants(input: string[] | undefined): AdapterKey[] {
|
|
9
|
+
if (!input || input.length === 0) return ['claude'];
|
|
10
|
+
const set = new Set<AdapterKey>();
|
|
11
|
+
for (const raw of input) {
|
|
12
|
+
const v = raw.toLowerCase().trim();
|
|
13
|
+
if (v === 'all') { ALL_ADAPTERS.forEach((a) => set.add(a)); continue; }
|
|
14
|
+
if (v === 'claude' || v === 'copilot' || v === 'codex') { set.add(v); continue; }
|
|
15
|
+
throw new Error(`Unknown --assistant "${raw}" (valid: claude, copilot, codex, all)`);
|
|
16
|
+
}
|
|
17
|
+
return [...set];
|
|
18
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* applyOutputs — write a BuiltFile[] to disk with the agreed semantics (decisions 2, T2).
|
|
3
|
+
*
|
|
4
|
+
* managed (skills/commands): ALWAYS overwritten (version-managed, no rollback)
|
|
5
|
+
* config (CLAUDE.md/AGENTS.md/copilot-instructions): skip-if-exists unless `force`
|
|
6
|
+
* orphans: managed files written last run but not this run are DELETED (manifest-derived,
|
|
7
|
+
* replaces the hand-curated STALE list — decision T2)
|
|
8
|
+
* detect-and-warn: if a managed file on disk was hand-edited since we wrote it, warn
|
|
9
|
+
* dry-run: report adds/overwrites/skips/deletes/warnings without touching disk
|
|
10
|
+
*
|
|
11
|
+
* Manifest: <cwd>/.sungen/manifest.json = { version, managed: { <path>: <sha256> } }
|
|
12
|
+
*/
|
|
13
|
+
import * as fs from 'fs';
|
|
14
|
+
import * as path from 'path';
|
|
15
|
+
import * as crypto from 'crypto';
|
|
16
|
+
import { BuiltFile } from './build';
|
|
17
|
+
|
|
18
|
+
export interface ApplyOptions { force?: boolean; dryRun?: boolean; version: string }
|
|
19
|
+
export interface ApplyReport {
|
|
20
|
+
created: string[]; overwritten: string[]; skippedConfig: string[];
|
|
21
|
+
deletedOrphans: string[]; handEditWarnings: string[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const MANIFEST_REL = path.join('.sungen', 'manifest.json');
|
|
25
|
+
const sha = (s: string) => crypto.createHash('sha256').update(s).digest('hex');
|
|
26
|
+
|
|
27
|
+
interface Manifest { version: string; managed: Record<string, string> }
|
|
28
|
+
|
|
29
|
+
function readManifest(cwd: string): Manifest {
|
|
30
|
+
const p = path.join(cwd, MANIFEST_REL);
|
|
31
|
+
if (!fs.existsSync(p)) return { version: '', managed: {} };
|
|
32
|
+
try { return JSON.parse(fs.readFileSync(p, 'utf8')); } catch { return { version: '', managed: {} }; }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function applyOutputs(cwd: string, outputs: BuiltFile[], opts: ApplyOptions): ApplyReport {
|
|
36
|
+
const r: ApplyReport = { created: [], overwritten: [], skippedConfig: [], deletedOrphans: [], handEditWarnings: [] };
|
|
37
|
+
const prev = readManifest(cwd);
|
|
38
|
+
const newManaged: Record<string, string> = {};
|
|
39
|
+
|
|
40
|
+
const write = (rel: string, content: string) => {
|
|
41
|
+
if (opts.dryRun) return;
|
|
42
|
+
const abs = path.join(cwd, rel);
|
|
43
|
+
fs.mkdirSync(path.dirname(abs), { recursive: true });
|
|
44
|
+
fs.writeFileSync(abs, content, 'utf8');
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
for (const f of outputs) {
|
|
48
|
+
const abs = path.join(cwd, f.outputPath);
|
|
49
|
+
const exists = fs.existsSync(abs);
|
|
50
|
+
|
|
51
|
+
if (f.cls === 'config') {
|
|
52
|
+
if (exists && !opts.force) { r.skippedConfig.push(f.outputPath); continue; }
|
|
53
|
+
(exists ? r.overwritten : r.created).push(f.outputPath);
|
|
54
|
+
write(f.outputPath, f.content);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// managed: always overwrite, but warn if hand-edited since our last write
|
|
59
|
+
if (exists) {
|
|
60
|
+
const current = fs.readFileSync(abs, 'utf8');
|
|
61
|
+
const recorded = prev.managed[f.outputPath];
|
|
62
|
+
if (recorded && sha(current) !== recorded && sha(current) !== sha(f.content)) {
|
|
63
|
+
r.handEditWarnings.push(f.outputPath);
|
|
64
|
+
}
|
|
65
|
+
if (current !== f.content) r.overwritten.push(f.outputPath);
|
|
66
|
+
} else {
|
|
67
|
+
r.created.push(f.outputPath);
|
|
68
|
+
}
|
|
69
|
+
write(f.outputPath, f.content);
|
|
70
|
+
newManaged[f.outputPath] = sha(f.content);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Orphan cleanup: managed files we wrote last time but not now.
|
|
74
|
+
for (const oldPath of Object.keys(prev.managed)) {
|
|
75
|
+
if (newManaged[oldPath]) continue;
|
|
76
|
+
r.deletedOrphans.push(oldPath);
|
|
77
|
+
if (!opts.dryRun) {
|
|
78
|
+
const abs = path.join(cwd, oldPath);
|
|
79
|
+
if (fs.existsSync(abs)) fs.rmSync(abs, { force: true });
|
|
80
|
+
// prune now-empty skill dir
|
|
81
|
+
const dir = path.dirname(abs);
|
|
82
|
+
try { if (fs.existsSync(dir) && fs.readdirSync(dir).length === 0) fs.rmdirSync(dir); } catch { /* ignore */ }
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (!opts.dryRun) {
|
|
87
|
+
const mPath = path.join(cwd, MANIFEST_REL);
|
|
88
|
+
fs.mkdirSync(path.dirname(mPath), { recursive: true });
|
|
89
|
+
fs.writeFileSync(mPath, JSON.stringify({ version: opts.version, managed: newManaged }, null, 2));
|
|
90
|
+
}
|
|
91
|
+
return r;
|
|
92
|
+
}
|
|
@@ -6,11 +6,18 @@
|
|
|
6
6
|
|
|
7
7
|
import * as fs from 'fs';
|
|
8
8
|
import * as path from 'path';
|
|
9
|
+
import { readCapabilities } from '../harness/capability';
|
|
9
10
|
|
|
10
11
|
export interface FlowOptions {
|
|
11
12
|
name: string;
|
|
12
13
|
path?: string;
|
|
13
14
|
description?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Mobile navigation recipe for the flow's starting screen. A `>`-separated list of nav steps
|
|
17
|
+
* that take the app from launch to the first screen in the flow. Scaffolded into the Background.
|
|
18
|
+
* Ignored (with a warning) for web projects.
|
|
19
|
+
*/
|
|
20
|
+
reach?: string;
|
|
14
21
|
}
|
|
15
22
|
|
|
16
23
|
export class FlowManager {
|
|
@@ -25,6 +32,18 @@ export class FlowManager {
|
|
|
25
32
|
async addFlow(options: FlowOptions): Promise<void> {
|
|
26
33
|
this.validateFlowName(options.name);
|
|
27
34
|
|
|
35
|
+
// Detect project platform from qa/capabilities.yaml
|
|
36
|
+
const caps = readCapabilities(this.cwd);
|
|
37
|
+
const isMobile = caps.platform === 'mobile';
|
|
38
|
+
|
|
39
|
+
// --reach is mobile-only; warn and drop when the project is web
|
|
40
|
+
if (options.reach && !isMobile) {
|
|
41
|
+
console.warn(
|
|
42
|
+
`Warning: --reach is a mobile navigation recipe and is ignored for web projects. Dropping it.`
|
|
43
|
+
);
|
|
44
|
+
options = { ...options, reach: undefined };
|
|
45
|
+
}
|
|
46
|
+
|
|
28
47
|
const flowName = this.normalizeFlowName(options.name);
|
|
29
48
|
const flowDir = path.join(this.flowsDir, flowName);
|
|
30
49
|
|
|
@@ -59,28 +78,40 @@ export class FlowManager {
|
|
|
59
78
|
process.exit(1);
|
|
60
79
|
}
|
|
61
80
|
|
|
62
|
-
fs.writeFileSync(featurePath, this.generateFeatureTemplate(options, flowName), 'utf-8');
|
|
81
|
+
fs.writeFileSync(featurePath, this.generateFeatureTemplate(options, flowName, isMobile), 'utf-8');
|
|
63
82
|
|
|
64
83
|
const startPath = options.path || '/login';
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
const selectorLines = isMobile
|
|
85
|
+
? [
|
|
86
|
+
`# ${options.name} Flow Selectors (mobile)`,
|
|
87
|
+
`# Namespace keys by screen: "home:button", "settings:save"`,
|
|
88
|
+
`# Generated at /sungen:run-test via Appium MCP — accessibility-id preferred.`,
|
|
89
|
+
``,
|
|
90
|
+
`# "home:element":`,
|
|
91
|
+
`# type: 'accessibility-id'`,
|
|
92
|
+
`# value: 'element-id'`,
|
|
93
|
+
``,
|
|
94
|
+
]
|
|
95
|
+
: [
|
|
96
|
+
`# ${options.name} Flow Selectors`,
|
|
97
|
+
`# Namespace keys by screen to avoid duplicates: "login:submit", "awards:submit"`,
|
|
98
|
+
``,
|
|
99
|
+
`# --- Login screen ---`,
|
|
100
|
+
`login:`,
|
|
101
|
+
` type: 'page'`,
|
|
102
|
+
` value: '${startPath}'`,
|
|
103
|
+
``,
|
|
104
|
+
`# "login:email":`,
|
|
105
|
+
`# type: 'testid'`,
|
|
106
|
+
`# value: 'email-input'`,
|
|
107
|
+
``,
|
|
108
|
+
`# "login:submit":`,
|
|
109
|
+
`# type: 'role'`,
|
|
110
|
+
`# value: 'button'`,
|
|
111
|
+
`# name: 'Login'`,
|
|
112
|
+
``,
|
|
113
|
+
];
|
|
114
|
+
fs.writeFileSync(selectorPath, selectorLines.join('\n'), 'utf-8');
|
|
84
115
|
|
|
85
116
|
fs.writeFileSync(testDataPath, [
|
|
86
117
|
`# ${options.name} Flow Test Data`,
|
|
@@ -90,7 +121,7 @@ export class FlowManager {
|
|
|
90
121
|
].join('\n'), 'utf-8');
|
|
91
122
|
|
|
92
123
|
const specPath = path.join(requirementsDir, 'spec.md');
|
|
93
|
-
fs.writeFileSync(specPath, this.generateSpecTemplate(options, flowName), 'utf-8');
|
|
124
|
+
fs.writeFileSync(specPath, this.generateSpecTemplate(options, flowName, isMobile), 'utf-8');
|
|
94
125
|
|
|
95
126
|
const viewpointPath = path.join(requirementsDir, 'test-viewpoint.md');
|
|
96
127
|
fs.writeFileSync(viewpointPath, this.generateViewpointTemplate(options), 'utf-8');
|
|
@@ -104,12 +135,21 @@ export class FlowManager {
|
|
|
104
135
|
console.log(` ${path.relative(this.cwd, requirementsUiDir)}/`);
|
|
105
136
|
console.log('');
|
|
106
137
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
138
|
+
if (isMobile) {
|
|
139
|
+
console.log('Next steps:');
|
|
140
|
+
console.log(` 1. Fill requirements/spec.md with flow specification (screens, transitions, business rules)`);
|
|
141
|
+
console.log(` Use sungen-capture-mobile to scan each screen via Appium MCP`);
|
|
142
|
+
console.log(` 2. Generate test cases: /sungen:create-test ${flowName}`);
|
|
143
|
+
console.log(` 3. Compile: sungen generate --flow ${flowName} --framework appium`);
|
|
144
|
+
console.log(` 4. Run: npm run test:mobile\n`);
|
|
145
|
+
} else {
|
|
146
|
+
console.log('Next steps:');
|
|
147
|
+
console.log(` 1. Fill requirements/spec.md with flow specification (screens, transitions, business rules)`);
|
|
148
|
+
console.log(` Optionally add UI designs to requirements/ui/`);
|
|
149
|
+
console.log(` 2. Generate test cases: /sungen:create-test ${flowName}`);
|
|
150
|
+
console.log(` 3. Compile: sungen generate --flow ${flowName}`);
|
|
151
|
+
console.log(` 4. Run: npx playwright test\n`);
|
|
152
|
+
}
|
|
113
153
|
}
|
|
114
154
|
|
|
115
155
|
private validateFlowName(name: string): void {
|
|
@@ -131,7 +171,39 @@ export class FlowManager {
|
|
|
131
171
|
.replace(/-+/g, '-');
|
|
132
172
|
}
|
|
133
173
|
|
|
134
|
-
private generateSpecTemplate(options: FlowOptions, flowName: string): string {
|
|
174
|
+
private generateSpecTemplate(options: FlowOptions, flowName: string, isMobile: boolean): string {
|
|
175
|
+
if (isMobile) {
|
|
176
|
+
return `# ${options.name} Flow Specification
|
|
177
|
+
|
|
178
|
+
## Overview
|
|
179
|
+
- **Platform:** mobile (Android + iOS)
|
|
180
|
+
- **Auth Required:** no
|
|
181
|
+
- **Starting screen reach:** ${options.reach || '<!-- nav recipe to reach the first screen, e.g. "tap [Tab] > tap [Row]" -->'}
|
|
182
|
+
|
|
183
|
+
## Screens in Flow
|
|
184
|
+
<!-- List all screens this flow visits, in order -->
|
|
185
|
+
|
|
186
|
+
| # | Screen | Reach | Description |
|
|
187
|
+
|---|--------|-------|-------------|
|
|
188
|
+
| 1 | [Screen Name] | tap [element] | [What user does here] |
|
|
189
|
+
|
|
190
|
+
## Flow Steps
|
|
191
|
+
|
|
192
|
+
### Step 1: [Screen Name]
|
|
193
|
+
- **Action:** [What the user taps]
|
|
194
|
+
- **Expected:** [What should happen]
|
|
195
|
+
- **Transition:** Navigates to Step 2
|
|
196
|
+
|
|
197
|
+
## Business Rules
|
|
198
|
+
<!-- Rules that affect the flow: permissions, conditions, limits -->
|
|
199
|
+
- [Rule 1]
|
|
200
|
+
|
|
201
|
+
## Notes
|
|
202
|
+
<!-- Edge cases, known issues, environment-specific behavior -->
|
|
203
|
+
- [Note 1]
|
|
204
|
+
`;
|
|
205
|
+
}
|
|
206
|
+
|
|
135
207
|
const startPath = options.path || '/login';
|
|
136
208
|
return `# ${options.name} Flow Specification
|
|
137
209
|
|
|
@@ -215,9 +287,33 @@ export class FlowManager {
|
|
|
215
287
|
].join('\n');
|
|
216
288
|
}
|
|
217
289
|
|
|
218
|
-
private generateFeatureTemplate(options: FlowOptions, flowName: string): string {
|
|
290
|
+
private generateFeatureTemplate(options: FlowOptions, flowName: string, isMobile: boolean): string {
|
|
219
291
|
const description = options.description || `complete the ${options.name} flow`;
|
|
220
292
|
|
|
293
|
+
if (isMobile) {
|
|
294
|
+
const background = this.buildMobileBackground(options.reach);
|
|
295
|
+
return `@flow @platform:mobile
|
|
296
|
+
Feature: ${options.name} Flow
|
|
297
|
+
|
|
298
|
+
As a user
|
|
299
|
+
I want to ${description}
|
|
300
|
+
So that I can accomplish my end-to-end goal
|
|
301
|
+
|
|
302
|
+
# Mobile (Appium) flow — selectors use colon namespace: "home:element", "settings:save".
|
|
303
|
+
# See sungen-mobile-gestures for swipe/long-press/scroll steps.
|
|
304
|
+
|
|
305
|
+
${background}
|
|
306
|
+
@high
|
|
307
|
+
Scenario: Sample step for ${options.name}
|
|
308
|
+
When User tap [Home:element]
|
|
309
|
+
Then User see [Settings] screen
|
|
310
|
+
|
|
311
|
+
Scenario: Sample next step for ${options.name}
|
|
312
|
+
When User tap [Settings:element]
|
|
313
|
+
Then User see [Result:header] header with {{result_text}}
|
|
314
|
+
`;
|
|
315
|
+
}
|
|
316
|
+
|
|
221
317
|
return `@flow
|
|
222
318
|
Feature: ${options.name} Flow
|
|
223
319
|
|
|
@@ -240,4 +336,44 @@ Feature: ${options.name} Flow
|
|
|
240
336
|
Then User see "expected result" text
|
|
241
337
|
`;
|
|
242
338
|
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Build the Background block for a mobile flow — same structure as screen-manager.
|
|
342
|
+
* The `--reach` steps represent how to reach the FIRST screen of the flow from app launch.
|
|
343
|
+
*/
|
|
344
|
+
private buildMobileBackground(reach?: string): string {
|
|
345
|
+
const normalizeStep = (raw: string): string =>
|
|
346
|
+
raw
|
|
347
|
+
.trim()
|
|
348
|
+
.replace(/^(given|when|and|then|but)\s+/i, '')
|
|
349
|
+
.replace(/^user\s+/i, '')
|
|
350
|
+
.trim();
|
|
351
|
+
|
|
352
|
+
const steps = (reach || '')
|
|
353
|
+
.split('>')
|
|
354
|
+
.map(normalizeStep)
|
|
355
|
+
.filter(Boolean);
|
|
356
|
+
|
|
357
|
+
if (steps.length === 0) {
|
|
358
|
+
return [
|
|
359
|
+
' Background:',
|
|
360
|
+
' # Navigation recipe — how to reach the first screen of this flow from app launch.',
|
|
361
|
+
' # Prefill with --reach "tap [Tab] > tap [Row]" at add-flow time.',
|
|
362
|
+
' Given User is on [Home] screen',
|
|
363
|
+
' # When User tap [<tab or button that leads to the first screen>]',
|
|
364
|
+
'',
|
|
365
|
+
].join('\n');
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const navLines = steps.map(
|
|
369
|
+
(body, i) => ` ${i === 0 ? 'When' : 'And'} User ${body}`,
|
|
370
|
+
);
|
|
371
|
+
return [
|
|
372
|
+
' Background:',
|
|
373
|
+
' # Navigation recipe — replayed by capture-mobile to land on the first screen.',
|
|
374
|
+
' Given User is on [Home] screen',
|
|
375
|
+
...navLines,
|
|
376
|
+
'',
|
|
377
|
+
].join('\n');
|
|
378
|
+
}
|
|
243
379
|
}
|