@sun-asterisk/sungen 3.2.2-beta.9 ā 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/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.map +1 -1
- package/dist/cli/commands/journey.js +24 -2
- package/dist/cli/commands/journey.js.map +1 -1
- 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/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 +37 -1
- package/dist/harness/journey.d.ts.map +1 -1
- package/dist/harness/journey.js +146 -19
- package/dist/harness/journey.js.map +1 -1
- 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 -5
- 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/dist/orchestrator/templates/{ai-instructions/claude-cmd-run-test.md ā ai-src/commands/run-test.md} +116 -8
- 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} +31 -10
- 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/{src/orchestrator/templates/ai-instructions/claude-skill-selector-fix-mobile.md ā dist/orchestrator/templates/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/generate.ts +2 -1
- package/src/cli/commands/init.ts +50 -3
- package/src/cli/commands/journey.ts +20 -3
- package/src/cli/commands/update.ts +14 -4
- 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 +167 -19
- 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 -5
- 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/src/orchestrator/templates/{ai-instructions/claude-cmd-run-test.md ā ai-src/commands/run-test.md} +116 -8
- 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} +31 -10
- 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/{dist/orchestrator/templates/ai-instructions/claude-skill-selector-fix-mobile.md ā src/orchestrator/templates/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 -94
- 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 -158
- 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 -176
- 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 -94
- 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 -158
- 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 -176
- 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
package/src/harness/journey.ts
CHANGED
|
@@ -27,6 +27,10 @@ export interface Obligation {
|
|
|
27
27
|
waivedReason?: string; // S2 ā set when the QA explicitly waived this obligation
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
/** S5 ā a parsed anchor so an IDE can jump straight to what needs review. */
|
|
31
|
+
export interface Anchor { vpId?: string; file?: string; line?: number; }
|
|
32
|
+
export interface ReviewItem { text: string; anchor: Anchor; }
|
|
33
|
+
|
|
30
34
|
export interface JourneyReport {
|
|
31
35
|
unit: string;
|
|
32
36
|
generatedFrom: string[]; // which artifacts were available
|
|
@@ -35,7 +39,7 @@ export interface JourneyReport {
|
|
|
35
39
|
gateStatus: string | null;
|
|
36
40
|
score: number | null;
|
|
37
41
|
obligations: Obligation[];
|
|
38
|
-
needsYou:
|
|
42
|
+
needsYou: ReviewItem[]; // S5 ā the review queue: human-judgment findings, each with an anchor
|
|
39
43
|
nextSuggested: string;
|
|
40
44
|
}
|
|
41
45
|
|
|
@@ -58,6 +62,13 @@ function isHumanFinding(f: string): boolean {
|
|
|
58
62
|
return /@manual|MANUAL-|DEPTH-DEFERRED|UNSOURCEABLE|CAPABILITY-SUGGESTION|judgment|oracle|review/i.test(f);
|
|
59
63
|
}
|
|
60
64
|
|
|
65
|
+
/** S5 ā pull an IDE-jumpable anchor out of a finding (VP id, scenario, or `file.ext:line`). */
|
|
66
|
+
function extractAnchor(text: string): Anchor {
|
|
67
|
+
const vp = text.match(/\bVP-[A-Z0-9-]+\b/);
|
|
68
|
+
const fl = text.match(/([\w./-]+\.(?:md|feature|ts|yaml)):(\d+)/);
|
|
69
|
+
return { vpId: vp ? vp[0] : undefined, file: fl ? fl[1] : undefined, line: fl ? Number(fl[2]) : undefined };
|
|
70
|
+
}
|
|
71
|
+
|
|
61
72
|
const SAT = 0.8; // axis at/above this = satisfied (below = needs-work)
|
|
62
73
|
|
|
63
74
|
function computeFresh(projectRoot: string, unit: string): JourneyReport {
|
|
@@ -73,7 +84,7 @@ function computeFresh(projectRoot: string, unit: string): JourneyReport {
|
|
|
73
84
|
const ran = (p: string) => phases.some((s) => s === p || s.startsWith(p));
|
|
74
85
|
|
|
75
86
|
const obligations: Obligation[] = [];
|
|
76
|
-
const needsYou:
|
|
87
|
+
const needsYou: ReviewItem[] = [];
|
|
77
88
|
|
|
78
89
|
if (!audit) {
|
|
79
90
|
// Nothing measured yet ā the journey hasn't really begun.
|
|
@@ -105,19 +116,31 @@ function computeFresh(projectRoot: string, unit: string): JourneyReport {
|
|
|
105
116
|
detail: autoPending ? `${audit.automatableManual.automatable} @manual scenario(s) a driver could automate` : 'no capability-pending automatable cases',
|
|
106
117
|
});
|
|
107
118
|
|
|
108
|
-
//
|
|
109
|
-
|
|
119
|
+
// Needs-you: the review queue. Prefer PRECISE per-scenario anchors from audit's structured
|
|
120
|
+
// depth data ā each shallow business-critical scenario carries its own VP id ā over regex-parsing
|
|
121
|
+
// the aggregate "DEPTH:" finding string (which names no scenario, so points nowhere). Then
|
|
122
|
+
// supplement with the remaining human-judgment findings.
|
|
123
|
+
const shallowBC: { name: string; category?: string }[] = (audit.depth && audit.depth.shallowBusinessCritical) || [];
|
|
124
|
+
for (const s of shallowBC) {
|
|
125
|
+
needsYou.push({
|
|
126
|
+
text: `DEEPEN ā "${s.name}": assert data, not just visibility (\`⦠with {{value}}\` / \`see all ⦠contain {{v}}\`), or defer cross-screen with @manual + reason.`,
|
|
127
|
+
anchor: extractAnchor(s.name),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
const haveStructuredDepth = shallowBC.length > 0;
|
|
131
|
+
for (const f of (audit.findings || [])) {
|
|
132
|
+
if (!isHumanFinding(f)) continue;
|
|
133
|
+
if (haveStructuredDepth && /^\s*DEPTH\b/i.test(f)) continue; // superseded by the per-scenario items above
|
|
134
|
+
needsYou.push({ text: f, anchor: extractAnchor(f) });
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Human sign-off: always pending until S5 explicit signoff; carries the now-final review-queue count.
|
|
138
|
+
const manualCount = (audit.manualOracle && (audit.manualOracle.manualTotal ?? audit.manualOracle.total)) || 0;
|
|
110
139
|
obligations.push({
|
|
111
140
|
id: 'OB-signoff', title: 'Human sign-off', status: 'pending',
|
|
112
|
-
detail: `${needsYou.length} item(s) queued for your review
|
|
141
|
+
detail: `${needsYou.length} item(s) queued for your review Ā· ${manualCount} @manual scenario(s)`,
|
|
113
142
|
});
|
|
114
143
|
|
|
115
|
-
// Needs-you: human-judgment findings (the review-queue seed), with their anchors (titles) intact.
|
|
116
|
-
for (const f of (audit.findings || [])) if (isHumanFinding(f)) needsYou.push(f);
|
|
117
|
-
// Re-stamp the signoff detail now that needsYou is filled.
|
|
118
|
-
const signoff = obligations.find((o) => o.id === 'OB-signoff');
|
|
119
|
-
if (signoff) signoff.detail = `${needsYou.length} item(s) queued for your review Ā· ${manualCount} @manual scenario(s)`;
|
|
120
|
-
|
|
121
144
|
// Next suggested = first non-satisfied obligation; if all satisfied but run-test not done ā run.
|
|
122
145
|
const firstGap = obligations.find((o) => o.status !== 'satisfied' && o.id !== 'OB-signoff');
|
|
123
146
|
let nextSuggested: string;
|
|
@@ -135,7 +158,8 @@ function computeFresh(projectRoot: string, unit: string): JourneyReport {
|
|
|
135
158
|
// ---------------- S2: writable lifecycle ā persisted waivers + reconcile ----------------
|
|
136
159
|
|
|
137
160
|
interface Waiver { reason: string; at: string; auditHashAtWaive: string; }
|
|
138
|
-
interface
|
|
161
|
+
interface Signoff { by?: string; at: string; auditHashAtSignoff: string; } // S5
|
|
162
|
+
interface JourneyState { unit: string; auditHash: string; waivers: Record<string, Waiver>; signoff?: Signoff; }
|
|
139
163
|
|
|
140
164
|
function statePath(projectRoot: string, slug: string): string {
|
|
141
165
|
return path.join(projectRoot, '.sungen', 'journey', `${slug}.state.json`);
|
|
@@ -181,11 +205,22 @@ export function runJourney(projectRoot: string, unit: string): JourneyReport {
|
|
|
181
205
|
ob.waivedReason = w.reason;
|
|
182
206
|
ob.detail = `waived ā ${w.reason}`;
|
|
183
207
|
} else {
|
|
184
|
-
report.needsYou.unshift(`ā ļø Waiver on "${ob.title}" is STALE (evidence changed since ${w.at}) ā re-decide. Was: ${w.reason}
|
|
208
|
+
report.needsYou.unshift({ text: `ā ļø Waiver on "${ob.title}" is STALE (evidence changed since ${w.at}) ā re-decide. Was: ${w.reason}`, anchor: { vpId: ob.id } });
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// S5 ā sign-off reconcile: a recorded sign-off satisfies OB-signoff while its evidence holds;
|
|
212
|
+
// if the audit changed since, the sign-off is STALE ā re-surface for re-review (anti-amnesia).
|
|
213
|
+
const signoffOb = report.obligations.find((o) => o.id === 'OB-signoff');
|
|
214
|
+
if (signoffOb && state.signoff) {
|
|
215
|
+
if (state.signoff.auditHashAtSignoff === curHash) {
|
|
216
|
+
signoffOb.status = 'satisfied';
|
|
217
|
+
signoffOb.detail = `signed off${state.signoff.by ? ' by ' + state.signoff.by : ''} at ${state.signoff.at}`;
|
|
218
|
+
} else {
|
|
219
|
+
report.needsYou.unshift({ text: `ā ļø Sign-off is STALE (suite changed since ${state.signoff.at}) ā re-review and sign off again.`, anchor: { vpId: 'OB-signoff' } });
|
|
185
220
|
}
|
|
186
221
|
}
|
|
187
222
|
report.nextSuggested = computeNext(report, unit);
|
|
188
|
-
saveState(sp, { unit, auditHash: curHash, waivers: state.waivers });
|
|
223
|
+
saveState(sp, { unit, auditHash: curHash, waivers: state.waivers, signoff: state.signoff });
|
|
189
224
|
return report;
|
|
190
225
|
}
|
|
191
226
|
|
|
@@ -210,6 +245,25 @@ export function waive(projectRoot: string, unit: string, obId: string, reason: s
|
|
|
210
245
|
return runJourney(projectRoot, unit);
|
|
211
246
|
}
|
|
212
247
|
|
|
248
|
+
/**
|
|
249
|
+
* Sign off ā the single human gate (S5). Allowed ONLY when every other deliver-required
|
|
250
|
+
* obligation is satisfied or waived (you cannot sign off an unclean suite). Records who/when +
|
|
251
|
+
* the evidence cursor; reconcile invalidates it (stale ā re-review) if the suite later changes.
|
|
252
|
+
*/
|
|
253
|
+
export function signoff(projectRoot: string, unit: string, by?: string): JourneyReport {
|
|
254
|
+
const before = runJourney(projectRoot, unit);
|
|
255
|
+
const blockers = before.obligations.filter((o) => o.id !== 'OB-signoff' && o.status !== 'satisfied' && o.status !== 'waived');
|
|
256
|
+
if (blockers.length) {
|
|
257
|
+
throw new Error(`Cannot sign off ā still open: ${blockers.map((b) => b.id).join(', ')}. Fix, or waive each with a reason, first.`);
|
|
258
|
+
}
|
|
259
|
+
const slug = reportSlug(unit);
|
|
260
|
+
const sp = statePath(projectRoot, slug);
|
|
261
|
+
const state = loadState(sp) || { unit, auditHash: '', waivers: {} };
|
|
262
|
+
state.signoff = { by, at: new Date().toISOString(), auditHashAtSignoff: auditHashOf(projectRoot, slug) };
|
|
263
|
+
saveState(sp, state);
|
|
264
|
+
return runJourney(projectRoot, unit);
|
|
265
|
+
}
|
|
266
|
+
|
|
213
267
|
const ICON: Record<ObStatus, string> = { satisfied: 'ā
', 'needs-work': 'ā ļø ', pending: 'ā³', waived: 'š«' };
|
|
214
268
|
|
|
215
269
|
export function renderJourneyBoard(r: JourneyReport): string {
|
|
@@ -222,9 +276,14 @@ export function renderJourneyBoard(r: JourneyReport): string {
|
|
|
222
276
|
L.push('## What must still be true');
|
|
223
277
|
for (const o of r.obligations) L.push(`- ${ICON[o.status]} **${o.title}** ā ${o.detail}`);
|
|
224
278
|
L.push('');
|
|
225
|
-
L.push(`## š
|
|
226
|
-
if (r.needsYou.length)
|
|
227
|
-
|
|
279
|
+
L.push(`## š Review queue ā needs your judgment (${r.needsYou.length})`);
|
|
280
|
+
if (r.needsYou.length) {
|
|
281
|
+
for (const it of r.needsYou.slice(0, 20)) {
|
|
282
|
+
const a = it.anchor;
|
|
283
|
+
const tag = [a.vpId, a.file && `${a.file}${a.line ? ':' + a.line : ''}`].filter(Boolean).join(' Ā· ');
|
|
284
|
+
L.push(`- ${it.text}${tag ? ` ć${tag}ć` : ''}`);
|
|
285
|
+
}
|
|
286
|
+
} else L.push('- (nothing queued)');
|
|
228
287
|
L.push('');
|
|
229
288
|
L.push(`## ā Next`);
|
|
230
289
|
L.push(`${r.nextSuggested}`);
|
|
@@ -255,8 +314,8 @@ const PHASE_REQUIRED: Record<GatePhase, string[]> = {
|
|
|
255
314
|
create: ['OB-spec', 'OB-coverage', 'OB-depth', 'OB-trace'],
|
|
256
315
|
// post-run: the design gates + automation coverage.
|
|
257
316
|
run: ['OB-spec', 'OB-coverage', 'OB-depth', 'OB-trace', 'OB-automation'],
|
|
258
|
-
// pre-delivery: everything automated
|
|
259
|
-
deliver: ['OB-spec', 'OB-coverage', 'OB-depth', 'OB-trace', 'OB-automation'],
|
|
317
|
+
// pre-delivery: everything automated PLUS the single human sign-off (S5).
|
|
318
|
+
deliver: ['OB-spec', 'OB-coverage', 'OB-depth', 'OB-trace', 'OB-automation', 'OB-signoff'],
|
|
260
319
|
};
|
|
261
320
|
|
|
262
321
|
export function runGate(projectRoot: string, unit: string, phase: GatePhase): GateVerdict {
|
|
@@ -284,3 +343,92 @@ export function renderGate(v: GateVerdict): string {
|
|
|
284
343
|
L.push('');
|
|
285
344
|
return L.join('\n');
|
|
286
345
|
}
|
|
346
|
+
|
|
347
|
+
// ---------------- #409: project-level roll-up across all units ----------------
|
|
348
|
+
//
|
|
349
|
+
// Multi-unit fan-out PARALLELISES generation but human review/sign-off must stay SERIAL ā you can't
|
|
350
|
+
// judge N boards at once. This roll-up is that serial surface: one row per unit (gate Ā· score Ā· phase
|
|
351
|
+
// Ā· what it still needs), and a single "review this next" pointer. The per-unit board is unchanged;
|
|
352
|
+
// this only aggregates the same read-only `runJourney` synthesis.
|
|
353
|
+
|
|
354
|
+
export type UnitKind = 'screen' | 'flow' | 'api';
|
|
355
|
+
export interface UnitSummary {
|
|
356
|
+
unit: string;
|
|
357
|
+
kind: UnitKind;
|
|
358
|
+
score: number | null;
|
|
359
|
+
gateStatus: string | null;
|
|
360
|
+
youAreHere: string;
|
|
361
|
+
obligationsOpen: number; // non-satisfied, non-waived (excludes OB-signoff)
|
|
362
|
+
reviewQueue: number;
|
|
363
|
+
signedOff: boolean;
|
|
364
|
+
started: boolean; // has an audit report yet
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/** Discover every unit under qa/screens, qa/flows, and qa/api top-level areas. */
|
|
368
|
+
export function listUnits(projectRoot: string): { unit: string; kind: UnitKind }[] {
|
|
369
|
+
const out: { unit: string; kind: UnitKind }[] = [];
|
|
370
|
+
const scan = (sub: string, kind: UnitKind) => {
|
|
371
|
+
const d = path.join(projectRoot, 'qa', sub);
|
|
372
|
+
if (!fs.existsSync(d)) return;
|
|
373
|
+
for (const e of fs.readdirSync(d, { withFileTypes: true })) {
|
|
374
|
+
// 'flows' under qa/api is a container for api-flows (a nested tier) ā not a unit itself.
|
|
375
|
+
if (e.isDirectory() && !(sub === 'api' && e.name === 'flows')) out.push({ unit: e.name, kind });
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
scan('screens', 'screen');
|
|
379
|
+
scan('flows', 'flow');
|
|
380
|
+
scan('api', 'api');
|
|
381
|
+
return out;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/** Roll up every unit's journey into one table of summaries (serial review surface). */
|
|
385
|
+
export function rollupJourney(projectRoot: string): UnitSummary[] {
|
|
386
|
+
return listUnits(projectRoot).map(({ unit, kind }) => {
|
|
387
|
+
const r = runJourney(projectRoot, unit);
|
|
388
|
+
const signedOff = r.obligations.find((o) => o.id === 'OB-signoff')?.status === 'satisfied';
|
|
389
|
+
const obligationsOpen = r.obligations.filter(
|
|
390
|
+
(o) => o.id !== 'OB-signoff' && o.status !== 'satisfied' && o.status !== 'waived',
|
|
391
|
+
).length;
|
|
392
|
+
return {
|
|
393
|
+
unit, kind, score: r.score, gateStatus: r.gateStatus, youAreHere: r.youAreHere,
|
|
394
|
+
obligationsOpen, reviewQueue: r.needsYou.length, signedOff,
|
|
395
|
+
started: r.generatedFrom.includes('audit'),
|
|
396
|
+
};
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function unitStatusLabel(r: UnitSummary): string {
|
|
401
|
+
if (!r.started) return 'ā»ļø not started';
|
|
402
|
+
if (r.signedOff) return 'ā
signed off';
|
|
403
|
+
if (r.obligationsOpen > 0) return `ā³ ${r.obligationsOpen} obligation(s) open`;
|
|
404
|
+
if (r.reviewQueue > 0) return `š review ${r.reviewQueue} item(s)`;
|
|
405
|
+
return 'š” ready to sign off';
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
export function renderRollupBoard(rows: UnitSummary[]): string {
|
|
409
|
+
const L: string[] = [];
|
|
410
|
+
L.push('# Journey roll-up ā all units');
|
|
411
|
+
L.push('');
|
|
412
|
+
if (!rows.length) {
|
|
413
|
+
L.push('No units found under `qa/screens`, `qa/flows`, or `qa/api`.');
|
|
414
|
+
return L.join('\n');
|
|
415
|
+
}
|
|
416
|
+
L.push('| Unit | Kind | Score | Gate | Phase | Needs |');
|
|
417
|
+
L.push('|---|---|---|---|---|---|');
|
|
418
|
+
for (const r of rows) {
|
|
419
|
+
L.push(`| ${r.unit} | ${r.kind} | ${r.score ?? 'ā'} | ${r.gateStatus ?? 'ā'} | ${r.youAreHere} | ${unitStatusLabel(r)} |`);
|
|
420
|
+
}
|
|
421
|
+
L.push('');
|
|
422
|
+
const blocked = rows.filter((r) => r.started && (r.obligationsOpen > 0));
|
|
423
|
+
const toReview = rows.filter((r) => r.started && r.obligationsOpen === 0 && !r.signedOff && r.reviewQueue >= 0);
|
|
424
|
+
const notStarted = rows.filter((r) => !r.started);
|
|
425
|
+
L.push(`**${rows.filter((r) => r.signedOff).length}/${rows.length} signed off** Ā· ${blocked.length} with open obligations Ā· ${notStarted.length} not started.`);
|
|
426
|
+
L.push('');
|
|
427
|
+
L.push('## ā Next (review is serial ā one unit at a time)');
|
|
428
|
+
const next = blocked[0] || toReview[0] || notStarted[0];
|
|
429
|
+
if (!next) L.push('All units signed off ā `sungen delivery` to export.');
|
|
430
|
+
else if (!next.started) L.push(`Generate **${next.unit}** ā \`/sungen:create-test ${next.unit}\`.`);
|
|
431
|
+
else L.push(`Review **${next.unit}** (${unitStatusLabel(next)}) ā \`sungen journey --screen ${next.unit}\`, then sign off.`);
|
|
432
|
+
L.push('');
|
|
433
|
+
return L.join('\n');
|
|
434
|
+
}
|
|
@@ -42,6 +42,26 @@ export function isolationRisk(featureText: string, stateful: boolean): boolean {
|
|
|
42
42
|
return !/@cleanup:cart\b|@isolate\b|empty cart|fresh (?:browser )?context|new context/i.test(featureText);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* #414 ā the complement of isolationRisk. Per-scenario isolation is the DEFAULT now, so untagged
|
|
47
|
+
* suites can't cascade. `@serial` opts INTO a shared-page `test.describe.serial` suite, whose
|
|
48
|
+
* Playwright semantics SKIP every test after the first failure. That is correct ONLY for a genuinely
|
|
49
|
+
* stateful ordered sequence; for INDEPENDENT scenarios ā each re-establishing its own start state via
|
|
50
|
+
* a navigating Background ā `@serial` buys no correctness, only a cascade that *masks* failures (one
|
|
51
|
+
* early red turns the rest into greens-by-omission). Returns the scenario count when `@serial` should
|
|
52
|
+
* be dropped (the default isolation is safer), else 0.
|
|
53
|
+
*
|
|
54
|
+
* Conservative on purpose ā only fires on `@serial` suites whose every scenario provably restarts (a
|
|
55
|
+
* `Background` that navigates `on [..] page`), so a real stateful sequence keeps its `@serial`.
|
|
56
|
+
*/
|
|
57
|
+
export function serialCascadeRisk(featureText: string, scenarioCount: number): number {
|
|
58
|
+
if (!/@serial\b/i.test(featureText)) return 0; // isolated by default ā no cascade
|
|
59
|
+
if (scenarioCount < 8) return 0; // small blast radius ā not worth the churn
|
|
60
|
+
const navBackground = /Background:[\s\S]*?\bon \[[^\]]+\] page\b/i.test(featureText);
|
|
61
|
+
if (!navBackground) return 0; // no per-scenario reset ā genuinely stateful; @serial is right
|
|
62
|
+
return scenarioCount;
|
|
63
|
+
}
|
|
64
|
+
|
|
45
65
|
export function downstreamScope(specText: string, scenarios: ScenarioInfo[]): DownstreamResult {
|
|
46
66
|
const routes = downstreamRoutes(specText);
|
|
47
67
|
const underCovered: { route: string; slug: string }[] = [];
|
package/src/harness/sensors.ts
CHANGED
|
@@ -59,9 +59,17 @@ export function loadCatalog(): Catalog {
|
|
|
59
59
|
return parseYaml(fs.readFileSync(p, 'utf-8')) as Catalog;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
// Word-aware keyword match: `\b<kw>(s|es|ed|ing)?\b`, so a keyword matches whole words (plus
|
|
63
|
+
// simple plural/verb suffixes) but NOT as a substring of a larger word ā e.g. `form` must not
|
|
64
|
+
// match inside `Format` or `@platform`, while `product` still matches `products`. Multi-word
|
|
65
|
+
// keywords ("add to cart", "is hidden") match the phrase with a boundary at each end.
|
|
66
|
+
const wordRe = (kw: string) => {
|
|
67
|
+
const esc = kw.toLowerCase().replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
68
|
+
return new RegExp(`\\b${esc}(?:s|es|ed|ing)?\\b`);
|
|
69
|
+
};
|
|
62
70
|
const has = (haystacks: string[], kw: string) => {
|
|
63
|
-
const
|
|
64
|
-
return haystacks.some((h) =>
|
|
71
|
+
const re = wordRe(kw);
|
|
72
|
+
return haystacks.some((h) => re.test(h));
|
|
65
73
|
};
|
|
66
74
|
|
|
67
75
|
// ---------- Sensor 1: Viewpoint Gate (catalog-driven) ----------
|
|
@@ -75,16 +83,21 @@ export interface GateResult {
|
|
|
75
83
|
universalGaps: string[];
|
|
76
84
|
}
|
|
77
85
|
|
|
78
|
-
export function viewpointGate(scenarios: ScenarioInfo[], viewpoints: ViewpointEntry[], catalog: Catalog): GateResult {
|
|
86
|
+
export function viewpointGate(scenarios: ScenarioInfo[], viewpoints: ViewpointEntry[], catalog: Catalog, isMobile = false): GateResult {
|
|
79
87
|
const haystacks = [
|
|
80
88
|
...scenarios.map((s) => s.haystack),
|
|
81
89
|
...viewpoints.map((v) => `${v.id} ${v.reason}`.toLowerCase()),
|
|
82
90
|
];
|
|
83
91
|
|
|
84
|
-
// Detect page-type by detect_keywords hit count
|
|
92
|
+
// Detect page-type by detect_keywords hit count. `mobile-*` page-types are candidates ONLY for
|
|
93
|
+
// mobile targets; web targets never consider them. Mobile targets still consider the web types
|
|
94
|
+
// too, so a mobile commerce/form screen is selected as ecommerce-list/form by keyword fit ā
|
|
95
|
+
// `mobile-home` does not crowd out a better-fitting type. With no type matching ā pageType stays
|
|
96
|
+
// null ā no themes required ā the gate passes leniently rather than false-FAILing.
|
|
85
97
|
let pageType: string | null = null;
|
|
86
98
|
let best = 0;
|
|
87
99
|
for (const [pt, def] of Object.entries(catalog.page_types)) {
|
|
100
|
+
if (pt.startsWith('mobile-') && !isMobile) continue;
|
|
88
101
|
const hits = def.detect_keywords.filter((k) => has(haystacks, k)).length;
|
|
89
102
|
if (hits > best) { best = hits; pageType = pt; }
|
|
90
103
|
}
|
|
@@ -97,10 +110,14 @@ export function viewpointGate(scenarios: ScenarioInfo[], viewpoints: ViewpointEn
|
|
|
97
110
|
// Scenarios that cover this theme by keyword (include @manual ā a manual
|
|
98
111
|
// scenario with a real assertion still covers the viewpoint for design).
|
|
99
112
|
const coverers = scenarios.filter((s) => t.keywords.some((k) => s.haystack.includes(k.toLowerCase())));
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
113
|
+
if (coverers.length === 0) { gaps.push({ theme: t.theme, keywords: t.keywords, status: 'missing' }); continue; }
|
|
114
|
+
// A theme WITHOUT `depth:` is visibility/navigation ā landing/seeing/leaving IS the
|
|
115
|
+
// assertion, so mere presence covers it. Only DATA-correctness themes (depth.requires:
|
|
116
|
+
// data-assertion) need a data assertion to count as deeply covered.
|
|
117
|
+
const needsDepth = t.depth?.requires === 'data-assertion';
|
|
118
|
+
if (!needsDepth) { covered++; continue; }
|
|
119
|
+
if (coverers.some((s) => s.hasDataAssertion)) covered++;
|
|
120
|
+
else gaps.push({ theme: t.theme, keywords: t.keywords, status: 'shallow' });
|
|
104
121
|
}
|
|
105
122
|
}
|
|
106
123
|
|
|
@@ -6,106 +6,15 @@
|
|
|
6
6
|
|
|
7
7
|
import * as fs from 'fs';
|
|
8
8
|
import * as path from 'path';
|
|
9
|
+
import { buildOutputs } from './ai-skills/build';
|
|
10
|
+
import { applyOutputs } from './ai-skills/writer';
|
|
11
|
+
import { AdapterKey } from './ai-skills/adapters';
|
|
9
12
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
['claude-config.md', 'CLAUDE.md'],
|
|
15
|
-
['copilot-config.md', '.github/copilot-instructions.md'],
|
|
16
|
-
|
|
17
|
-
// Commands ā Claude Code
|
|
18
|
-
['claude-cmd-add-screen.md', '.claude/commands/sungen/add-screen.md'],
|
|
19
|
-
['claude-cmd-add-flow.md', '.claude/commands/sungen/add-flow.md'],
|
|
20
|
-
['claude-cmd-create-test.md', '.claude/commands/sungen/create-test.md'],
|
|
21
|
-
['claude-cmd-design.md', '.claude/commands/sungen/design.md'],
|
|
22
|
-
['claude-cmd-run-test.md', '.claude/commands/sungen/run-test.md'],
|
|
23
|
-
['claude-cmd-review.md', '.claude/commands/sungen/review.md'],
|
|
24
|
-
['claude-cmd-delivery.md', '.claude/commands/sungen/delivery.md'],
|
|
25
|
-
['claude-cmd-dashboard.md', '.claude/commands/sungen/dashboard.md'],
|
|
26
|
-
['claude-cmd-locale.md', '.claude/commands/sungen/locale.md'],
|
|
27
|
-
['claude-cmd-feedback.md', '.claude/commands/sungen/feedback.md'],
|
|
28
|
-
|
|
29
|
-
// Commands ā GitHub Copilot
|
|
30
|
-
['copilot-cmd-add-screen.md', '.github/prompts/sungen-add-screen.prompt.md'],
|
|
31
|
-
['copilot-cmd-add-flow.md', '.github/prompts/sungen-add-flow.prompt.md'],
|
|
32
|
-
['copilot-cmd-create-test.md', '.github/prompts/sungen-create-test.prompt.md'],
|
|
33
|
-
['copilot-cmd-design.md', '.github/prompts/sungen-design.prompt.md'],
|
|
34
|
-
['copilot-cmd-run-test.md', '.github/prompts/sungen-run-test.prompt.md'],
|
|
35
|
-
['copilot-cmd-review.md', '.github/prompts/sungen-review.prompt.md'],
|
|
36
|
-
['copilot-cmd-delivery.md', '.github/prompts/sungen-delivery.prompt.md'],
|
|
37
|
-
['copilot-cmd-dashboard.md', '.github/prompts/sungen-dashboard.prompt.md'],
|
|
38
|
-
['copilot-cmd-locale.md', '.github/prompts/sungen-locale.prompt.md'],
|
|
39
|
-
['copilot-cmd-feedback.md', '.github/prompts/sungen-feedback.prompt.md'],
|
|
40
|
-
|
|
41
|
-
// Skills ā Claude Code
|
|
42
|
-
['claude-skill-gherkin-syntax.md', '.claude/skills/sungen-gherkin-syntax/SKILL.md'],
|
|
43
|
-
['claude-skill-selector-keys.md', '.claude/skills/sungen-selector-keys/SKILL.md'],
|
|
44
|
-
['claude-skill-error-mapping.md', '.claude/skills/sungen-error-mapping/SKILL.md'],
|
|
45
|
-
['claude-skill-tc-generation.md', '.claude/skills/sungen-tc-generation/SKILL.md'],
|
|
46
|
-
['claude-skill-test-design-techniques.md', '.claude/skills/sungen-test-design-techniques/SKILL.md'],
|
|
47
|
-
['claude-skill-selector-fix.md', '.claude/skills/sungen-selector-fix/SKILL.md'],
|
|
48
|
-
['claude-skill-tc-review.md', '.claude/skills/sungen-tc-review/SKILL.md'],
|
|
49
|
-
['claude-skill-harness-audit.md', '.claude/skills/sungen-harness-audit/SKILL.md'],
|
|
50
|
-
['claude-skill-api-design.md', '.claude/skills/sungen-api-design/SKILL.md'],
|
|
51
|
-
['claude-skill-ingest-legacy.md', '.claude/skills/sungen-ingest-legacy/SKILL.md'],
|
|
52
|
-
['claude-skill-viewpoint.md', '.claude/skills/sungen-viewpoint/SKILL.md'],
|
|
53
|
-
['claude-skill-viewpoint-group-a-data-entry.md', '.claude/skills/sungen-viewpoint/group-a-data-entry.md'],
|
|
54
|
-
['claude-skill-viewpoint-group-b-data-ops.md', '.claude/skills/sungen-viewpoint/group-b-data-ops.md'],
|
|
55
|
-
['claude-skill-viewpoint-group-c-data-explore.md', '.claude/skills/sungen-viewpoint/group-c-data-explore.md'],
|
|
56
|
-
['claude-skill-viewpoint-group-d-display.md', '.claude/skills/sungen-viewpoint/group-d-display.md'],
|
|
57
|
-
['claude-skill-viewpoint-group-e-identity.md', '.claude/skills/sungen-viewpoint/group-e-identity.md'],
|
|
58
|
-
['claude-skill-delivery.md', '.claude/skills/sungen-delivery/SKILL.md'],
|
|
59
|
-
['claude-skill-dashboard.md', '.claude/skills/sungen-dashboard/SKILL.md'],
|
|
60
|
-
// sungen-capture ā router skill (1 SKILL.md + 4 mode files). Replaces the former
|
|
61
|
-
// capture-figma / capture-live / capture-local / figma-source standalone skills.
|
|
62
|
-
['claude-skill-capture.md', '.claude/skills/sungen-capture/SKILL.md'],
|
|
63
|
-
['claude-skill-capture-mode-figma-mcp.md', '.claude/skills/sungen-capture/mode-figma-mcp.md'],
|
|
64
|
-
['claude-skill-capture-mode-figma-pat.md', '.claude/skills/sungen-capture/mode-figma-pat.md'],
|
|
65
|
-
['claude-skill-capture-mode-live.md', '.claude/skills/sungen-capture/mode-live.md'],
|
|
66
|
-
['claude-skill-capture-mode-local.md', '.claude/skills/sungen-capture/mode-local.md'],
|
|
67
|
-
['claude-skill-locale.md', '.claude/skills/sungen-locale/SKILL.md'],
|
|
68
|
-
// Mobile (Appium) skills ā relevant for platform: mobile (MOB-5).
|
|
69
|
-
['claude-skill-mobile-gestures.md', '.claude/skills/sungen-mobile-gestures/SKILL.md'],
|
|
70
|
-
['claude-skill-capture-mobile.md', '.claude/skills/sungen-capture-mobile/SKILL.md'],
|
|
71
|
-
['claude-skill-selector-fix-mobile.md', '.claude/skills/sungen-selector-fix-mobile/SKILL.md'],
|
|
72
|
-
|
|
73
|
-
// Agents ā Claude Code sub-agents (isolated context). Copilot runs these inline.
|
|
74
|
-
['claude-agent-reviewer.md', '.claude/agents/sungen-reviewer.md'],
|
|
75
|
-
['claude-agent-discovery.md', '.claude/agents/sungen-discovery.md'],
|
|
76
|
-
['claude-agent-challenge.md', '.claude/agents/sungen-challenge.md'],
|
|
77
|
-
['claude-agent-generator.md', '.claude/agents/sungen-generator.md'],
|
|
13
|
+
function sungenVersion(): string {
|
|
14
|
+
try { return require(path.join(__dirname, '..', '..', 'package.json')).version || '0.0.0'; }
|
|
15
|
+
catch { return '0.0.0'; }
|
|
16
|
+
}
|
|
78
17
|
|
|
79
|
-
// Skills ā GitHub Copilot
|
|
80
|
-
['github-skill-sungen-gherkin-syntax.md', '.github/skills/sungen-gherkin-syntax/SKILL.md'],
|
|
81
|
-
['github-skill-sungen-selector-keys.md', '.github/skills/sungen-selector-keys/SKILL.md'],
|
|
82
|
-
['github-skill-sungen-error-mapping.md', '.github/skills/sungen-error-mapping/SKILL.md'],
|
|
83
|
-
['github-skill-sungen-tc-generation.md', '.github/skills/sungen-tc-generation/SKILL.md'],
|
|
84
|
-
['github-skill-sungen-test-design-techniques.md', '.github/skills/sungen-test-design-techniques/SKILL.md'],
|
|
85
|
-
['github-skill-sungen-selector-fix.md', '.github/skills/sungen-selector-fix/SKILL.md'],
|
|
86
|
-
['github-skill-sungen-tc-review.md', '.github/skills/sungen-tc-review/SKILL.md'],
|
|
87
|
-
['github-skill-sungen-harness-audit.md', '.github/skills/sungen-harness-audit/SKILL.md'],
|
|
88
|
-
['github-skill-sungen-api-design.md', '.github/skills/sungen-api-design/SKILL.md'],
|
|
89
|
-
['github-skill-sungen-ingest-legacy.md', '.github/skills/sungen-ingest-legacy/SKILL.md'],
|
|
90
|
-
['github-skill-sungen-viewpoint.md', '.github/skills/sungen-viewpoint/SKILL.md'],
|
|
91
|
-
['github-skill-sungen-viewpoint-group-a-data-entry.md', '.github/skills/sungen-viewpoint/group-a-data-entry.md'],
|
|
92
|
-
['github-skill-sungen-viewpoint-group-b-data-ops.md', '.github/skills/sungen-viewpoint/group-b-data-ops.md'],
|
|
93
|
-
['github-skill-sungen-viewpoint-group-c-data-explore.md', '.github/skills/sungen-viewpoint/group-c-data-explore.md'],
|
|
94
|
-
['github-skill-sungen-viewpoint-group-d-display.md', '.github/skills/sungen-viewpoint/group-d-display.md'],
|
|
95
|
-
['github-skill-sungen-viewpoint-group-e-identity.md', '.github/skills/sungen-viewpoint/group-e-identity.md'],
|
|
96
|
-
['github-skill-sungen-delivery.md', '.github/skills/sungen-delivery/SKILL.md'],
|
|
97
|
-
['github-skill-sungen-dashboard.md', '.github/skills/sungen-dashboard/SKILL.md'],
|
|
98
|
-
['github-skill-sungen-capture.md', '.github/skills/sungen-capture/SKILL.md'],
|
|
99
|
-
['github-skill-sungen-capture-mode-figma-mcp.md', '.github/skills/sungen-capture/mode-figma-mcp.md'],
|
|
100
|
-
['github-skill-sungen-capture-mode-figma-pat.md', '.github/skills/sungen-capture/mode-figma-pat.md'],
|
|
101
|
-
['github-skill-sungen-capture-mode-live.md', '.github/skills/sungen-capture/mode-live.md'],
|
|
102
|
-
['github-skill-sungen-capture-mode-local.md', '.github/skills/sungen-capture/mode-local.md'],
|
|
103
|
-
['github-skill-sungen-locale.md', '.github/skills/sungen-locale/SKILL.md'],
|
|
104
|
-
// Mobile (Appium) skills ā relevant for platform: mobile (MOB-5).
|
|
105
|
-
['github-skill-sungen-mobile-gestures.md', '.github/skills/sungen-mobile-gestures/SKILL.md'],
|
|
106
|
-
['github-skill-sungen-capture-mobile.md', '.github/skills/sungen-capture-mobile/SKILL.md'],
|
|
107
|
-
['github-skill-sungen-selector-fix-mobile.md', '.github/skills/sungen-selector-fix-mobile/SKILL.md'],
|
|
108
|
-
];
|
|
109
18
|
|
|
110
19
|
// Skill/asset directories retired in a previous refactor. `sungen update` removes
|
|
111
20
|
// these so already-initialized projects don't keep loading stale skill descriptions.
|
|
@@ -124,119 +33,48 @@ export const STALE_AI_RULES_PATHS: string[] = [
|
|
|
124
33
|
|
|
125
34
|
export class AIRulesUpdater {
|
|
126
35
|
private cwd: string;
|
|
127
|
-
private aiTemplateDir: string;
|
|
128
36
|
|
|
129
37
|
constructor(cwd: string) {
|
|
130
38
|
this.cwd = cwd;
|
|
131
|
-
this.aiTemplateDir = path.join(__dirname, 'templates', 'ai-instructions');
|
|
132
39
|
}
|
|
133
40
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
for (
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if (!fs.existsSync(templatePath)) {
|
|
147
|
-
missing.push(templateFile);
|
|
148
|
-
continue;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const newContent = fs.readFileSync(templatePath, 'utf-8');
|
|
152
|
-
|
|
153
|
-
if (fs.existsSync(outputPath)) {
|
|
154
|
-
const currentContent = fs.readFileSync(outputPath, 'utf-8');
|
|
155
|
-
if (currentContent === newContent) {
|
|
156
|
-
unchanged.push(outputRelPath);
|
|
157
|
-
continue;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (!dryRun) {
|
|
161
|
-
fs.writeFileSync(outputPath, newContent, 'utf-8');
|
|
162
|
-
}
|
|
163
|
-
updated.push(outputRelPath);
|
|
164
|
-
} else {
|
|
165
|
-
if (!dryRun) {
|
|
166
|
-
const outputDir = path.dirname(outputPath);
|
|
167
|
-
if (!fs.existsSync(outputDir)) {
|
|
168
|
-
fs.mkdirSync(outputDir, { recursive: true });
|
|
169
|
-
}
|
|
170
|
-
fs.writeFileSync(outputPath, newContent, 'utf-8');
|
|
171
|
-
}
|
|
172
|
-
created.push(outputRelPath);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Remove retired skills/assets so stale descriptions stop loading.
|
|
41
|
+
/**
|
|
42
|
+
* Refresh AI rules/commands/skills from the single-source generator.
|
|
43
|
+
* @param dryRun show changes without writing
|
|
44
|
+
* @param opts.agents which assistants to install (default: claude ā decision T5)
|
|
45
|
+
* @param opts.force overwrite user config files (CLAUDE.md/AGENTS.md/copilot-instructions)
|
|
46
|
+
*/
|
|
47
|
+
async update(dryRun: boolean, opts: { agents?: AdapterKey[]; force?: boolean } = {}): Promise<void> {
|
|
48
|
+
const agents = opts.agents && opts.agents.length ? opts.agents : (['claude'] as AdapterKey[]);
|
|
49
|
+
console.log(`š Updating AI rules for: ${agents.join(', ')}${dryRun ? ' (dry-run)' : ''}\n`);
|
|
50
|
+
|
|
51
|
+
// One-time legacy cleanup for projects created before the manifest existed.
|
|
177
52
|
const removed: string[] = [];
|
|
178
53
|
for (const staleRelPath of STALE_AI_RULES_PATHS) {
|
|
179
54
|
const stalePath = path.join(this.cwd, staleRelPath);
|
|
180
55
|
if (fs.existsSync(stalePath)) {
|
|
181
|
-
if (!dryRun) {
|
|
182
|
-
fs.rmSync(stalePath, { recursive: true, force: true });
|
|
183
|
-
}
|
|
56
|
+
if (!dryRun) fs.rmSync(stalePath, { recursive: true, force: true });
|
|
184
57
|
removed.push(staleRelPath);
|
|
185
58
|
}
|
|
186
59
|
}
|
|
187
60
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
61
|
+
const outputs = buildOutputs(agents);
|
|
62
|
+
const r = applyOutputs(this.cwd, outputs, { version: sungenVersion(), dryRun, force: opts.force });
|
|
63
|
+
|
|
64
|
+
if (dryRun) console.log('š Dry run ā no files changed\n');
|
|
65
|
+
if (removed.length) console.log(`šļø Removed retired assets (${removed.length})`);
|
|
66
|
+
if (r.deletedOrphans.length) console.log(`šļø Removed orphans (${r.deletedOrphans.length}): ${r.deletedOrphans.join(', ')}`);
|
|
67
|
+
if (r.created.length) console.log(`⨠Created (${r.created.length})`);
|
|
68
|
+
if (r.overwritten.length) console.log(`āļø Updated (${r.overwritten.length})`);
|
|
69
|
+
if (r.skippedConfig.length) console.log(`āļø Config preserved (use --force to overwrite): ${r.skippedConfig.join(', ')}`);
|
|
70
|
+
if (r.handEditWarnings.length) {
|
|
71
|
+
console.log(`\nā ļø Overwrote files that look hand-edited (sungen owns these ā version-managed):`);
|
|
72
|
+
for (const f of r.handEditWarnings) console.log(` ${f}`);
|
|
191
73
|
}
|
|
192
74
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
console.log();
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
if (updated.length > 0) {
|
|
202
|
-
console.log(`āļø Updated (${updated.length}):`);
|
|
203
|
-
for (const f of updated) {
|
|
204
|
-
console.log(` ${f}`);
|
|
205
|
-
}
|
|
206
|
-
console.log();
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
if (created.length > 0) {
|
|
210
|
-
console.log(`⨠Created (${created.length}):`);
|
|
211
|
-
for (const f of created) {
|
|
212
|
-
console.log(` ${f}`);
|
|
213
|
-
}
|
|
214
|
-
console.log();
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
if (unchanged.length > 0) {
|
|
218
|
-
console.log(`ā
Already up to date (${unchanged.length}):`);
|
|
219
|
-
for (const f of unchanged) {
|
|
220
|
-
console.log(` ${f}`);
|
|
221
|
-
}
|
|
222
|
-
console.log();
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
if (missing.length > 0) {
|
|
226
|
-
console.log(`ā ļø Template not found (${missing.length}):`);
|
|
227
|
-
for (const f of missing) {
|
|
228
|
-
console.log(` ${f}`);
|
|
229
|
-
}
|
|
230
|
-
console.log();
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
const totalChanges = updated.length + created.length;
|
|
234
|
-
if (totalChanges === 0) {
|
|
235
|
-
console.log('All AI rules are up to date. No changes needed.');
|
|
236
|
-
} else if (dryRun) {
|
|
237
|
-
console.log(`${totalChanges} file(s) would be changed. Run without --dry-run to apply.`);
|
|
238
|
-
} else {
|
|
239
|
-
console.log(`${totalChanges} file(s) updated successfully.`);
|
|
240
|
-
}
|
|
75
|
+
const total = r.created.length + r.overwritten.length;
|
|
76
|
+
if (total === 0 && !removed.length && !r.deletedOrphans.length) console.log('All AI rules are up to date. No changes needed.');
|
|
77
|
+
else if (dryRun) console.log(`\n${total} file(s) would change. Run without --dry-run to apply.`);
|
|
78
|
+
else console.log(`\n${total} file(s) updated for ${agents.join(', ')}.`);
|
|
241
79
|
}
|
|
242
80
|
}
|