@agents-inc/cli 0.72.0 → 0.73.0
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/CHANGELOG.md +13 -0
- package/dist/{chunk-OODTDGEM.js → chunk-3K6FSET7.js} +6 -6
- package/dist/{chunk-LBTW5HSY.js → chunk-3REVX6S5.js} +11 -11
- package/dist/chunk-3REVX6S5.js.map +1 -0
- package/dist/{chunk-HMJGSAKV.js → chunk-3VNQPCOE.js} +2510 -2687
- package/dist/chunk-3VNQPCOE.js.map +1 -0
- package/dist/{chunk-V2XIWRHP.js → chunk-4KLUOFP6.js} +6 -7
- package/dist/chunk-4KLUOFP6.js.map +1 -0
- package/dist/{chunk-MGQVO357.js → chunk-6JRQPSKV.js} +2 -2
- package/dist/chunk-6JRQPSKV.js.map +1 -0
- package/dist/{chunk-ZYUASJUN.js → chunk-BH4LN7XV.js} +8 -6
- package/dist/chunk-BH4LN7XV.js.map +1 -0
- package/dist/{chunk-6YMW4HMX.js → chunk-DNPJ5GUK.js} +6 -6
- package/dist/chunk-DNPJ5GUK.js.map +1 -0
- package/dist/chunk-E74Q7GUE.js +5132 -0
- package/dist/chunk-E74Q7GUE.js.map +1 -0
- package/dist/{chunk-AHZ34QVK.js → chunk-EMWP363L.js} +8 -10
- package/dist/chunk-EMWP363L.js.map +1 -0
- package/dist/chunk-EMX7PA2I.js +39 -0
- package/dist/chunk-EMX7PA2I.js.map +1 -0
- package/dist/{chunk-SEAL43IR.js → chunk-G23HPF6K.js} +3 -3
- package/dist/chunk-GDUOOT3J.js +689 -0
- package/dist/chunk-GDUOOT3J.js.map +1 -0
- package/dist/{chunk-HJVWBSLM.js → chunk-GSFZDUV2.js} +4 -4
- package/dist/chunk-GSFZDUV2.js.map +1 -0
- package/dist/{chunk-LM5YQUBR.js → chunk-H4ETXZVL.js} +6 -6
- package/dist/{chunk-ZFRALAK5.js → chunk-JHMECCBN.js} +4 -5
- package/dist/chunk-JHMECCBN.js.map +1 -0
- package/dist/{chunk-UQTG4ZBA.js → chunk-K7WYMQQB.js} +18 -20
- package/dist/chunk-K7WYMQQB.js.map +1 -0
- package/dist/{chunk-RJOLQ7EK.js → chunk-KE2EAVFQ.js} +4 -4
- package/dist/{chunk-CKPJTMNC.js → chunk-KSMT5FVM.js} +4 -4
- package/dist/chunk-KSMT5FVM.js.map +1 -0
- package/dist/{chunk-52THXN5G.js → chunk-NUJHWYCR.js} +2 -2
- package/dist/{chunk-URAXGHF2.js → chunk-OLWGGD4G.js} +20 -15
- package/dist/chunk-OLWGGD4G.js.map +1 -0
- package/dist/{chunk-FKRYJOPC.js → chunk-PNZCVOCE.js} +5 -5
- package/dist/chunk-PNZCVOCE.js.map +1 -0
- package/dist/chunk-SRIH4U5Y.js +159 -0
- package/dist/chunk-SRIH4U5Y.js.map +1 -0
- package/dist/{chunk-J4TVAB5H.js → chunk-T7QY777F.js} +2 -2
- package/dist/{chunk-Q3YMO5YG.js → chunk-TNSVPZHP.js} +20 -2
- package/dist/chunk-TNSVPZHP.js.map +1 -0
- package/dist/{chunk-WWHDP5CP.js → chunk-V5HR77EY.js} +94 -13
- package/dist/chunk-V5HR77EY.js.map +1 -0
- package/dist/{chunk-ZEJIEC2A.js → chunk-WJL4KU5V.js} +66 -240
- package/dist/chunk-WJL4KU5V.js.map +1 -0
- package/dist/{chunk-G3LNIYZG.js → chunk-Y47CLMWE.js} +2 -2
- package/dist/{chunk-3SLO2QPW.js → chunk-Y4VUU5BT.js} +12 -14
- package/dist/chunk-Y4VUU5BT.js.map +1 -0
- package/dist/{chunk-F43WGOGN.js → chunk-ZBLSWJFM.js} +2 -2
- package/dist/chunk-ZBLSWJFM.js.map +1 -0
- package/dist/commands/build/marketplace.js +4 -3
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +8 -7
- package/dist/commands/build/plugins.js.map +1 -1
- package/dist/commands/build/stack.js +8 -7
- package/dist/commands/build/stack.js.map +1 -1
- package/dist/commands/compile.js +13 -9
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/config/index.js +8 -7
- package/dist/commands/config/index.js.map +1 -1
- package/dist/commands/config/path.js +7 -6
- package/dist/commands/config/path.js.map +1 -1
- package/dist/commands/config/show.js +8 -7
- package/dist/commands/diff.js +7 -6
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/doctor.js +12 -13
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +32 -34
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +14 -12
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/import/skill.js +7 -6
- package/dist/commands/import/skill.js.map +1 -1
- package/dist/commands/info.js +11 -10
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/init.js +27 -26
- package/dist/commands/list.js +7 -6
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/new/agent.js +8 -7
- package/dist/commands/new/agent.js.map +1 -1
- package/dist/commands/new/marketplace.js +11 -14
- package/dist/commands/new/marketplace.js.map +1 -1
- package/dist/commands/new/skill.js +8 -7
- package/dist/commands/outdated.js +7 -6
- package/dist/commands/outdated.js.map +1 -1
- package/dist/commands/search.js +8 -9
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/uninstall.js +7 -6
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +9 -9
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/validate.js +15 -17
- package/dist/commands/validate.js.map +1 -1
- package/dist/components/wizard/category-grid.js +2 -2
- package/dist/components/wizard/category-grid.test.js +16 -65
- package/dist/components/wizard/category-grid.test.js.map +1 -1
- package/dist/components/wizard/domain-selection.js +9 -8
- package/dist/components/wizard/source-grid.js +4 -4
- package/dist/components/wizard/source-grid.test.js +18 -16
- package/dist/components/wizard/source-grid.test.js.map +1 -1
- package/dist/components/wizard/stack-selection.js +8 -7
- package/dist/components/wizard/step-agents.js +9 -8
- package/dist/components/wizard/step-agents.test.js +14 -13
- package/dist/components/wizard/step-agents.test.js.map +1 -1
- package/dist/components/wizard/step-build.js +10 -9
- package/dist/components/wizard/step-build.test.js +16 -15
- package/dist/components/wizard/step-build.test.js.map +1 -1
- package/dist/components/wizard/step-confirm.js +5 -4
- package/dist/components/wizard/step-confirm.test.js +10 -9
- package/dist/components/wizard/step-confirm.test.js.map +1 -1
- package/dist/components/wizard/step-settings.js +8 -7
- package/dist/components/wizard/step-settings.test.js +11 -10
- package/dist/components/wizard/step-settings.test.js.map +1 -1
- package/dist/components/wizard/step-sources.js +13 -12
- package/dist/components/wizard/step-sources.test.js +18 -17
- package/dist/components/wizard/step-sources.test.js.map +1 -1
- package/dist/components/wizard/step-stack.js +11 -10
- package/dist/components/wizard/step-stack.test.js +15 -14
- package/dist/components/wizard/step-stack.test.js.map +1 -1
- package/dist/components/wizard/wizard-layout.js +8 -7
- package/dist/components/wizard/wizard.js +25 -24
- package/dist/hooks/init.js +27 -26
- package/dist/hooks/init.js.map +1 -1
- package/dist/{loader-KVKSTKWX.js → loader-XQ3WBTVP.js} +4 -3
- package/dist/{source-loader-65IAJPNV.js → source-loader-F4PGP6LH.js} +7 -6
- package/dist/source-manager-QCIO4XZK.js +20 -0
- package/dist/stores/wizard-store.js +7 -6
- package/dist/stores/wizard-store.test.js +29 -28
- package/dist/stores/wizard-store.test.js.map +1 -1
- package/package.json +1 -1
- package/src/schemas/custom-metadata.schema.json +81 -0
- package/src/schemas/metadata.schema.json +127 -41
- package/src/schemas/stacks.schema.json +3 -45
- package/dist/chunk-3SLO2QPW.js.map +0 -1
- package/dist/chunk-6YMW4HMX.js.map +0 -1
- package/dist/chunk-AHZ34QVK.js.map +0 -1
- package/dist/chunk-BKL3DF2Q.js +0 -45
- package/dist/chunk-BKL3DF2Q.js.map +0 -1
- package/dist/chunk-CKPJTMNC.js.map +0 -1
- package/dist/chunk-D7FEORKC.js +0 -253
- package/dist/chunk-D7FEORKC.js.map +0 -1
- package/dist/chunk-F43WGOGN.js.map +0 -1
- package/dist/chunk-FKRYJOPC.js.map +0 -1
- package/dist/chunk-HJVWBSLM.js.map +0 -1
- package/dist/chunk-HMJGSAKV.js.map +0 -1
- package/dist/chunk-LBTW5HSY.js.map +0 -1
- package/dist/chunk-MGQVO357.js.map +0 -1
- package/dist/chunk-Q3YMO5YG.js.map +0 -1
- package/dist/chunk-T4EXUIBY.js +0 -19
- package/dist/chunk-T4EXUIBY.js.map +0 -1
- package/dist/chunk-UQTG4ZBA.js.map +0 -1
- package/dist/chunk-URAXGHF2.js.map +0 -1
- package/dist/chunk-V2XIWRHP.js.map +0 -1
- package/dist/chunk-WWHDP5CP.js.map +0 -1
- package/dist/chunk-ZEJIEC2A.js.map +0 -1
- package/dist/chunk-ZFRALAK5.js.map +0 -1
- package/dist/chunk-ZYUASJUN.js.map +0 -1
- package/dist/source-manager-LJH225GA.js +0 -19
- package/dist/stores/matrix-store.js +0 -15
- package/dist/stores/matrix-store.js.map +0 -1
- package/dist/stores/matrix-store.test.js +0 -127
- package/dist/stores/matrix-store.test.js.map +0 -1
- /package/dist/{chunk-OODTDGEM.js.map → chunk-3K6FSET7.js.map} +0 -0
- /package/dist/{chunk-SEAL43IR.js.map → chunk-G23HPF6K.js.map} +0 -0
- /package/dist/{chunk-LM5YQUBR.js.map → chunk-H4ETXZVL.js.map} +0 -0
- /package/dist/{chunk-RJOLQ7EK.js.map → chunk-KE2EAVFQ.js.map} +0 -0
- /package/dist/{chunk-52THXN5G.js.map → chunk-NUJHWYCR.js.map} +0 -0
- /package/dist/{chunk-J4TVAB5H.js.map → chunk-T7QY777F.js.map} +0 -0
- /package/dist/{chunk-G3LNIYZG.js.map → chunk-Y47CLMWE.js.map} +0 -0
- /package/dist/{loader-KVKSTKWX.js.map → loader-XQ3WBTVP.js.map} +0 -0
- /package/dist/{source-loader-65IAJPNV.js.map → source-loader-F4PGP6LH.js.map} +0 -0
- /package/dist/{source-manager-LJH225GA.js.map → source-manager-QCIO4XZK.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/cli/components/wizard/step-build.test.tsx"],"sourcesContent":["import { render } from \"ink-testing-library\";\nimport { indexBy } from \"remeda\";\nimport { describe, expect, it, beforeEach, afterEach, vi } from \"vitest\";\nimport { StepBuild, type StepBuildProps } from \"./step-build\";\nimport { validateBuildStep } from \"../../lib/wizard/index\";\nimport { orderDomains } from \"./utils\";\nimport type { CategoryRow as GridCategoryRow } from \"./category-grid\";\nimport type {\n CategoryDefinition,\n Domain,\n ResolvedSkill,\n Category,\n CategorySelections,\n} from \"../../types\";\nimport {\n ENTER,\n ESCAPE,\n RENDER_DELAY_MS,\n INPUT_DELAY_MS,\n delay,\n} from \"../../lib/__tests__/test-constants\";\nimport { createMockSkill, createMockMatrix, SKILLS } from \"../../lib/__tests__/helpers\";\nimport { useMatrixStore } from \"../../stores/matrix-store\";\nimport {\n WEB_FRAMEWORK_CATEGORY,\n WEB_STYLING_CATEGORY,\n WEB_STATE_CATEGORY,\n API_FRAMEWORK_CATEGORY,\n API_DATABASE_CATEGORY,\n CLI_FRAMEWORK_CATEGORY,\n} from \"../../lib/__tests__/mock-data/mock-categories.js\";\n\nconst buildTestMatrix = (categories: CategoryDefinition[], skills: ResolvedSkill[]) =>\n createMockMatrix(...skills, {\n // Test data construction cast: indexBy returns generic Record\n categories: indexBy(categories, (c) => c.id) as Record<Category, CategoryDefinition>,\n });\n\nconst defaultMatrix = buildTestMatrix(\n [\n WEB_FRAMEWORK_CATEGORY,\n WEB_STYLING_CATEGORY,\n WEB_STATE_CATEGORY,\n API_FRAMEWORK_CATEGORY,\n API_DATABASE_CATEGORY,\n ],\n [\n SKILLS.react,\n SKILLS.vue,\n SKILLS.tailwind,\n SKILLS.scss,\n SKILLS.zustand,\n SKILLS.hono,\n SKILLS.drizzle,\n ],\n);\n\nconst defaultProps: StepBuildProps = {\n domain: \"web\",\n selectedDomains: [\"web\"],\n selections: {},\n allSelections: [],\n showLabels: false,\n onToggle: vi.fn(),\n onToggleLabels: vi.fn(),\n onContinue: vi.fn(),\n onBack: vi.fn(),\n};\n\nconst renderStepBuild = (props: Partial<StepBuildProps> = {}) => {\n return render(<StepBuild {...defaultProps} {...props} />);\n};\n\ndescribe(\"StepBuild component\", () => {\n let cleanup: (() => void) | undefined;\n\n beforeEach(() => {\n useMatrixStore.getState().setMatrix(defaultMatrix);\n });\n\n afterEach(() => {\n cleanup?.();\n cleanup = undefined;\n });\n\n describe(\"rendering\", () => {\n it(\"should render CategoryGrid with correct categories for domain\", () => {\n // For web domain with framework-first flow, initially only shows Framework\n // To see other categories, need a framework selection\n const { lastFrame, unmount } = renderStepBuild({\n selections: { \"web-framework\": [\"web-framework-react\"] }, // Framework selected to show other categories\n });\n cleanup = unmount;\n\n const output = lastFrame();\n // Web domain should show Framework, Styling, Client State (when framework selected)\n expect(output).toContain(\"Framework\");\n expect(output).toContain(\"Styling\");\n expect(output).toContain(\"Client State\");\n // Should NOT show API categories\n expect(output).not.toContain(\"API Framework\");\n expect(output).not.toContain(\"Database\");\n });\n\n it(\"should render API categories when domain is api\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n domain: \"api\",\n });\n cleanup = unmount;\n\n const output = lastFrame();\n // API domain should show API Framework, Database\n expect(output).toContain(\"API Framework\");\n expect(output).toContain(\"Database\");\n // Should NOT show Web categories\n expect(output).not.toContain(\"Styling\");\n expect(output).not.toContain(\"Client State\");\n });\n\n it(\"should render skills as options\", () => {\n // Need framework selected to see other categories in web domain\n const { lastFrame, unmount } = renderStepBuild({\n selections: { \"web-framework\": [\"web-framework-react\"] },\n });\n cleanup = unmount;\n\n const output = lastFrame();\n // Framework skills\n expect(output).toContain(\"React\");\n expect(output).toContain(\"Vue\");\n // Styling skills (visible after framework selected)\n expect(output).toContain(\"Tailwind\");\n expect(output).toContain(\"Scss Modules\");\n });\n\n it(\"should show required indicator (*) for required categories\", () => {\n const { lastFrame, unmount } = renderStepBuild();\n cleanup = unmount;\n\n const output = lastFrame();\n // Framework and Styling are required\n expect(output).toContain(\"*\");\n });\n\n it(\"should render categories for the domain\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n selections: { \"web-framework\": [\"web-framework-react\"] },\n });\n cleanup = unmount;\n\n const output = lastFrame();\n // Should render the domain categories\n expect(output).toContain(\"Framework\");\n expect(output).toContain(\"Styling\");\n });\n });\n\n describe(\"domain header\", () => {\n it(\"should show ViewTitle with current domain when multiple domains selected\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n selectedDomains: [\"web\", \"api\"],\n });\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Customize your Web stack\");\n });\n\n it(\"should show ViewTitle with domain when only one selected\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n selectedDomains: [\"web\"],\n });\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Customize your Web stack\");\n });\n\n it(\"should show ViewTitle for current domain on final domain\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n selectedDomains: [\"web\", \"api\"],\n domain: \"api\",\n });\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Customize your API stack\");\n });\n\n it(\"should show correct domain display names\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n selectedDomains: [\"web\", \"api\", \"cli\"],\n domain: \"api\",\n });\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Customize your API stack\");\n });\n\n it(\"should display domains in canonical order regardless of selection order\", () => {\n // Domains selected in reverse order: CLI, Mobile, API, Web\n expect(orderDomains([\"cli\", \"mobile\", \"api\", \"web\"])).toEqual([\n \"web\",\n \"api\",\n \"mobile\",\n \"cli\",\n ]);\n });\n\n it(\"should preserve canonical order with partial domain selection\", () => {\n // Only CLI and Web selected, in reverse order\n expect(orderDomains([\"cli\", \"web\"])).toEqual([\"web\", \"cli\"]);\n });\n\n it(\"should place custom domains before built-in domains\", () => {\n expect(orderDomains([\"web\", \"gaming\" as Domain, \"api\", \"devops\" as Domain])).toEqual([\n \"devops\",\n \"gaming\",\n \"web\",\n \"api\",\n ]);\n });\n });\n\n describe(\"category filtering\", () => {\n it(\"should filter categories correctly by domain\", () => {\n // Web domain with framework selected (to bypass framework-first filter)\n const { lastFrame: webFrame, unmount: webUnmount } = renderStepBuild({\n domain: \"web\",\n selections: { \"web-framework\": [\"web-framework-react\"] },\n });\n const webOutput = webFrame();\n webUnmount();\n\n // API domain (no framework-first filter for API)\n const { lastFrame: apiFrame, unmount: apiUnmount } = renderStepBuild({\n domain: \"api\",\n });\n cleanup = apiUnmount;\n const apiOutput = apiFrame();\n\n // Web should have Framework, Styling, Client State (with framework selected)\n expect(webOutput).toContain(\"Framework\");\n expect(webOutput).toContain(\"Styling\");\n expect(webOutput).toContain(\"Client State\");\n expect(webOutput).not.toContain(\"API Framework\");\n\n // API should have API Framework, Database\n expect(apiOutput).toContain(\"API Framework\");\n expect(apiOutput).toContain(\"Database\");\n expect(apiOutput).not.toContain(\"Styling\");\n });\n\n it(\"should sort categories by order\", () => {\n // Need framework selected to see all categories\n const { lastFrame, unmount } = renderStepBuild({\n selections: { \"web-framework\": [\"web-framework-react\"] },\n });\n cleanup = unmount;\n\n const output = lastFrame();\n // Framework (order 0) should appear before Styling (order 1)\n // and Styling before Client State (order 2)\n const frameworkIndex = output?.indexOf(\"Framework\") ?? -1;\n const stylingIndex = output?.indexOf(\"Styling\") ?? -1;\n const stateIndex = output?.indexOf(\"Client State\") ?? -1;\n\n expect(frameworkIndex).toBeLessThan(stylingIndex);\n expect(stylingIndex).toBeLessThan(stateIndex);\n });\n });\n\n describe(\"option states\", () => {\n it(\"should show selected options correctly\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n allSelections: [\"web-framework-react\"],\n selections: { \"web-framework\": [\"web-framework-react\"] },\n });\n cleanup = unmount;\n\n const output = lastFrame();\n // Should show selected option (no circle symbol anymore, uses background)\n // Just verify the selected label is present\n expect(output).toContain(\"React\");\n });\n\n it(\"should pass showLabels to CategoryGrid\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n showLabels: true,\n });\n cleanup = unmount;\n\n const output = lastFrame();\n // Labels toggle is now shown globally in wizard-layout\n // Verify component renders without error\n expect(output).toBeDefined();\n });\n });\n\n describe(\"keyboard navigation\", () => {\n it(\"should call onContinue when Enter is pressed with valid selections\", async () => {\n const onContinue = vi.fn();\n // Provide selections for required categories to pass validation\n const { stdin, unmount } = renderStepBuild({\n onContinue,\n selections: {\n \"web-framework\": [\"web-framework-react\"],\n \"web-styling\": [\"web-styling-tailwind\"],\n },\n });\n cleanup = unmount;\n\n await delay(RENDER_DELAY_MS);\n stdin.write(ENTER);\n await delay(INPUT_DELAY_MS);\n\n expect(onContinue).toHaveBeenCalled();\n });\n\n it(\"should call onBack when Escape is pressed\", async () => {\n const onBack = vi.fn();\n const { stdin, unmount } = renderStepBuild({ onBack });\n cleanup = unmount;\n\n await delay(RENDER_DELAY_MS);\n stdin.write(ESCAPE);\n await delay(INPUT_DELAY_MS);\n\n expect(onBack).toHaveBeenCalled();\n });\n\n it(\"should pass toggle callback to CategoryGrid\", async () => {\n const onToggle = vi.fn();\n const { stdin, unmount } = renderStepBuild({\n onToggle,\n });\n cleanup = unmount;\n\n await delay(RENDER_DELAY_MS);\n // Space should trigger toggle\n stdin.write(\" \");\n await delay(INPUT_DELAY_MS);\n\n expect(onToggle).toHaveBeenCalled();\n });\n });\n\n describe(\"toggle callbacks\", () => {\n it(\"should pass onToggleLabels to CategoryGrid\", async () => {\n const onToggleLabels = vi.fn();\n const { stdin, unmount } = renderStepBuild({ onToggleLabels });\n cleanup = unmount;\n\n await delay(RENDER_DELAY_MS);\n stdin.write(\"d\"); // 'd' key toggles compatibility labels\n await delay(INPUT_DELAY_MS);\n\n expect(onToggleLabels).toHaveBeenCalled();\n });\n });\n\n describe(\"edge cases\", () => {\n it(\"should handle domain with no categories\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n domain: \"mobile\", // No mobile categories in test matrix\n });\n cleanup = unmount;\n\n const output = lastFrame();\n // Should show empty state message from CategoryGrid\n expect(output).toContain(\"No categories to display\");\n });\n\n it(\"should handle unknown domain gracefully\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n domain: \"shared\",\n });\n cleanup = unmount;\n\n const output = lastFrame();\n // Should render without crashing\n expect(output).toBeDefined();\n });\n\n it(\"should handle empty allSelections\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n allSelections: [],\n });\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Framework\");\n });\n\n it(\"should handle allSelections with skills from other domains\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n domain: \"web\",\n allSelections: [\"api-framework-hono\", \"api-database-drizzle\"], // API skills in test matrix\n selections: { \"web-framework\": [\"web-framework-react\"] }, // Need framework to see other categories\n });\n cleanup = unmount;\n\n const output = lastFrame();\n // Should still render web categories\n expect(output).toContain(\"Framework\");\n expect(output).toContain(\"Styling\");\n });\n });\n\n describe(\"multi-domain scenarios\", () => {\n it(\"should show ViewTitle for current domain in multi-domain flow\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n domain: \"web\",\n selectedDomains: [\"web\", \"api\"],\n });\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Customize your Web stack\");\n });\n\n it(\"should show ViewTitle for last domain in multi-domain flow\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n domain: \"api\",\n selectedDomains: [\"web\", \"api\"],\n });\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Customize your API stack\");\n });\n\n it(\"should show ViewTitle for current domain in three-domain flow\", () => {\n // Add cli category to matrix\n const cliFrameworkCategory = { ...CLI_FRAMEWORK_CATEGORY, required: true, order: 0 };\n const commanderSkill = createMockSkill(\"cli-framework-commander\", {\n displayName: \"commander\",\n });\n\n const matrixWithCli = buildTestMatrix(\n [\n WEB_FRAMEWORK_CATEGORY,\n WEB_STYLING_CATEGORY,\n WEB_STATE_CATEGORY,\n API_FRAMEWORK_CATEGORY,\n API_DATABASE_CATEGORY,\n cliFrameworkCategory,\n ],\n [\n SKILLS.react,\n SKILLS.vue,\n SKILLS.tailwind,\n SKILLS.scss,\n SKILLS.zustand,\n SKILLS.hono,\n SKILLS.drizzle,\n commanderSkill,\n ],\n );\n\n useMatrixStore.getState().setMatrix(matrixWithCli);\n const { lastFrame, unmount } = renderStepBuild({\n domain: \"api\",\n selectedDomains: [\"web\", \"api\", \"cli\"],\n });\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Customize your API stack\");\n });\n });\n\n describe(\"header and selection count\", () => {\n it(\"should show ViewTitle with domain name\", () => {\n const { lastFrame, unmount } = renderStepBuild();\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Customize your Web stack\");\n });\n\n it(\"should render ViewTitle with domain display name\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n domain: \"api\",\n });\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Customize your API stack\");\n });\n });\n\n describe(\"keyboard help text\", () => {\n it(\"should respond to d key for toggling compatibility labels\", async () => {\n const onToggleLabels = vi.fn();\n const { stdin, unmount } = renderStepBuild({ onToggleLabels });\n cleanup = unmount;\n\n await delay(RENDER_DELAY_MS);\n stdin.write(\"d\");\n await delay(INPUT_DELAY_MS);\n\n expect(onToggleLabels).toHaveBeenCalled();\n });\n });\n\n describe(\"validateBuildStep\", () => {\n it(\"should return valid when required categories have selections\", () => {\n const categories: GridCategoryRow[] = [\n {\n id: \"web-framework\",\n displayName: \"Framework\",\n required: true,\n exclusive: true,\n options: [{ id: \"web-framework-react\", state: \"normal\", selected: true }],\n },\n ];\n const selections: CategorySelections = { \"web-framework\": [\"web-framework-react\"] };\n\n const result = validateBuildStep(categories, selections);\n expect(result.valid).toBe(true);\n expect(result.message).toBeUndefined();\n });\n\n it(\"should return invalid when required category has no selection\", () => {\n const categories: GridCategoryRow[] = [\n {\n id: \"web-framework\",\n displayName: \"Framework\",\n required: true,\n exclusive: true,\n options: [{ id: \"web-framework-react\", state: \"normal\", selected: false }],\n },\n ];\n const selections: CategorySelections = {};\n\n const result = validateBuildStep(categories, selections);\n expect(result.valid).toBe(false);\n expect(result.message).toContain(\"Framework\");\n });\n\n it(\"should return valid when optional categories have no selections\", () => {\n const categories: GridCategoryRow[] = [\n {\n id: \"web-client-state\",\n displayName: \"State Management\",\n required: false,\n exclusive: true,\n options: [\n {\n id: \"web-state-zustand\",\n state: \"normal\",\n selected: false,\n },\n ],\n },\n ];\n const selections: CategorySelections = {};\n\n const result = validateBuildStep(categories, selections);\n expect(result.valid).toBe(true);\n });\n\n it(\"should return invalid for first missing required category\", () => {\n const categories: GridCategoryRow[] = [\n {\n id: \"web-framework\",\n displayName: \"Framework\",\n required: true,\n exclusive: true,\n options: [],\n },\n {\n id: \"web-styling\",\n displayName: \"Styling\",\n required: true,\n exclusive: true,\n options: [],\n },\n ];\n const selections: CategorySelections = {};\n\n const result = validateBuildStep(categories, selections);\n expect(result.valid).toBe(false);\n expect(result.message).toContain(\"Framework\"); // Should be the first one\n });\n });\n\n describe(\"validation on continue\", () => {\n it(\"should show validation error when trying to continue without required selection\", async () => {\n const onContinue = vi.fn();\n const { stdin, lastFrame, unmount } = renderStepBuild({\n onContinue,\n selections: {},\n });\n cleanup = unmount;\n\n await delay(RENDER_DELAY_MS);\n\n // Press Enter to continue without selecting required framework\n stdin.write(ENTER);\n await delay(INPUT_DELAY_MS);\n\n // Should show validation error and NOT call onContinue\n const output = lastFrame();\n expect(output).toContain(\"Select at least one skill\");\n expect(onContinue).not.toHaveBeenCalled();\n });\n\n it(\"should call onContinue when validation passes\", async () => {\n const onContinue = vi.fn();\n const { stdin, unmount } = renderStepBuild({\n onContinue,\n selections: {\n \"web-framework\": [\"web-framework-react\"],\n \"web-styling\": [\"web-styling-tailwind\"],\n },\n });\n cleanup = unmount;\n\n await delay(RENDER_DELAY_MS);\n\n // Press Enter to continue with required selections\n stdin.write(ENTER);\n await delay(INPUT_DELAY_MS);\n\n expect(onContinue).toHaveBeenCalled();\n });\n });\n});\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/cli/components/wizard/step-build.test.tsx"],"sourcesContent":["import { render } from \"ink-testing-library\";\nimport { indexBy } from \"remeda\";\nimport { describe, expect, it, beforeEach, afterEach, vi } from \"vitest\";\nimport { StepBuild, type StepBuildProps } from \"./step-build\";\nimport { validateBuildStep } from \"../../lib/wizard/index\";\nimport { orderDomains } from \"./utils\";\nimport type { CategoryRow as GridCategoryRow } from \"./category-grid\";\nimport type {\n CategoryDefinition,\n Domain,\n ResolvedSkill,\n Category,\n CategorySelections,\n SkillId,\n} from \"../../types\";\nimport {\n ENTER,\n ESCAPE,\n RENDER_DELAY_MS,\n INPUT_DELAY_MS,\n delay,\n} from \"../../lib/__tests__/test-constants\";\nimport { createMockSkill, createMockMatrix, SKILLS } from \"../../lib/__tests__/helpers\";\nimport { initializeMatrix } from \"../../lib/matrix/matrix-provider\";\nimport {\n WEB_FRAMEWORK_CATEGORY,\n WEB_STYLING_CATEGORY,\n WEB_STATE_CATEGORY,\n API_FRAMEWORK_CATEGORY,\n API_DATABASE_CATEGORY,\n CLI_FRAMEWORK_CATEGORY,\n} from \"../../lib/__tests__/mock-data/mock-categories.js\";\n\nconst buildTestMatrix = (categories: CategoryDefinition[], skills: ResolvedSkill[]) =>\n createMockMatrix(...skills, {\n // Test data construction cast: indexBy returns generic Record\n categories: indexBy(categories, (c) => c.id) as Record<Category, CategoryDefinition>,\n });\n\nconst defaultMatrix = buildTestMatrix(\n [\n WEB_FRAMEWORK_CATEGORY,\n WEB_STYLING_CATEGORY,\n WEB_STATE_CATEGORY,\n API_FRAMEWORK_CATEGORY,\n API_DATABASE_CATEGORY,\n ],\n [\n SKILLS.react,\n SKILLS.vue,\n SKILLS.tailwind,\n SKILLS.scss,\n SKILLS.zustand,\n SKILLS.hono,\n SKILLS.drizzle,\n ],\n);\n\nconst defaultProps: StepBuildProps = {\n domain: \"web\",\n selectedDomains: [\"web\"],\n selections: {},\n allSelections: [],\n showLabels: false,\n onToggle: vi.fn(),\n onToggleLabels: vi.fn(),\n onContinue: vi.fn(),\n onBack: vi.fn(),\n};\n\nconst renderStepBuild = (props: Partial<StepBuildProps> = {}) => {\n return render(<StepBuild {...defaultProps} {...props} />);\n};\n\ndescribe(\"StepBuild component\", () => {\n let cleanup: (() => void) | undefined;\n\n beforeEach(() => {\n initializeMatrix(defaultMatrix);\n });\n\n afterEach(() => {\n cleanup?.();\n cleanup = undefined;\n });\n\n describe(\"rendering\", () => {\n it(\"should render CategoryGrid with correct categories for domain\", () => {\n // For web domain with framework-first flow, initially only shows Framework\n // To see other categories, need a framework selection\n const { lastFrame, unmount } = renderStepBuild({\n selections: { \"web-framework\": [\"web-framework-react\"] }, // Framework selected to show other categories\n });\n cleanup = unmount;\n\n const output = lastFrame();\n // Web domain should show Framework, Styling, Client State (when framework selected)\n expect(output).toContain(\"Framework\");\n expect(output).toContain(\"Styling\");\n expect(output).toContain(\"Client State\");\n // Should NOT show API categories\n expect(output).not.toContain(\"API Framework\");\n expect(output).not.toContain(\"Database\");\n });\n\n it(\"should render API categories when domain is api\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n domain: \"api\",\n });\n cleanup = unmount;\n\n const output = lastFrame();\n // API domain should show API Framework, Database\n expect(output).toContain(\"API Framework\");\n expect(output).toContain(\"Database\");\n // Should NOT show Web categories\n expect(output).not.toContain(\"Styling\");\n expect(output).not.toContain(\"Client State\");\n });\n\n it(\"should render skills as options\", () => {\n // Need framework selected to see other categories in web domain\n const { lastFrame, unmount } = renderStepBuild({\n selections: { \"web-framework\": [\"web-framework-react\"] },\n });\n cleanup = unmount;\n\n const output = lastFrame();\n // Framework skills\n expect(output).toContain(\"React\");\n expect(output).toContain(\"Vue\");\n // Styling skills (visible after framework selected)\n expect(output).toContain(\"Tailwind\");\n expect(output).toContain(\"Scss Modules\");\n });\n\n it(\"should show required indicator (*) for required categories\", () => {\n const { lastFrame, unmount } = renderStepBuild();\n cleanup = unmount;\n\n const output = lastFrame();\n // Framework and Styling are required\n expect(output).toContain(\"*\");\n });\n\n it(\"should render categories for the domain\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n selections: { \"web-framework\": [\"web-framework-react\"] },\n });\n cleanup = unmount;\n\n const output = lastFrame();\n // Should render the domain categories\n expect(output).toContain(\"Framework\");\n expect(output).toContain(\"Styling\");\n });\n });\n\n describe(\"domain header\", () => {\n it(\"should show ViewTitle with current domain when multiple domains selected\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n selectedDomains: [\"web\", \"api\"],\n });\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Customize your Web stack\");\n });\n\n it(\"should show ViewTitle with domain when only one selected\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n selectedDomains: [\"web\"],\n });\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Customize your Web stack\");\n });\n\n it(\"should show ViewTitle for current domain on final domain\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n selectedDomains: [\"web\", \"api\"],\n domain: \"api\",\n });\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Customize your API stack\");\n });\n\n it(\"should show correct domain display names\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n selectedDomains: [\"web\", \"api\", \"cli\"],\n domain: \"api\",\n });\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Customize your API stack\");\n });\n\n it(\"should display domains in canonical order regardless of selection order\", () => {\n // Domains selected in reverse order: CLI, Mobile, API, Web\n expect(orderDomains([\"cli\", \"mobile\", \"api\", \"web\"])).toEqual([\n \"web\",\n \"api\",\n \"mobile\",\n \"cli\",\n ]);\n });\n\n it(\"should preserve canonical order with partial domain selection\", () => {\n // Only CLI and Web selected, in reverse order\n expect(orderDomains([\"cli\", \"web\"])).toEqual([\"web\", \"cli\"]);\n });\n\n it(\"should place custom domains before built-in domains\", () => {\n expect(orderDomains([\"web\", \"gaming\" as Domain, \"api\", \"devops\" as Domain])).toEqual([\n \"devops\",\n \"gaming\",\n \"web\",\n \"api\",\n ]);\n });\n });\n\n describe(\"category filtering\", () => {\n it(\"should filter categories correctly by domain\", () => {\n // Web domain with framework selected (to bypass framework-first filter)\n const { lastFrame: webFrame, unmount: webUnmount } = renderStepBuild({\n domain: \"web\",\n selections: { \"web-framework\": [\"web-framework-react\"] },\n });\n const webOutput = webFrame();\n webUnmount();\n\n // API domain (no framework-first filter for API)\n const { lastFrame: apiFrame, unmount: apiUnmount } = renderStepBuild({\n domain: \"api\",\n });\n cleanup = apiUnmount;\n const apiOutput = apiFrame();\n\n // Web should have Framework, Styling, Client State (with framework selected)\n expect(webOutput).toContain(\"Framework\");\n expect(webOutput).toContain(\"Styling\");\n expect(webOutput).toContain(\"Client State\");\n expect(webOutput).not.toContain(\"API Framework\");\n\n // API should have API Framework, Database\n expect(apiOutput).toContain(\"API Framework\");\n expect(apiOutput).toContain(\"Database\");\n expect(apiOutput).not.toContain(\"Styling\");\n });\n\n it(\"should sort categories by order\", () => {\n // Need framework selected to see all categories\n const { lastFrame, unmount } = renderStepBuild({\n selections: { \"web-framework\": [\"web-framework-react\"] },\n });\n cleanup = unmount;\n\n const output = lastFrame();\n // Framework (order 0) should appear before Styling (order 1)\n // and Styling before Client State (order 2)\n const frameworkIndex = output?.indexOf(\"Framework\") ?? -1;\n const stylingIndex = output?.indexOf(\"Styling\") ?? -1;\n const stateIndex = output?.indexOf(\"Client State\") ?? -1;\n\n expect(frameworkIndex).toBeLessThan(stylingIndex);\n expect(stylingIndex).toBeLessThan(stateIndex);\n });\n });\n\n describe(\"option states\", () => {\n it(\"should show selected options correctly\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n allSelections: [\"web-framework-react\"],\n selections: { \"web-framework\": [\"web-framework-react\"] },\n });\n cleanup = unmount;\n\n const output = lastFrame();\n // Should show selected option (no circle symbol anymore, uses background)\n // Just verify the selected label is present\n expect(output).toContain(\"React\");\n });\n\n it(\"should pass showLabels to CategoryGrid\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n showLabels: true,\n });\n cleanup = unmount;\n\n const output = lastFrame();\n // Labels toggle is now shown globally in wizard-layout\n // Verify component renders without error\n expect(output).toBeDefined();\n });\n });\n\n describe(\"keyboard navigation\", () => {\n it(\"should call onContinue when Enter is pressed with valid selections\", async () => {\n const onContinue = vi.fn();\n // Provide selections for required categories to pass validation\n const { stdin, unmount } = renderStepBuild({\n onContinue,\n selections: {\n \"web-framework\": [\"web-framework-react\"],\n \"web-styling\": [\"web-styling-tailwind\"],\n },\n });\n cleanup = unmount;\n\n await delay(RENDER_DELAY_MS);\n stdin.write(ENTER);\n await delay(INPUT_DELAY_MS);\n\n expect(onContinue).toHaveBeenCalled();\n });\n\n it(\"should call onBack when Escape is pressed\", async () => {\n const onBack = vi.fn();\n const { stdin, unmount } = renderStepBuild({ onBack });\n cleanup = unmount;\n\n await delay(RENDER_DELAY_MS);\n stdin.write(ESCAPE);\n await delay(INPUT_DELAY_MS);\n\n expect(onBack).toHaveBeenCalled();\n });\n\n it(\"should pass toggle callback to CategoryGrid\", async () => {\n const onToggle = vi.fn();\n const { stdin, unmount } = renderStepBuild({\n onToggle,\n });\n cleanup = unmount;\n\n await delay(RENDER_DELAY_MS);\n // Space should trigger toggle\n stdin.write(\" \");\n await delay(INPUT_DELAY_MS);\n\n expect(onToggle).toHaveBeenCalled();\n });\n });\n\n describe(\"toggle callbacks\", () => {\n it(\"should pass onToggleLabels to CategoryGrid\", async () => {\n const onToggleLabels = vi.fn();\n const { stdin, unmount } = renderStepBuild({ onToggleLabels });\n cleanup = unmount;\n\n await delay(RENDER_DELAY_MS);\n stdin.write(\"d\"); // 'd' key toggles compatibility labels\n await delay(INPUT_DELAY_MS);\n\n expect(onToggleLabels).toHaveBeenCalled();\n });\n });\n\n describe(\"edge cases\", () => {\n it(\"should handle domain with no categories\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n domain: \"mobile\", // No mobile categories in test matrix\n });\n cleanup = unmount;\n\n const output = lastFrame();\n // Should show empty state message from CategoryGrid\n expect(output).toContain(\"No categories to display\");\n });\n\n it(\"should handle unknown domain gracefully\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n domain: \"shared\",\n });\n cleanup = unmount;\n\n const output = lastFrame();\n // Should render without crashing\n expect(output).toBeDefined();\n });\n\n it(\"should handle empty allSelections\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n allSelections: [],\n });\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Framework\");\n });\n\n it(\"should handle allSelections with skills from other domains\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n domain: \"web\",\n allSelections: [\"api-framework-hono\", \"api-database-drizzle\"], // API skills in test matrix\n selections: { \"web-framework\": [\"web-framework-react\"] }, // Need framework to see other categories\n });\n cleanup = unmount;\n\n const output = lastFrame();\n // Should still render web categories\n expect(output).toContain(\"Framework\");\n expect(output).toContain(\"Styling\");\n });\n });\n\n describe(\"multi-domain scenarios\", () => {\n it(\"should show ViewTitle for current domain in multi-domain flow\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n domain: \"web\",\n selectedDomains: [\"web\", \"api\"],\n });\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Customize your Web stack\");\n });\n\n it(\"should show ViewTitle for last domain in multi-domain flow\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n domain: \"api\",\n selectedDomains: [\"web\", \"api\"],\n });\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Customize your API stack\");\n });\n\n it(\"should show ViewTitle for current domain in three-domain flow\", () => {\n // Add cli category to matrix\n const cliFrameworkCategory = { ...CLI_FRAMEWORK_CATEGORY, required: true, order: 0 };\n // Boundary cast: fictional skill ID for testing CLI domain display\n const commanderSkill = createMockSkill(\"cli-framework-commander\" as SkillId, {\n displayName: \"commander\",\n });\n\n const matrixWithCli = buildTestMatrix(\n [\n WEB_FRAMEWORK_CATEGORY,\n WEB_STYLING_CATEGORY,\n WEB_STATE_CATEGORY,\n API_FRAMEWORK_CATEGORY,\n API_DATABASE_CATEGORY,\n cliFrameworkCategory,\n ],\n [\n SKILLS.react,\n SKILLS.vue,\n SKILLS.tailwind,\n SKILLS.scss,\n SKILLS.zustand,\n SKILLS.hono,\n SKILLS.drizzle,\n commanderSkill,\n ],\n );\n\n initializeMatrix(matrixWithCli);\n const { lastFrame, unmount } = renderStepBuild({\n domain: \"api\",\n selectedDomains: [\"web\", \"api\", \"cli\"],\n });\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Customize your API stack\");\n });\n });\n\n describe(\"header and selection count\", () => {\n it(\"should show ViewTitle with domain name\", () => {\n const { lastFrame, unmount } = renderStepBuild();\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Customize your Web stack\");\n });\n\n it(\"should render ViewTitle with domain display name\", () => {\n const { lastFrame, unmount } = renderStepBuild({\n domain: \"api\",\n });\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Customize your API stack\");\n });\n });\n\n describe(\"keyboard help text\", () => {\n it(\"should respond to d key for toggling compatibility labels\", async () => {\n const onToggleLabels = vi.fn();\n const { stdin, unmount } = renderStepBuild({ onToggleLabels });\n cleanup = unmount;\n\n await delay(RENDER_DELAY_MS);\n stdin.write(\"d\");\n await delay(INPUT_DELAY_MS);\n\n expect(onToggleLabels).toHaveBeenCalled();\n });\n });\n\n describe(\"validateBuildStep\", () => {\n it(\"should return valid when required categories have selections\", () => {\n const categories: GridCategoryRow[] = [\n {\n id: \"web-framework\",\n displayName: \"Framework\",\n required: true,\n exclusive: true,\n options: [{ id: \"web-framework-react\", state: \"normal\", selected: true }],\n },\n ];\n const selections: CategorySelections = { \"web-framework\": [\"web-framework-react\"] };\n\n const result = validateBuildStep(categories, selections);\n expect(result.valid).toBe(true);\n expect(result.message).toBeUndefined();\n });\n\n it(\"should return invalid when required category has no selection\", () => {\n const categories: GridCategoryRow[] = [\n {\n id: \"web-framework\",\n displayName: \"Framework\",\n required: true,\n exclusive: true,\n options: [{ id: \"web-framework-react\", state: \"normal\", selected: false }],\n },\n ];\n const selections: CategorySelections = {};\n\n const result = validateBuildStep(categories, selections);\n expect(result.valid).toBe(false);\n expect(result.message).toContain(\"Framework\");\n });\n\n it(\"should return valid when optional categories have no selections\", () => {\n const categories: GridCategoryRow[] = [\n {\n id: \"web-client-state\",\n displayName: \"State Management\",\n required: false,\n exclusive: true,\n options: [\n {\n id: \"web-state-zustand\",\n state: \"normal\",\n selected: false,\n },\n ],\n },\n ];\n const selections: CategorySelections = {};\n\n const result = validateBuildStep(categories, selections);\n expect(result.valid).toBe(true);\n });\n\n it(\"should return invalid for first missing required category\", () => {\n const categories: GridCategoryRow[] = [\n {\n id: \"web-framework\",\n displayName: \"Framework\",\n required: true,\n exclusive: true,\n options: [],\n },\n {\n id: \"web-styling\",\n displayName: \"Styling\",\n required: true,\n exclusive: true,\n options: [],\n },\n ];\n const selections: CategorySelections = {};\n\n const result = validateBuildStep(categories, selections);\n expect(result.valid).toBe(false);\n expect(result.message).toContain(\"Framework\"); // Should be the first one\n });\n });\n\n describe(\"validation on continue\", () => {\n it(\"should show validation error when trying to continue without required selection\", async () => {\n const onContinue = vi.fn();\n const { stdin, lastFrame, unmount } = renderStepBuild({\n onContinue,\n selections: {},\n });\n cleanup = unmount;\n\n await delay(RENDER_DELAY_MS);\n\n // Press Enter to continue without selecting required framework\n stdin.write(ENTER);\n await delay(INPUT_DELAY_MS);\n\n // Should show validation error and NOT call onContinue\n const output = lastFrame();\n expect(output).toContain(\"Select at least one skill\");\n expect(onContinue).not.toHaveBeenCalled();\n });\n\n it(\"should call onContinue when validation passes\", async () => {\n const onContinue = vi.fn();\n const { stdin, unmount } = renderStepBuild({\n onContinue,\n selections: {\n \"web-framework\": [\"web-framework-react\"],\n \"web-styling\": [\"web-styling-tailwind\"],\n },\n });\n cleanup = unmount;\n\n await delay(RENDER_DELAY_MS);\n\n // Press Enter to continue with required selections\n stdin.write(ENTER);\n await delay(INPUT_DELAY_MS);\n\n expect(onContinue).toHaveBeenCalled();\n });\n });\n});\n"],"mappings":"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","names":[]}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
StepConfirm
|
|
4
|
-
} from "../../chunk-
|
|
5
|
-
import "../../chunk-
|
|
4
|
+
} from "../../chunk-NUJHWYCR.js";
|
|
5
|
+
import "../../chunk-BH4LN7XV.js";
|
|
6
6
|
import "../../chunk-AQYAVLZK.js";
|
|
7
7
|
import "../../chunk-6VIOO74O.js";
|
|
8
|
-
import "../../chunk-
|
|
9
|
-
import "../../chunk-
|
|
8
|
+
import "../../chunk-EMX7PA2I.js";
|
|
9
|
+
import "../../chunk-E74Q7GUE.js";
|
|
10
|
+
import "../../chunk-SRIH4U5Y.js";
|
|
10
11
|
import "../../chunk-EGMQ3SXN.js";
|
|
11
12
|
import "../../chunk-DHET7RCE.js";
|
|
12
13
|
export {
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from "../../chunk-66UDJBF6.js";
|
|
11
11
|
import {
|
|
12
12
|
buildSkillConfigs
|
|
13
|
-
} from "../../chunk-
|
|
13
|
+
} from "../../chunk-V5HR77EY.js";
|
|
14
14
|
import {
|
|
15
15
|
afterEach,
|
|
16
16
|
describe,
|
|
@@ -20,16 +20,17 @@ import {
|
|
|
20
20
|
} from "../../chunk-XY3XDVMI.js";
|
|
21
21
|
import {
|
|
22
22
|
StepConfirm
|
|
23
|
-
} from "../../chunk-
|
|
24
|
-
import "../../chunk-
|
|
23
|
+
} from "../../chunk-NUJHWYCR.js";
|
|
24
|
+
import "../../chunk-BH4LN7XV.js";
|
|
25
25
|
import "../../chunk-AQYAVLZK.js";
|
|
26
|
-
import "../../chunk-
|
|
26
|
+
import "../../chunk-OLWGGD4G.js";
|
|
27
27
|
import "../../chunk-6VIOO74O.js";
|
|
28
|
-
import "../../chunk-
|
|
29
|
-
import "../../chunk-
|
|
30
|
-
import "../../chunk-
|
|
31
|
-
import "../../chunk-
|
|
32
|
-
import "../../chunk-
|
|
28
|
+
import "../../chunk-3VNQPCOE.js";
|
|
29
|
+
import "../../chunk-ZBLSWJFM.js";
|
|
30
|
+
import "../../chunk-EMX7PA2I.js";
|
|
31
|
+
import "../../chunk-E74Q7GUE.js";
|
|
32
|
+
import "../../chunk-WJL4KU5V.js";
|
|
33
|
+
import "../../chunk-SRIH4U5Y.js";
|
|
33
34
|
import "../../chunk-EGMQ3SXN.js";
|
|
34
35
|
import "../../chunk-NKKYTCBH.js";
|
|
35
36
|
import {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/cli/components/wizard/step-confirm.test.tsx"],"sourcesContent":["import { render } from \"ink-testing-library\";\nimport { afterEach, describe, expect, it, vi } from \"vitest\";\nimport { StepConfirm } from \"./step-confirm\";\nimport { ENTER, ESCAPE, RENDER_DELAY_MS, delay } from \"../../lib/__tests__/test-constants\";\nimport { buildSkillConfigs } from \"../../lib/__tests__/helpers\";\n\ndescribe(\"StepConfirm component\", () => {\n let cleanup: (() => void) | undefined;\n\n afterEach(() => {\n cleanup?.();\n cleanup = undefined;\n });\n\n describe(\"stack path\", () => {\n it(\"should render stack name in title\", () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n stackName=\"nextjs-fullstack\"\n technologyCount={12}\n skillCount={12}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Ready to install nextjs-fullstack\");\n });\n\n it(\"should show technology count\", () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n stackName=\"nextjs-fullstack\"\n technologyCount={12}\n skillCount={12}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Technologies:\");\n expect(output).toContain(\"12\");\n });\n\n it(\"should show skill count with verified label\", () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n stackName=\"nextjs-fullstack\"\n technologyCount={12}\n skillCount={12}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Skills:\");\n expect(output).toContain(\"(all verified)\");\n });\n\n it(\"should show install mode as Plugin\", () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n stackName=\"nextjs-fullstack\"\n technologyCount={12}\n skillCount={12}\n skillConfigs={buildSkillConfigs([\"web-framework-react\", \"web-styling-scss-modules\"], {\n source: \"agents-inc\",\n })}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Install mode:\");\n expect(output).toContain(\"Plugin\");\n });\n\n it(\"should show install mode as Local\", () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n stackName=\"nextjs-fullstack\"\n technologyCount={12}\n skillCount={12}\n skillConfigs={buildSkillConfigs([\"web-framework-react\", \"web-styling-scss-modules\"])}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Install mode:\");\n expect(output).toContain(\"Local\");\n });\n\n it(\"should render confirm step content\", () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n stackName=\"nextjs-fullstack\"\n technologyCount={12}\n skillCount={12}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Ready to install\");\n });\n });\n\n describe(\"scratch path\", () => {\n it(\"should render custom stack title with domain names\", () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n selectedDomains={[\"web\", \"api\"]}\n domainSelections={{\n web: {\n \"web-framework\": [\"web-framework-react\"],\n \"web-styling\": [\"web-styling-scss-modules\"],\n },\n api: { \"api-api\": [\"api-framework-hono\"] },\n }}\n technologyCount={3}\n skillCount={3}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Ready to install your custom stack\");\n expect(output).toContain(\"Web + API\");\n });\n\n it(\"should show domain breakdown with technologies\", () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n selectedDomains={[\"web\", \"api\"]}\n domainSelections={{\n web: {\n \"web-framework\": [\"web-framework-react\"],\n \"web-styling\": [\"web-styling-scss-modules\"],\n },\n api: { \"api-api\": [\"api-framework-hono\"] },\n }}\n technologyCount={3}\n skillCount={3}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Web:\");\n expect(output).toContain(\"react\");\n expect(output).toContain(\"scss-modules\");\n expect(output).toContain(\"API:\");\n expect(output).toContain(\"hono\");\n });\n\n it(\"should handle single domain without plus sign\", () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n selectedDomains={[\"web\"]}\n domainSelections={{\n web: { \"web-framework\": [\"web-framework-react\"] },\n }}\n technologyCount={1}\n skillCount={1}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"(Web)\");\n expect(output).not.toContain(\"+\");\n });\n\n it(\"should skip domains with no selections\", () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n selectedDomains={[\"web\", \"api\"]}\n domainSelections={{\n web: { \"web-framework\": [\"web-framework-react\"] },\n api: {}, // Empty selections\n }}\n technologyCount={1}\n skillCount={1}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Web:\");\n expect(output).toContain(\"react\");\n // API section should not appear since no technologies selected\n const lines = output?.split(\"\\n\") || [];\n const apiLine = lines.find((line) => line.includes(\"API:\") && line.includes(\"hono\"));\n expect(apiLine).toBeUndefined();\n });\n });\n\n describe(\"keyboard navigation\", () => {\n it(\"should call onComplete when Enter is pressed\", async () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { stdin, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n stackName=\"nextjs-fullstack\"\n technologyCount={12}\n skillCount={12}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n await delay(RENDER_DELAY_MS);\n await stdin.write(ENTER);\n await delay(RENDER_DELAY_MS);\n\n expect(onComplete).toHaveBeenCalled();\n });\n\n it(\"should call onBack when Escape is pressed\", async () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { stdin, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n stackName=\"nextjs-fullstack\"\n technologyCount={12}\n skillCount={12}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n await delay(RENDER_DELAY_MS);\n await stdin.write(ESCAPE);\n await delay(RENDER_DELAY_MS);\n\n expect(onBack).toHaveBeenCalled();\n expect(onComplete).not.toHaveBeenCalled();\n });\n\n it(\"should not call onBack when Escape is pressed but onBack is not provided\", async () => {\n const onComplete = vi.fn();\n\n const { stdin, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n stackName=\"nextjs-fullstack\"\n technologyCount={12}\n skillCount={12}\n // No onBack provided\n />,\n );\n cleanup = unmount;\n\n await delay(RENDER_DELAY_MS);\n await stdin.write(ESCAPE);\n await delay(RENDER_DELAY_MS);\n\n // Should not crash and onComplete should not be called\n expect(onComplete).not.toHaveBeenCalled();\n });\n });\n\n describe(\"install mode display\", () => {\n it('should show \"Plugin\" when all skills use non-local source', () => {\n const onComplete = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n skillConfigs={buildSkillConfigs([\"web-framework-react\", \"web-styling-scss-modules\"], {\n source: \"agents-inc\",\n })}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Install mode:\");\n expect(output).toContain(\"Plugin\");\n });\n\n it('should show \"Local (editable copies)\" when all skills are local', () => {\n const onComplete = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n skillConfigs={buildSkillConfigs([\"web-framework-react\", \"web-styling-scss-modules\"])}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Install mode:\");\n expect(output).toContain(\"Local (editable copies)\");\n });\n\n it('should show \"Mixed\" with counts when skills have mixed sources', () => {\n const onComplete = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n skillConfigs={[\n ...buildSkillConfigs([\"web-framework-react\"]),\n ...buildSkillConfigs([\"web-styling-scss-modules\"], { source: \"agents-inc\" }),\n ...buildSkillConfigs([\"web-state-zustand\"]),\n ]}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Install mode:\");\n expect(output).toContain(\"Mixed\");\n expect(output).toContain(\"2 local\");\n expect(output).toContain(\"1 plugin\");\n });\n\n it(\"should not show install mode when skillConfigs is not provided\", () => {\n const onComplete = vi.fn();\n\n const { lastFrame, unmount } = render(<StepConfirm onComplete={onComplete} />);\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).not.toContain(\"Install mode:\");\n });\n });\n\n describe(\"default props\", () => {\n it(\"should render custom stack title when no stack name provided\", () => {\n const onComplete = vi.fn();\n\n const { lastFrame, unmount } = render(<StepConfirm onComplete={onComplete} />);\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Ready to install your custom stack\");\n });\n\n it(\"should not show stats when not provided\", () => {\n const onComplete = vi.fn();\n\n const { lastFrame, unmount } = render(<StepConfirm onComplete={onComplete} />);\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).not.toContain(\"Technologies:\");\n expect(output).not.toContain(\"Skills:\");\n expect(output).not.toContain(\"Install mode:\");\n });\n });\n});\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/cli/components/wizard/step-confirm.test.tsx"],"sourcesContent":["import { render } from \"ink-testing-library\";\nimport { afterEach, describe, expect, it, vi } from \"vitest\";\nimport { StepConfirm } from \"./step-confirm\";\nimport { ENTER, ESCAPE, RENDER_DELAY_MS, delay } from \"../../lib/__tests__/test-constants\";\nimport { buildSkillConfigs } from \"../../lib/__tests__/helpers\";\n\ndescribe(\"StepConfirm component\", () => {\n let cleanup: (() => void) | undefined;\n\n afterEach(() => {\n cleanup?.();\n cleanup = undefined;\n });\n\n describe(\"stack path\", () => {\n it(\"should render stack name in title\", () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n stackName=\"nextjs-fullstack\"\n technologyCount={12}\n skillCount={12}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Ready to install nextjs-fullstack\");\n });\n\n it(\"should show technology count\", () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n stackName=\"nextjs-fullstack\"\n technologyCount={12}\n skillCount={12}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Technologies:\");\n expect(output).toContain(\"12\");\n });\n\n it(\"should show skill count with verified label\", () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n stackName=\"nextjs-fullstack\"\n technologyCount={12}\n skillCount={12}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Skills:\");\n expect(output).toContain(\"(all verified)\");\n });\n\n it(\"should show install mode as Plugin\", () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n stackName=\"nextjs-fullstack\"\n technologyCount={12}\n skillCount={12}\n skillConfigs={buildSkillConfigs([\"web-framework-react\", \"web-styling-scss-modules\"], {\n source: \"agents-inc\",\n })}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Install mode:\");\n expect(output).toContain(\"Plugin\");\n });\n\n it(\"should show install mode as Local\", () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n stackName=\"nextjs-fullstack\"\n technologyCount={12}\n skillCount={12}\n skillConfigs={buildSkillConfigs([\"web-framework-react\", \"web-styling-scss-modules\"])}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Install mode:\");\n expect(output).toContain(\"Local\");\n });\n\n it(\"should render confirm step content\", () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n stackName=\"nextjs-fullstack\"\n technologyCount={12}\n skillCount={12}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Ready to install\");\n });\n });\n\n describe(\"scratch path\", () => {\n it(\"should render custom stack title with domain names\", () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n selectedDomains={[\"web\", \"api\"]}\n domainSelections={{\n web: {\n \"web-framework\": [\"web-framework-react\"],\n \"web-styling\": [\"web-styling-scss-modules\"],\n },\n api: { \"api-api\": [\"api-framework-hono\"] },\n }}\n technologyCount={3}\n skillCount={3}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Ready to install your custom stack\");\n expect(output).toContain(\"Web + API\");\n });\n\n it(\"should show domain breakdown with technologies\", () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n selectedDomains={[\"web\", \"api\"]}\n domainSelections={{\n web: {\n \"web-framework\": [\"web-framework-react\"],\n \"web-styling\": [\"web-styling-scss-modules\"],\n },\n api: { \"api-api\": [\"api-framework-hono\"] },\n }}\n technologyCount={3}\n skillCount={3}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Web:\");\n expect(output).toContain(\"react\");\n expect(output).toContain(\"scss-modules\");\n expect(output).toContain(\"API:\");\n expect(output).toContain(\"hono\");\n });\n\n it(\"should handle single domain without plus sign\", () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n selectedDomains={[\"web\"]}\n domainSelections={{\n web: { \"web-framework\": [\"web-framework-react\"] },\n }}\n technologyCount={1}\n skillCount={1}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"(Web)\");\n expect(output).not.toContain(\"+\");\n });\n\n it(\"should skip domains with no selections\", () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n selectedDomains={[\"web\", \"api\"]}\n domainSelections={{\n web: { \"web-framework\": [\"web-framework-react\"] },\n api: {}, // Empty selections\n }}\n technologyCount={1}\n skillCount={1}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Web:\");\n expect(output).toContain(\"react\");\n // API section should not appear since no technologies selected\n const lines = output?.split(\"\\n\") || [];\n const apiLine = lines.find((line) => line.includes(\"API:\") && line.includes(\"hono\"));\n expect(apiLine).toBeUndefined();\n });\n });\n\n describe(\"keyboard navigation\", () => {\n it(\"should call onComplete when Enter is pressed\", async () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { stdin, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n stackName=\"nextjs-fullstack\"\n technologyCount={12}\n skillCount={12}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n await delay(RENDER_DELAY_MS);\n await stdin.write(ENTER);\n await delay(RENDER_DELAY_MS);\n\n expect(onComplete).toHaveBeenCalled();\n });\n\n it(\"should call onBack when Escape is pressed\", async () => {\n const onComplete = vi.fn();\n const onBack = vi.fn();\n\n const { stdin, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n stackName=\"nextjs-fullstack\"\n technologyCount={12}\n skillCount={12}\n onBack={onBack}\n />,\n );\n cleanup = unmount;\n\n await delay(RENDER_DELAY_MS);\n await stdin.write(ESCAPE);\n await delay(RENDER_DELAY_MS);\n\n expect(onBack).toHaveBeenCalled();\n expect(onComplete).not.toHaveBeenCalled();\n });\n\n it(\"should not call onBack when Escape is pressed but onBack is not provided\", async () => {\n const onComplete = vi.fn();\n\n const { stdin, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n stackName=\"nextjs-fullstack\"\n technologyCount={12}\n skillCount={12}\n // No onBack provided\n />,\n );\n cleanup = unmount;\n\n await delay(RENDER_DELAY_MS);\n await stdin.write(ESCAPE);\n await delay(RENDER_DELAY_MS);\n\n // Should not crash and onComplete should not be called\n expect(onComplete).not.toHaveBeenCalled();\n });\n });\n\n describe(\"install mode display\", () => {\n it('should show \"Plugin\" when all skills use non-local source', () => {\n const onComplete = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n skillConfigs={buildSkillConfigs([\"web-framework-react\", \"web-styling-scss-modules\"], {\n source: \"agents-inc\",\n })}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Install mode:\");\n expect(output).toContain(\"Plugin\");\n });\n\n it('should show \"Local (editable copies)\" when all skills are local', () => {\n const onComplete = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n skillConfigs={buildSkillConfigs([\"web-framework-react\", \"web-styling-scss-modules\"])}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Install mode:\");\n expect(output).toContain(\"Local (editable copies)\");\n });\n\n it('should show \"Mixed\" with counts when skills have mixed sources', () => {\n const onComplete = vi.fn();\n\n const { lastFrame, unmount } = render(\n <StepConfirm\n onComplete={onComplete}\n skillConfigs={[\n ...buildSkillConfigs([\"web-framework-react\"]),\n ...buildSkillConfigs([\"web-styling-scss-modules\"], { source: \"agents-inc\" }),\n ...buildSkillConfigs([\"web-state-zustand\"]),\n ]}\n />,\n );\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Install mode:\");\n expect(output).toContain(\"Mixed\");\n expect(output).toContain(\"2 local\");\n expect(output).toContain(\"1 plugin\");\n });\n\n it(\"should not show install mode when skillConfigs is not provided\", () => {\n const onComplete = vi.fn();\n\n const { lastFrame, unmount } = render(<StepConfirm onComplete={onComplete} />);\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).not.toContain(\"Install mode:\");\n });\n });\n\n describe(\"default props\", () => {\n it(\"should render custom stack title when no stack name provided\", () => {\n const onComplete = vi.fn();\n\n const { lastFrame, unmount } = render(<StepConfirm onComplete={onComplete} />);\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Ready to install your custom stack\");\n });\n\n it(\"should not show stats when not provided\", () => {\n const onComplete = vi.fn();\n\n const { lastFrame, unmount } = render(<StepConfirm onComplete={onComplete} />);\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).not.toContain(\"Technologies:\");\n expect(output).not.toContain(\"Skills:\");\n expect(output).not.toContain(\"Install mode:\");\n });\n });\n});\n"],"mappings":"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","names":[]}
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
StepSettings
|
|
4
|
-
} from "../../chunk-
|
|
4
|
+
} from "../../chunk-H4ETXZVL.js";
|
|
5
5
|
import "../../chunk-7SOPVGDV.js";
|
|
6
|
-
import "../../chunk-KUV24B5M.js";
|
|
7
6
|
import "../../chunk-XMLCXRTS.js";
|
|
8
7
|
import "../../chunk-AQYAVLZK.js";
|
|
9
8
|
import "../../chunk-AUNBGZS4.js";
|
|
9
|
+
import "../../chunk-KUV24B5M.js";
|
|
10
10
|
import "../../chunk-U3IGFMCY.js";
|
|
11
11
|
import "../../chunk-6VIOO74O.js";
|
|
12
|
-
import "../../chunk-
|
|
13
|
-
import "../../chunk-
|
|
14
|
-
import "../../chunk-
|
|
15
|
-
import "../../chunk-
|
|
16
|
-
import "../../chunk-
|
|
12
|
+
import "../../chunk-3VNQPCOE.js";
|
|
13
|
+
import "../../chunk-ZBLSWJFM.js";
|
|
14
|
+
import "../../chunk-EMX7PA2I.js";
|
|
15
|
+
import "../../chunk-E74Q7GUE.js";
|
|
16
|
+
import "../../chunk-WJL4KU5V.js";
|
|
17
|
+
import "../../chunk-SRIH4U5Y.js";
|
|
17
18
|
import "../../chunk-EGMQ3SXN.js";
|
|
18
19
|
import "../../chunk-NKKYTCBH.js";
|
|
19
20
|
import "../../chunk-DHET7RCE.js";
|
|
@@ -19,19 +19,20 @@ import {
|
|
|
19
19
|
} from "../../chunk-XY3XDVMI.js";
|
|
20
20
|
import {
|
|
21
21
|
StepSettings
|
|
22
|
-
} from "../../chunk-
|
|
22
|
+
} from "../../chunk-H4ETXZVL.js";
|
|
23
23
|
import "../../chunk-7SOPVGDV.js";
|
|
24
|
-
import "../../chunk-KUV24B5M.js";
|
|
25
24
|
import "../../chunk-XMLCXRTS.js";
|
|
26
25
|
import "../../chunk-AQYAVLZK.js";
|
|
27
26
|
import "../../chunk-AUNBGZS4.js";
|
|
27
|
+
import "../../chunk-KUV24B5M.js";
|
|
28
28
|
import "../../chunk-U3IGFMCY.js";
|
|
29
29
|
import "../../chunk-6VIOO74O.js";
|
|
30
|
-
import "../../chunk-
|
|
31
|
-
import "../../chunk-
|
|
32
|
-
import "../../chunk-
|
|
33
|
-
import "../../chunk-
|
|
34
|
-
import "../../chunk-
|
|
30
|
+
import "../../chunk-3VNQPCOE.js";
|
|
31
|
+
import "../../chunk-ZBLSWJFM.js";
|
|
32
|
+
import "../../chunk-EMX7PA2I.js";
|
|
33
|
+
import "../../chunk-E74Q7GUE.js";
|
|
34
|
+
import "../../chunk-WJL4KU5V.js";
|
|
35
|
+
import "../../chunk-SRIH4U5Y.js";
|
|
35
36
|
import "../../chunk-EGMQ3SXN.js";
|
|
36
37
|
import "../../chunk-NKKYTCBH.js";
|
|
37
38
|
import {
|
|
@@ -63,7 +64,7 @@ describe("StepSettings component", () => {
|
|
|
63
64
|
let cleanup;
|
|
64
65
|
beforeEach(async () => {
|
|
65
66
|
vi.resetAllMocks();
|
|
66
|
-
const { getSourceSummary } = await import("../../source-manager-
|
|
67
|
+
const { getSourceSummary } = await import("../../source-manager-QCIO4XZK.js");
|
|
67
68
|
vi.mocked(getSourceSummary).mockResolvedValue({
|
|
68
69
|
sources: [
|
|
69
70
|
{ name: "public", url: "github:agents-inc/skills", enabled: true },
|
|
@@ -224,7 +225,7 @@ describe("StepSettings component", () => {
|
|
|
224
225
|
});
|
|
225
226
|
describe("edge cases", () => {
|
|
226
227
|
it("should handle empty sources list gracefully", async () => {
|
|
227
|
-
const { getSourceSummary } = await import("../../source-manager-
|
|
228
|
+
const { getSourceSummary } = await import("../../source-manager-QCIO4XZK.js");
|
|
228
229
|
vi.mocked(getSourceSummary).mockResolvedValue({
|
|
229
230
|
sources: [{ name: "public", url: "github:agents-inc/skills", enabled: true }],
|
|
230
231
|
localSkillCount: 0,
|
|
@@ -238,7 +239,7 @@ describe("StepSettings component", () => {
|
|
|
238
239
|
globalExpect(output).toContain("0");
|
|
239
240
|
});
|
|
240
241
|
it("should handle getSourceSummary failure gracefully", async () => {
|
|
241
|
-
const { getSourceSummary } = await import("../../source-manager-
|
|
242
|
+
const { getSourceSummary } = await import("../../source-manager-QCIO4XZK.js");
|
|
242
243
|
vi.mocked(getSourceSummary).mockRejectedValue(new Error("Config read failed"));
|
|
243
244
|
const { lastFrame, unmount } = renderStepSettings();
|
|
244
245
|
cleanup = unmount;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/cli/components/wizard/step-settings.test.tsx"],"sourcesContent":["import { render } from \"ink-testing-library\";\nimport { describe, expect, it, afterEach, beforeEach, vi } from \"vitest\";\nimport { StepSettings, type StepSettingsProps } from \"./step-settings\";\nimport {\n ESCAPE,\n ARROW_UP,\n ARROW_DOWN,\n INPUT_DELAY_MS,\n delay,\n} from \"../../lib/__tests__/test-constants\";\n\n// Mock source-manager\nvi.mock(\"../../lib/configuration/source-manager.js\", async (importOriginal) => ({\n ...(await importOriginal<typeof import(\"../../lib/configuration/source-manager.js\")>()),\n getSourceSummary: vi.fn(),\n addSource: vi.fn(),\n removeSource: vi.fn(),\n}));\n\n// Mock config\nvi.mock(\"../../lib/configuration/config.js\", async (importOriginal) => ({\n ...(await importOriginal<typeof import(\"../../lib/configuration/config.js\")>()),\n DEFAULT_SOURCE: \"github:agents-inc/skills\",\n}));\n\nconst LOADING_SETTLE_MS = 200;\n\nconst defaultProps: StepSettingsProps = {\n projectDir: \"/test/project\",\n onClose: vi.fn(),\n};\n\nconst renderStepSettings = (props: Partial<StepSettingsProps> = {}) => {\n return render(<StepSettings {...defaultProps} {...props} />);\n};\n\ndescribe(\"StepSettings component\", () => {\n let cleanup: (() => void) | undefined;\n\n beforeEach(async () => {\n vi.resetAllMocks();\n\n const { getSourceSummary } = await import(\"../../lib/configuration/source-manager.js\");\n vi.mocked(getSourceSummary).mockResolvedValue({\n sources: [\n { name: \"public\", url: \"github:agents-inc/skills\", enabled: true },\n { name: \"acme-corp\", url: \"github:acme-corp/claude-skills\", enabled: true },\n ],\n localSkillCount: 3,\n pluginSkillCount: 1,\n });\n });\n\n afterEach(() => {\n cleanup?.();\n cleanup = undefined;\n });\n\n describe(\"rendering\", () => {\n it(\"should render the title\", async () => {\n const { lastFrame, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n const output = lastFrame();\n expect(output).toContain(\"Skill Sources\");\n });\n\n it(\"should render configured sources\", async () => {\n const { lastFrame, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n const output = lastFrame();\n expect(output).toContain(\"Public\");\n expect(output).toContain(\"acme-corp\");\n });\n\n it(\"should show default label for public source\", async () => {\n const { lastFrame, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n const output = lastFrame();\n expect(output).toContain(\"(default)\");\n });\n\n it(\"should show source URLs\", async () => {\n const { lastFrame, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n const output = lastFrame();\n expect(output).toContain(\"github:agents-inc/skills\");\n expect(output).toContain(\"github:acme-corp/claude-skills\");\n });\n\n it(\"should show local skill count\", async () => {\n const { lastFrame, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n const output = lastFrame();\n expect(output).toContain(\"3\");\n expect(output).toContain(\".claude/skills/\");\n });\n\n it(\"should show plugin count\", async () => {\n const { lastFrame, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n const output = lastFrame();\n expect(output).toContain(\"1\");\n expect(output).toContain(\"installed plugins\");\n });\n\n it(\"should show add source input area\", async () => {\n const { lastFrame, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n const output = lastFrame();\n expect(output).toContain(\"Add source\");\n });\n\n it(\"should show loading state initially\", () => {\n const { lastFrame, unmount } = renderStepSettings();\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Loading sources...\");\n });\n });\n\n describe(\"keyboard navigation\", () => {\n it(\"should navigate down with arrow down\", async () => {\n const { lastFrame, stdin, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n\n // Move focus down\n stdin.write(ARROW_DOWN);\n await delay(INPUT_DELAY_MS);\n\n const output = lastFrame();\n // The second source (acme-corp) should now be focused\n expect(output).toContain(\"acme-corp\");\n });\n\n it(\"should navigate up with arrow up\", async () => {\n const { lastFrame, stdin, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n\n // Move down then up\n stdin.write(ARROW_DOWN);\n await delay(INPUT_DELAY_MS);\n stdin.write(ARROW_UP);\n await delay(INPUT_DELAY_MS);\n\n const output = lastFrame();\n expect(output).toContain(\"Public\");\n });\n\n it(\"should not navigate above first item\", async () => {\n const { lastFrame, stdin, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n\n // Try to move up from first item\n stdin.write(ARROW_UP);\n await delay(INPUT_DELAY_MS);\n\n const output = lastFrame();\n expect(output).toContain(\"Public\");\n });\n });\n\n describe(\"escape to close\", () => {\n it(\"should call onClose when Escape is pressed\", async () => {\n const onClose = vi.fn();\n const { stdin, unmount } = renderStepSettings({ onClose });\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n stdin.write(ESCAPE);\n await delay(INPUT_DELAY_MS);\n\n expect(onClose).toHaveBeenCalledTimes(1);\n });\n });\n\n describe(\"add source input mode\", () => {\n it(\"should enter add source mode on 'a' key\", async () => {\n const { lastFrame, stdin, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n\n stdin.write(\"a\");\n await delay(INPUT_DELAY_MS);\n\n const output = lastFrame();\n // Should show cursor block character indicating input mode\n expect(output).toContain(\"\\u2588\");\n });\n\n it(\"should exit add source mode on Escape\", async () => {\n const onClose = vi.fn();\n const { lastFrame, stdin, unmount } = renderStepSettings({ onClose });\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n\n // Enter add mode\n stdin.write(\"a\");\n await delay(INPUT_DELAY_MS);\n\n // Escape from add mode (should NOT close settings)\n stdin.write(ESCAPE);\n await delay(INPUT_DELAY_MS);\n\n expect(onClose).not.toHaveBeenCalled();\n\n const output = lastFrame();\n // Should still show the settings view\n expect(output).toContain(\"Skill Sources\");\n });\n\n it(\"should show hint text for add mode\", async () => {\n const { lastFrame, stdin, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n\n stdin.write(\"a\");\n await delay(INPUT_DELAY_MS);\n\n const output = lastFrame();\n expect(output).toContain(\"ENTER submit\");\n expect(output).toContain(\"ESC cancel\");\n });\n\n it(\"should show hint text for normal mode\", async () => {\n const { lastFrame, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n\n const output = lastFrame();\n expect(output).toContain(\"DEL remove\");\n expect(output).toContain(\"close\");\n });\n });\n\n describe(\"edge cases\", () => {\n it(\"should handle empty sources list gracefully\", async () => {\n const { getSourceSummary } = await import(\"../../lib/configuration/source-manager.js\");\n vi.mocked(getSourceSummary).mockResolvedValue({\n sources: [{ name: \"public\", url: \"github:agents-inc/skills\", enabled: true }],\n localSkillCount: 0,\n pluginSkillCount: 0,\n });\n\n const { lastFrame, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n\n const output = lastFrame();\n expect(output).toContain(\"Public\");\n expect(output).toContain(\"0\");\n });\n\n it(\"should handle getSourceSummary failure gracefully\", async () => {\n const { getSourceSummary } = await import(\"../../lib/configuration/source-manager.js\");\n vi.mocked(getSourceSummary).mockRejectedValue(new Error(\"Config read failed\"));\n\n const { lastFrame, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n\n const output = lastFrame();\n // Should show fallback with default source\n expect(output).toContain(\"Public\");\n });\n });\n});\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/cli/components/wizard/step-settings.test.tsx"],"sourcesContent":["import { render } from \"ink-testing-library\";\nimport { describe, expect, it, afterEach, beforeEach, vi } from \"vitest\";\nimport { StepSettings, type StepSettingsProps } from \"./step-settings\";\nimport {\n ESCAPE,\n ARROW_UP,\n ARROW_DOWN,\n INPUT_DELAY_MS,\n delay,\n} from \"../../lib/__tests__/test-constants\";\n\n// Mock source-manager\nvi.mock(\"../../lib/configuration/source-manager.js\", async (importOriginal) => ({\n ...(await importOriginal<typeof import(\"../../lib/configuration/source-manager.js\")>()),\n getSourceSummary: vi.fn(),\n addSource: vi.fn(),\n removeSource: vi.fn(),\n}));\n\n// Mock config\nvi.mock(\"../../lib/configuration/config.js\", async (importOriginal) => ({\n ...(await importOriginal<typeof import(\"../../lib/configuration/config.js\")>()),\n DEFAULT_SOURCE: \"github:agents-inc/skills\",\n}));\n\nconst LOADING_SETTLE_MS = 200;\n\nconst defaultProps: StepSettingsProps = {\n projectDir: \"/test/project\",\n onClose: vi.fn(),\n};\n\nconst renderStepSettings = (props: Partial<StepSettingsProps> = {}) => {\n return render(<StepSettings {...defaultProps} {...props} />);\n};\n\ndescribe(\"StepSettings component\", () => {\n let cleanup: (() => void) | undefined;\n\n beforeEach(async () => {\n vi.resetAllMocks();\n\n const { getSourceSummary } = await import(\"../../lib/configuration/source-manager.js\");\n vi.mocked(getSourceSummary).mockResolvedValue({\n sources: [\n { name: \"public\", url: \"github:agents-inc/skills\", enabled: true },\n { name: \"acme-corp\", url: \"github:acme-corp/claude-skills\", enabled: true },\n ],\n localSkillCount: 3,\n pluginSkillCount: 1,\n });\n });\n\n afterEach(() => {\n cleanup?.();\n cleanup = undefined;\n });\n\n describe(\"rendering\", () => {\n it(\"should render the title\", async () => {\n const { lastFrame, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n const output = lastFrame();\n expect(output).toContain(\"Skill Sources\");\n });\n\n it(\"should render configured sources\", async () => {\n const { lastFrame, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n const output = lastFrame();\n expect(output).toContain(\"Public\");\n expect(output).toContain(\"acme-corp\");\n });\n\n it(\"should show default label for public source\", async () => {\n const { lastFrame, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n const output = lastFrame();\n expect(output).toContain(\"(default)\");\n });\n\n it(\"should show source URLs\", async () => {\n const { lastFrame, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n const output = lastFrame();\n expect(output).toContain(\"github:agents-inc/skills\");\n expect(output).toContain(\"github:acme-corp/claude-skills\");\n });\n\n it(\"should show local skill count\", async () => {\n const { lastFrame, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n const output = lastFrame();\n expect(output).toContain(\"3\");\n expect(output).toContain(\".claude/skills/\");\n });\n\n it(\"should show plugin count\", async () => {\n const { lastFrame, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n const output = lastFrame();\n expect(output).toContain(\"1\");\n expect(output).toContain(\"installed plugins\");\n });\n\n it(\"should show add source input area\", async () => {\n const { lastFrame, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n const output = lastFrame();\n expect(output).toContain(\"Add source\");\n });\n\n it(\"should show loading state initially\", () => {\n const { lastFrame, unmount } = renderStepSettings();\n cleanup = unmount;\n\n const output = lastFrame();\n expect(output).toContain(\"Loading sources...\");\n });\n });\n\n describe(\"keyboard navigation\", () => {\n it(\"should navigate down with arrow down\", async () => {\n const { lastFrame, stdin, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n\n // Move focus down\n stdin.write(ARROW_DOWN);\n await delay(INPUT_DELAY_MS);\n\n const output = lastFrame();\n // The second source (acme-corp) should now be focused\n expect(output).toContain(\"acme-corp\");\n });\n\n it(\"should navigate up with arrow up\", async () => {\n const { lastFrame, stdin, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n\n // Move down then up\n stdin.write(ARROW_DOWN);\n await delay(INPUT_DELAY_MS);\n stdin.write(ARROW_UP);\n await delay(INPUT_DELAY_MS);\n\n const output = lastFrame();\n expect(output).toContain(\"Public\");\n });\n\n it(\"should not navigate above first item\", async () => {\n const { lastFrame, stdin, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n\n // Try to move up from first item\n stdin.write(ARROW_UP);\n await delay(INPUT_DELAY_MS);\n\n const output = lastFrame();\n expect(output).toContain(\"Public\");\n });\n });\n\n describe(\"escape to close\", () => {\n it(\"should call onClose when Escape is pressed\", async () => {\n const onClose = vi.fn();\n const { stdin, unmount } = renderStepSettings({ onClose });\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n stdin.write(ESCAPE);\n await delay(INPUT_DELAY_MS);\n\n expect(onClose).toHaveBeenCalledTimes(1);\n });\n });\n\n describe(\"add source input mode\", () => {\n it(\"should enter add source mode on 'a' key\", async () => {\n const { lastFrame, stdin, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n\n stdin.write(\"a\");\n await delay(INPUT_DELAY_MS);\n\n const output = lastFrame();\n // Should show cursor block character indicating input mode\n expect(output).toContain(\"\\u2588\");\n });\n\n it(\"should exit add source mode on Escape\", async () => {\n const onClose = vi.fn();\n const { lastFrame, stdin, unmount } = renderStepSettings({ onClose });\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n\n // Enter add mode\n stdin.write(\"a\");\n await delay(INPUT_DELAY_MS);\n\n // Escape from add mode (should NOT close settings)\n stdin.write(ESCAPE);\n await delay(INPUT_DELAY_MS);\n\n expect(onClose).not.toHaveBeenCalled();\n\n const output = lastFrame();\n // Should still show the settings view\n expect(output).toContain(\"Skill Sources\");\n });\n\n it(\"should show hint text for add mode\", async () => {\n const { lastFrame, stdin, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n\n stdin.write(\"a\");\n await delay(INPUT_DELAY_MS);\n\n const output = lastFrame();\n expect(output).toContain(\"ENTER submit\");\n expect(output).toContain(\"ESC cancel\");\n });\n\n it(\"should show hint text for normal mode\", async () => {\n const { lastFrame, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n\n const output = lastFrame();\n expect(output).toContain(\"DEL remove\");\n expect(output).toContain(\"close\");\n });\n });\n\n describe(\"edge cases\", () => {\n it(\"should handle empty sources list gracefully\", async () => {\n const { getSourceSummary } = await import(\"../../lib/configuration/source-manager.js\");\n vi.mocked(getSourceSummary).mockResolvedValue({\n sources: [{ name: \"public\", url: \"github:agents-inc/skills\", enabled: true }],\n localSkillCount: 0,\n pluginSkillCount: 0,\n });\n\n const { lastFrame, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n\n const output = lastFrame();\n expect(output).toContain(\"Public\");\n expect(output).toContain(\"0\");\n });\n\n it(\"should handle getSourceSummary failure gracefully\", async () => {\n const { getSourceSummary } = await import(\"../../lib/configuration/source-manager.js\");\n vi.mocked(getSourceSummary).mockRejectedValue(new Error(\"Config read failed\"));\n\n const { lastFrame, unmount } = renderStepSettings();\n cleanup = unmount;\n\n await delay(LOADING_SETTLE_MS);\n\n const output = lastFrame();\n // Should show fallback with default source\n expect(output).toContain(\"Public\");\n });\n });\n});\n"],"mappings":"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","names":[]}
|
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
StepSources
|
|
4
|
-
} from "../../chunk-
|
|
4
|
+
} from "../../chunk-3K6FSET7.js";
|
|
5
5
|
import "../../chunk-HGTC76BX.js";
|
|
6
|
-
import "../../chunk-6YMW4HMX.js";
|
|
7
|
-
import "../../chunk-7SOPVGDV.js";
|
|
8
6
|
import "../../chunk-K77I4XGL.js";
|
|
9
|
-
import "../../chunk-2MHSOPIU.js";
|
|
10
7
|
import "../../chunk-MWGDG4QN.js";
|
|
11
|
-
import "../../chunk-
|
|
12
|
-
import "../../chunk-
|
|
8
|
+
import "../../chunk-DNPJ5GUK.js";
|
|
9
|
+
import "../../chunk-7SOPVGDV.js";
|
|
10
|
+
import "../../chunk-2MHSOPIU.js";
|
|
13
11
|
import "../../chunk-GG4BSB6S.js";
|
|
14
12
|
import "../../chunk-AQYAVLZK.js";
|
|
15
13
|
import "../../chunk-AUNBGZS4.js";
|
|
16
|
-
import "../../chunk-
|
|
14
|
+
import "../../chunk-WF5PMBIR.js";
|
|
15
|
+
import "../../chunk-KUV24B5M.js";
|
|
16
|
+
import "../../chunk-OLWGGD4G.js";
|
|
17
17
|
import "../../chunk-6VIOO74O.js";
|
|
18
|
-
import "../../chunk-
|
|
19
|
-
import "../../chunk-
|
|
20
|
-
import "../../chunk-
|
|
21
|
-
import "../../chunk-
|
|
22
|
-
import "../../chunk-
|
|
18
|
+
import "../../chunk-3VNQPCOE.js";
|
|
19
|
+
import "../../chunk-ZBLSWJFM.js";
|
|
20
|
+
import "../../chunk-EMX7PA2I.js";
|
|
21
|
+
import "../../chunk-E74Q7GUE.js";
|
|
22
|
+
import "../../chunk-WJL4KU5V.js";
|
|
23
|
+
import "../../chunk-SRIH4U5Y.js";
|
|
23
24
|
import "../../chunk-EGMQ3SXN.js";
|
|
24
25
|
import "../../chunk-NKKYTCBH.js";
|
|
25
26
|
import "../../chunk-DHET7RCE.js";
|
|
@@ -13,9 +13,9 @@ import {
|
|
|
13
13
|
} from "../../chunk-66UDJBF6.js";
|
|
14
14
|
import {
|
|
15
15
|
WEB_PAIR_MATRIX
|
|
16
|
-
} from "../../chunk-
|
|
17
|
-
import "../../chunk-
|
|
18
|
-
import "../../chunk-
|
|
16
|
+
} from "../../chunk-GDUOOT3J.js";
|
|
17
|
+
import "../../chunk-TNSVPZHP.js";
|
|
18
|
+
import "../../chunk-V5HR77EY.js";
|
|
19
19
|
import {
|
|
20
20
|
afterEach,
|
|
21
21
|
beforeEach,
|
|
@@ -26,29 +26,30 @@ import {
|
|
|
26
26
|
} from "../../chunk-XY3XDVMI.js";
|
|
27
27
|
import {
|
|
28
28
|
StepSources
|
|
29
|
-
} from "../../chunk-
|
|
29
|
+
} from "../../chunk-3K6FSET7.js";
|
|
30
30
|
import "../../chunk-HGTC76BX.js";
|
|
31
|
-
import "../../chunk-6YMW4HMX.js";
|
|
32
|
-
import "../../chunk-7SOPVGDV.js";
|
|
33
31
|
import "../../chunk-K77I4XGL.js";
|
|
34
|
-
import "../../chunk-2MHSOPIU.js";
|
|
35
32
|
import "../../chunk-MWGDG4QN.js";
|
|
36
|
-
import "../../chunk-
|
|
37
|
-
import "../../chunk-
|
|
33
|
+
import "../../chunk-DNPJ5GUK.js";
|
|
34
|
+
import "../../chunk-7SOPVGDV.js";
|
|
35
|
+
import "../../chunk-2MHSOPIU.js";
|
|
38
36
|
import "../../chunk-GG4BSB6S.js";
|
|
39
37
|
import "../../chunk-AQYAVLZK.js";
|
|
40
38
|
import "../../chunk-AUNBGZS4.js";
|
|
39
|
+
import "../../chunk-WF5PMBIR.js";
|
|
40
|
+
import "../../chunk-KUV24B5M.js";
|
|
41
41
|
import {
|
|
42
42
|
useWizardStore
|
|
43
|
-
} from "../../chunk-
|
|
43
|
+
} from "../../chunk-OLWGGD4G.js";
|
|
44
44
|
import "../../chunk-6VIOO74O.js";
|
|
45
|
-
import "../../chunk-
|
|
46
|
-
import "../../chunk-
|
|
47
|
-
import "../../chunk-
|
|
45
|
+
import "../../chunk-3VNQPCOE.js";
|
|
46
|
+
import "../../chunk-ZBLSWJFM.js";
|
|
47
|
+
import "../../chunk-EMX7PA2I.js";
|
|
48
48
|
import {
|
|
49
|
-
|
|
50
|
-
} from "../../chunk-
|
|
51
|
-
import "../../chunk-
|
|
49
|
+
initializeMatrix
|
|
50
|
+
} from "../../chunk-E74Q7GUE.js";
|
|
51
|
+
import "../../chunk-WJL4KU5V.js";
|
|
52
|
+
import "../../chunk-SRIH4U5Y.js";
|
|
52
53
|
import {
|
|
53
54
|
DEFAULT_BRANDING,
|
|
54
55
|
UI_SYMBOLS
|
|
@@ -72,7 +73,7 @@ var renderStepSources = (props = {}) => {
|
|
|
72
73
|
describe("StepSources component", () => {
|
|
73
74
|
let cleanup;
|
|
74
75
|
beforeEach(() => {
|
|
75
|
-
|
|
76
|
+
initializeMatrix(mockMatrix);
|
|
76
77
|
useWizardStore.setState({
|
|
77
78
|
domainSelections: {
|
|
78
79
|
web: {
|