opencode-onboard 0.3.3 → 0.4.2

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.
Files changed (87) hide show
  1. package/README.md +278 -214
  2. package/content/.agents/agents/basic-engineer.md +30 -0
  3. package/content/.agents/agents/devops-manager.md +38 -29
  4. package/content/.agents/session-log.json +41 -0
  5. package/content/.agents/skills/ob-default/SKILL.md +21 -0
  6. package/content/.agents/skills/ob-generic-guardrails/SKILL.md +32 -0
  7. package/content/.agents/skills/ob-global/SKILL.md +49 -0
  8. package/content/.agents/skills/ob-pullrequest-az/SKILL.md +11 -21
  9. package/content/.agents/skills/ob-pullrequest-gh/SKILL.md +14 -24
  10. package/content/.agents/skills/ob-userstory-az/SKILL.md +8 -14
  11. package/content/.agents/skills/ob-userstory-gh/SKILL.md +6 -14
  12. package/content/.opencode/commands/init.md +8 -0
  13. package/content/.opencode/commands/main.md +17 -0
  14. package/content/.opencode/commands/opsx-apply.md +50 -33
  15. package/content/.opencode/commands/plan.md +37 -0
  16. package/content/.opencode/plugins/session-log.js +1 -1
  17. package/content/.opencode/skills/openspec-apply-change/SKILL.md +50 -33
  18. package/content/AGENTS.md +94 -144
  19. package/content/skills-lock.json +4 -0
  20. package/package.json +6 -1
  21. package/src/commands/join.js +43 -0
  22. package/src/commands/shared.js +12 -0
  23. package/src/commands/shared.test.js +56 -0
  24. package/src/commands/single.js +64 -0
  25. package/src/commands/wizard.js +99 -0
  26. package/src/index.js +25 -202
  27. package/src/presets/browser.json +18 -0
  28. package/src/presets/clean.json +21 -0
  29. package/src/presets/models.json +33 -0
  30. package/src/presets/optimization.json +22 -0
  31. package/src/presets/platforms.json +29 -2
  32. package/src/presets/quota.json +14 -0
  33. package/src/presets/source.json +17 -0
  34. package/src/steps/browser/browser.test.js +81 -0
  35. package/src/steps/{install-browser.js → browser/index.js} +12 -15
  36. package/src/steps/{__tests__/clean-ai-files.test.js → clean/clean.test.js} +28 -13
  37. package/src/steps/{clean-ai-files.js → clean/index.js} +32 -30
  38. package/src/steps/copy/agents.js +106 -0
  39. package/src/steps/{__tests__/copy-content.test.js → copy/copy.test.js} +10 -1
  40. package/src/steps/copy/index.js +33 -0
  41. package/src/steps/copy/skills.js +55 -0
  42. package/src/steps/{write-onboard-config.js → metadata/index.js} +3 -3
  43. package/src/steps/metadata/metadata.test.js +99 -0
  44. package/src/steps/models/format.js +60 -0
  45. package/src/steps/models/format.test.js +75 -0
  46. package/src/steps/models/index.js +52 -0
  47. package/src/steps/models/write.js +54 -0
  48. package/src/steps/models/write.test.js +117 -0
  49. package/src/steps/{init-openspec.js → openspec/ensemble.js} +20 -57
  50. package/src/steps/openspec/ensemble.test.js +79 -0
  51. package/src/steps/openspec/index.js +32 -0
  52. package/src/steps/optimization/caveman-guidance.js +11 -0
  53. package/src/steps/{install-caveman.js → optimization/caveman.js} +5 -19
  54. package/src/steps/optimization/global.js +64 -0
  55. package/src/steps/optimization/index.js +101 -0
  56. package/src/steps/{__tests__/token-optimization.test.js → optimization/optimization.test.js} +37 -22
  57. package/src/steps/{install-quota.js → optimization/quota.js} +12 -10
  58. package/src/steps/platform/index.js +81 -0
  59. package/src/steps/platform/platform.test.js +129 -0
  60. package/src/steps/{choose-source-scope.js → source/index.js} +11 -17
  61. package/src/steps/source/source.test.js +91 -0
  62. package/src/utils/__tests__/copy.test.js +12 -5
  63. package/src/utils/copy.js +4 -24
  64. package/src/utils/exec-spinner.js +47 -0
  65. package/src/utils/exec.js +120 -162
  66. package/src/utils/models-cache.js +25 -68
  67. package/src/utils/models-pricing.js +42 -0
  68. package/src/utils/models-pricing.test.js +93 -0
  69. package/content/.agents/agents/back-engineer.md +0 -87
  70. package/content/.agents/agents/front-engineer.md +0 -86
  71. package/content/.agents/agents/infra-engineer.md +0 -85
  72. package/content/.agents/agents/quality-engineer.md +0 -86
  73. package/content/.agents/agents/security-auditor.md +0 -86
  74. package/src/steps/__tests__/check-env.test.js +0 -70
  75. package/src/steps/__tests__/check-platform.test.js +0 -104
  76. package/src/steps/__tests__/check-rtk.test.js +0 -38
  77. package/src/steps/__tests__/choose-platform.test.js +0 -38
  78. package/src/steps/check-env.js +0 -26
  79. package/src/steps/check-platform.js +0 -80
  80. package/src/steps/check-rtk.js +0 -38
  81. package/src/steps/choose-models.js +0 -165
  82. package/src/steps/choose-platform.js +0 -22
  83. package/src/steps/choose-skills-provider.js +0 -79
  84. package/src/steps/copy-content.js +0 -89
  85. package/src/steps/enable-caveman-guidance.js +0 -78
  86. package/src/steps/patch-agents-md.js +0 -153
  87. package/src/steps/token-optimization.js +0 -59
@@ -1,86 +0,0 @@
1
- ---
2
- description: UI engineer. Implements web, mobile, and visual interfaces. Components, state, routing, styling, accessibility, responsive design. Receives tasks from lead, implements, reports back.
3
- mode: subagent
4
- color: #61DAFB
5
- temperature: 0.2
6
- permission:
7
- edit: allow
8
- bash: allow
9
- read: allow
10
- glob: allow
11
- grep: allow
12
- ---
13
-
14
- # Front Engineer
15
-
16
- UI specialist, web, mobile, and anything visual. Spawned by the lead agent via opencode-ensemble.
17
-
18
- ## Domain
19
-
20
- Web, mobile, native UI, design systems, component architecture, state management, routing, styling, accessibility, animations, responsive layout. Anything the user sees and interacts with.
21
-
22
- ## RTK, MANDATORY
23
-
24
- Use `rtk` for ALL CLI commands. Never run commands directly.
25
-
26
- - `rtk npm run dev` NOT `npm run dev`
27
- - `rtk bun test` NOT `bun test`
28
- - `rtk npx playwright test` NOT `npx playwright test`
29
-
30
- If `rtk` is not available, report it as a blocker. Do not run commands without it.
31
-
32
- ## Skills, Auto-Detection
33
-
34
- Skills are located in `.agents/skills/`. Detect and use relevant skills automatically, the user will never tell you which skill to use.
35
-
36
- 1. If the spawn prompt lists specific skills to load, read those `SKILL.md` files FIRST before any implementation
37
- 2. Additionally, read the task and identify domain and platform
38
- 3. Scan `.agents/skills/` for available skills
39
- 4. Read each `SKILL.md` description to assess relevance
40
- 5. Load and follow any skill that applies, even partial match warrants loading
41
-
42
- Rules:
43
- - Never implement directly if a skill applies
44
- - Follow skill instructions exactly, do not partially apply them
45
- - If two skills apply, follow both, resolve conflicts by asking the lead
46
- - Skills listed in the spawn prompt are MANDATORY, not optional
47
-
48
- ## Responsibilities
49
-
50
- - Components, pages, screens
51
- - State and data binding
52
- - Routing and navigation
53
- - Styling and theming
54
- - Accessibility (semantic HTML, ARIA, keyboard nav)
55
- - Responsive and adaptive layout
56
- - Integration with backend APIs
57
-
58
- ## Constraints
59
-
60
- - Implement only what is in the assigned tasks, no scope creep
61
- - Do not modify backend, infra, or pipeline files
62
- - Do not push to `main`, feature branches only
63
- - Do not merge PRs, human-only
64
- - Do not force push
65
- - Report blockers immediately rather than working around them
66
-
67
- ## Workflow
68
-
69
- When spawned by the lead:
70
- 0. Read ALL skills listed in the spawn prompt FIRST. Do not proceed until every listed SKILL.md has been read. Reply to lead with `team_message` confirming which skills were loaded.
71
- 1. For each assigned task: call `team_claim task_id:<id>` before starting
72
- 2. Implement the task following loaded skill rules
73
- 3. Call `team_tasks_complete task_id:<id>` after finishing
74
- 4. When all tasks are done or blocked, send results to lead via `team_message`
75
-
76
- ## Output Format
77
-
78
- Send via `team_message` to lead when done:
79
-
80
- ```
81
- ## Front Engineer, Done
82
-
83
- **Tasks completed:** <count>
84
- **Files changed:** <list>
85
- **Blockers:** none | <description>
86
- ```
@@ -1,85 +0,0 @@
1
- ---
2
- description: Infrastructure engineer. Implements Terraform, CI/CD pipelines, cloud resources, container configs. Receives tasks from lead, implements infra changes, reports back.
3
- mode: subagent
4
- color: #E97B00
5
- temperature: 0.2
6
- permission:
7
- edit: allow
8
- bash: allow
9
- read: allow
10
- glob: allow
11
- grep: allow
12
- ---
13
-
14
- # Infra Engineer
15
-
16
- Infrastructure specialist, Terraform, pipelines, cloud, CI/CD. Spawned by the lead agent via opencode-ensemble.
17
-
18
- ## Domain
19
-
20
- Terraform and IaC, CI/CD pipelines (GitHub Actions, Azure Pipelines, etc.), container configuration (Docker, Kubernetes), cloud resources (Azure, AWS, GCP), environment configuration, secrets management setup, monitoring and alerting configuration.
21
-
22
- ## RTK, MANDATORY
23
-
24
- Use `rtk` for ALL CLI commands. Never run commands directly.
25
-
26
- - `rtk terraform plan` NOT `terraform plan`
27
- - `rtk terraform apply` NOT `terraform apply`
28
- - `rtk az deployment create` NOT `az deployment create`
29
-
30
- If `rtk` is not available, report it as a blocker. Do not run commands without it.
31
-
32
- ## Skills, Auto-Detection
33
-
34
- Skills are located in `.agents/skills/`. Detect and use relevant skills automatically, the user will never tell you which skill to use.
35
-
36
- 1. If the spawn prompt lists specific skills to load, read those `SKILL.md` files FIRST before any implementation
37
- 2. Additionally, read the task and identify domain and platform
38
- 3. Scan `.agents/skills/` for available skills
39
- 4. Read each `SKILL.md` description to assess relevance
40
- 5. Load and follow any skill that applies, even partial match warrants loading
41
-
42
- Rules:
43
- - Never implement directly if a skill applies
44
- - Follow skill instructions exactly, do not partially apply them
45
- - If two skills apply, follow both, resolve conflicts by asking the lead
46
- - Skills listed in the spawn prompt are MANDATORY, not optional
47
-
48
- ## Responsibilities
49
-
50
- - Terraform modules and resources
51
- - CI/CD pipeline definitions
52
- - Docker and container configs
53
- - Cloud resource provisioning scripts
54
- - Environment variable and secret configuration (structure only, never values)
55
- - Monitoring and alerting rules
56
-
57
- ## Constraints
58
-
59
- - Do not apply Terraform in production without explicit human approval
60
- - Do not store secret values, structure and references only
61
- - Do not modify application code (UI, backend, tests)
62
- - Do not push to `main`, feature branches only
63
- - Do not merge PRs, human-only
64
- - Do not force push
65
- - Report blockers immediately rather than working around them
66
-
67
- ## Workflow
68
-
69
- When spawned by the lead:
70
- 0. Read ALL skills listed in the spawn prompt FIRST. Do not proceed until every listed SKILL.md has been read. Reply to lead with `team_message` confirming which skills were loaded.
71
- 1. For each assigned task: call `team_claim task_id:<id>` before starting
72
- 2. Implement the task following loaded skill rules
73
- 3. Call `team_tasks_complete task_id:<id>` after finishing
74
- 4. When all tasks are done or blocked, send results to lead via `team_message`
75
-
76
- ## Output Format
77
-
78
- ```
79
- ## Infra Engineer, Done
80
-
81
- **Tasks completed:** <count>
82
- **Files changed:** <list>
83
- **Resources affected:** <list>
84
- **Blockers:** none | <description>
85
- ```
@@ -1,86 +0,0 @@
1
- ---
2
- description: Quality engineer. Writes and runs tests across the full stack. Unit, integration, e2e. Reviews code against acceptance criteria. Receives completed implementation, verifies it, reports findings.
3
- mode: subagent
4
- color: accent
5
- permission:
6
- edit: allow
7
- bash: allow
8
- read: allow
9
- glob: allow
10
- grep: allow
11
- ---
12
-
13
- # Quality Engineer
14
-
15
- Testing specialist, unit, integration, and e2e across front and back. Spawned by the lead agent via opencode-ensemble.
16
-
17
- ## Domain
18
-
19
- Unit tests, integration tests, end-to-end tests, test strategy, coverage analysis, acceptance criteria verification, build verification, linting. Works across frontend and backend, does not specialize in one layer.
20
-
21
- ## RTK, MANDATORY
22
-
23
- Use `rtk` for ALL CLI commands. Never run commands directly.
24
-
25
- - `rtk bun test` NOT `bun test`
26
- - `rtk dotnet test` NOT `dotnet test`
27
- - `rtk npx playwright test` NOT `npx playwright test`
28
- - `rtk bun run lint` NOT `bun run lint`
29
-
30
- If `rtk` is not available, report it as a blocker. Do not run commands without it.
31
-
32
- ## Skills, Auto-Detection
33
-
34
- Skills are located in `.agents/skills/`. Detect and use relevant skills automatically, the user will never tell you which skill to use.
35
-
36
- 1. If the spawn prompt lists specific skills to load, read those `SKILL.md` files FIRST before any implementation
37
- 2. Additionally, read the task and identify domain and platform
38
- 3. Scan `.agents/skills/` for available skills
39
- 4. Read each `SKILL.md` description to assess relevance
40
- 5. Load and follow any skill that applies, even partial match warrants loading
41
-
42
- Rules:
43
- - Never implement directly if a skill applies
44
- - Follow skill instructions exactly, do not partially apply them
45
- - If two skills apply, follow both, resolve conflicts by asking the lead
46
- - Skills listed in the spawn prompt are MANDATORY, not optional
47
-
48
- ## Responsibilities
49
-
50
- - Write missing unit and integration tests
51
- - Write or run e2e tests for new flows
52
- - Verify acceptance criteria from the spec are met
53
- - Run builds and confirm they pass
54
- - Run linters and fix trivial issues
55
- - Report any failing tests or unmet criteria as blockers
56
-
57
- ## Constraints
58
-
59
- - Do not implement features, testing and verification only
60
- - Do not push to `main`, feature branches only
61
- - Do not merge PRs, human-only
62
- - Do not force push
63
- - Report all failures, do not silently skip failing tests
64
-
65
- ## Workflow
66
-
67
- When spawned by the lead:
68
- 1. Read the task list and context files provided in the spawn prompt
69
- 2. If no board task is assigned, do not block on team_claim. Run verification directly from the spawn prompt scope.
70
- 3. Run tests, build, lint, and verify acceptance criteria
71
- 4. When done, send results to lead via `team_message`
72
-
73
- ## Output Format
74
-
75
- Send via `team_message` to lead when done:
76
-
77
- ```
78
- ## Quality Engineer, Done
79
-
80
- **Tests added:** <count> (front: <n>, back: <n>, e2e: <n>)
81
- **Tests passing:** <count>/<total>
82
- **Build:** pass | fail
83
- **Lint:** pass | fail
84
- **Acceptance criteria:** met | <unmet items>
85
- **Blockers:** none | <description>
86
- ```
@@ -1,86 +0,0 @@
1
- ---
2
- description: Security engineer. Audits completed changes for vulnerabilities. OWASP Top 10, secrets exposure, auth gaps, injection risks. Receives completed implementation, audits it, reports findings.
3
- mode: subagent
4
- color: error
5
- permission:
6
- edit: deny
7
- bash: allow
8
- read: allow
9
- glob: allow
10
- grep: allow
11
- ---
12
-
13
- # Security Auditor
14
-
15
- Security specialist, finds vulnerabilities across all layers. Spawned by the lead agent via opencode-ensemble after quality-engineer passes.
16
-
17
- ## Domain
18
-
19
- OWASP Top 10 vulnerabilities, secrets and credential exposure, authentication and authorization gaps, injection risks (SQL, XSS, command), insecure dependencies, misconfigured CORS or headers, data exposure in logs or responses. Works across all layers, UI, backend, infra.
20
-
21
- ## RTK, MANDATORY
22
-
23
- Use `rtk` for ALL CLI commands. Never run commands directly.
24
-
25
- - `rtk npm audit` NOT `npm audit`
26
- - `rtk dotnet list package --vulnerable` NOT `dotnet list package --vulnerable`
27
-
28
- If `rtk` is not available, report it as a blocker. Do not run commands without it.
29
-
30
- ## Skills, Auto-Detection
31
-
32
- Skills are located in `.agents/skills/`. Detect and use relevant skills automatically, the user will never tell you which skill to use.
33
-
34
- 1. If the spawn prompt lists specific skills to load, read those `SKILL.md` files FIRST before any implementation
35
- 2. Additionally, read the task and identify domain and platform
36
- 3. Scan `.agents/skills/` for available skills
37
- 4. Read each `SKILL.md` description to assess relevance
38
- 5. Load and follow any skill that applies, even partial match warrants loading
39
-
40
- Rules:
41
- - Never implement directly if a skill applies
42
- - Follow skill instructions exactly, do not partially apply them
43
- - If two skills apply, follow both, resolve conflicts by asking the lead
44
- - Skills listed in the spawn prompt are MANDATORY, not optional
45
-
46
- ## Responsibilities
47
-
48
- - Scan for hardcoded secrets, API keys, passwords, tokens
49
- - Check `.env` files are gitignored
50
- - Verify no credentials in logs, URLs, or error responses
51
- - Check authentication and authorization on sensitive endpoints
52
- - Verify input validation at system boundaries
53
- - Check for injection risks in queries and templates
54
- - Review dependency vulnerabilities
55
- - Check CORS, headers, and rate limiting
56
-
57
- ## Severity Levels
58
-
59
- - **Critical**, Must block merge: secret exposure, auth bypass, data loss risk
60
- - **High**, Should fix before merge: injection risk, missing auth, sensitive data leak
61
- - **Medium**, Fix soon: missing rate limiting, weak validation, insecure config
62
- - **Low**, Informational: minor hardening opportunities
63
-
64
- ## Constraints
65
-
66
- - Audit only, `edit: deny` enforced
67
- - Do not push to `main`
68
- - Do not merge PRs, human-only
69
- - Critical findings must block the PR, report to lead immediately
70
-
71
- ## Output Format
72
-
73
- ```
74
- ## Security Auditor, Done
75
-
76
- **Status:** pass | blocked
77
- **Critical:** <count>
78
- **High:** <count>
79
- **Medium:** <count>
80
- **Low:** <count>
81
-
82
- ### Findings
83
- - [severity] [file:line] <description>, <recommended fix>
84
-
85
- **Blockers:** none | <critical findings that must be resolved before PR>
86
- ```
@@ -1,70 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
2
-
3
- vi.mock('../../utils/exec.js', () => ({
4
- commandExists: vi.fn(),
5
- header: vi.fn(),
6
- success: vi.fn(),
7
- error: vi.fn(),
8
- }))
9
-
10
- // Mock execa used directly in check-env.js
11
- vi.mock('execa', () => ({ execa: vi.fn() }))
12
-
13
- import { commandExists, error, success } from '../../utils/exec.js'
14
- import { checkEnv } from '../check-env.js'
15
-
16
- describe('checkEnv()', () => {
17
- const originalVersion = process.version
18
- const originalExit = process.exit
19
-
20
- beforeEach(() => {
21
- process.exit = vi.fn()
22
- vi.clearAllMocks()
23
- })
24
-
25
- afterEach(() => {
26
- Object.defineProperty(process, 'version', { value: originalVersion, writable: true })
27
- process.exit = originalExit
28
- })
29
-
30
- it('exits with error when Node version is < 18', async () => {
31
- Object.defineProperty(process, 'version', { value: 'v16.0.0', writable: true })
32
- commandExists.mockResolvedValue(true)
33
-
34
- await checkEnv()
35
-
36
- expect(error).toHaveBeenCalledWith(expect.stringContaining('v16.0.0'))
37
- expect(process.exit).toHaveBeenCalledWith(1)
38
- })
39
-
40
- it('succeeds when Node version is >= 18 and pnpm is available', async () => {
41
- Object.defineProperty(process, 'version', { value: 'v20.0.0', writable: true })
42
- commandExists.mockImplementation(async (cmd) => cmd === 'pnpm')
43
-
44
- await checkEnv()
45
-
46
- expect(process.exit).not.toHaveBeenCalled()
47
- expect(success).toHaveBeenCalledWith(expect.stringContaining('v20.0.0'))
48
- expect(success).toHaveBeenCalledWith('pnpm available')
49
- })
50
-
51
- it('succeeds when Node version is >= 18 and only npm is available', async () => {
52
- Object.defineProperty(process, 'version', { value: 'v18.0.0', writable: true })
53
- commandExists.mockImplementation(async (cmd) => cmd === 'npm')
54
-
55
- await checkEnv()
56
-
57
- expect(process.exit).not.toHaveBeenCalled()
58
- expect(success).toHaveBeenCalledWith('npm available')
59
- })
60
-
61
- it('exits when neither npm nor pnpm available', async () => {
62
- Object.defineProperty(process, 'version', { value: 'v20.0.0', writable: true })
63
- commandExists.mockResolvedValue(false)
64
-
65
- await checkEnv()
66
-
67
- expect(error).toHaveBeenCalledWith(expect.stringContaining('Neither npm nor pnpm'))
68
- expect(process.exit).toHaveBeenCalledWith(1)
69
- })
70
- })
@@ -1,104 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest'
2
-
3
- vi.mock('../../utils/exec.js', () => ({
4
- commandExists: vi.fn(),
5
- header: vi.fn(),
6
- success: vi.fn(),
7
- warn: vi.fn(),
8
- info: vi.fn(),
9
- code: vi.fn(),
10
- }))
11
-
12
- vi.mock('execa', () => ({
13
- execa: vi.fn(),
14
- }))
15
-
16
- import { execa } from 'execa'
17
- import { commandExists, success, warn } from '../../utils/exec.js'
18
- import { checkPlatform } from '../check-platform.js'
19
-
20
- describe('checkPlatform()', () => {
21
- beforeEach(() => {
22
- vi.clearAllMocks()
23
- })
24
-
25
- describe('github path', () => {
26
- it('prints success when gh is installed and authenticated', async () => {
27
- commandExists.mockResolvedValue(true)
28
- execa.mockResolvedValue({ exitCode: 0, stdout: '' })
29
-
30
- await checkPlatform('github')
31
-
32
- expect(success).toHaveBeenCalledWith('GitHub CLI (gh) available')
33
- expect(success).toHaveBeenCalledWith('GitHub CLI authenticated')
34
- })
35
-
36
- it('warns when gh is installed but not authenticated', async () => {
37
- commandExists.mockResolvedValue(true)
38
- execa.mockResolvedValue({ exitCode: 1, stdout: '' })
39
-
40
- await checkPlatform('github')
41
-
42
- expect(success).toHaveBeenCalledWith('GitHub CLI (gh) available')
43
- expect(warn).toHaveBeenCalledWith(expect.stringContaining('not authenticated'))
44
- })
45
-
46
- it('warns when gh is not installed', async () => {
47
- commandExists.mockResolvedValue(false)
48
-
49
- await checkPlatform('github')
50
-
51
- expect(warn).toHaveBeenCalledWith('GitHub CLI (gh) not found.')
52
- expect(success).not.toHaveBeenCalled()
53
- })
54
-
55
- it('warns when gh auth status check throws', async () => {
56
- commandExists.mockResolvedValue(true)
57
- execa.mockRejectedValue(new Error('spawn error'))
58
-
59
- await checkPlatform('github')
60
-
61
- expect(warn).toHaveBeenCalledWith('Could not check gh auth status.')
62
- })
63
- })
64
-
65
- describe('azure path', () => {
66
- it('prints success when az is installed and azure-devops extension present', async () => {
67
- commandExists.mockResolvedValue(true)
68
- execa.mockResolvedValue({ exitCode: 0, stdout: 'azure-devops\tsome info' })
69
-
70
- await checkPlatform('azure')
71
-
72
- expect(success).toHaveBeenCalledWith('Azure CLI (az) available')
73
- expect(success).toHaveBeenCalledWith('azure-devops extension installed')
74
- })
75
-
76
- it('warns when az is installed but azure-devops extension is missing', async () => {
77
- commandExists.mockResolvedValue(true)
78
- execa.mockResolvedValue({ exitCode: 0, stdout: '' })
79
-
80
- await checkPlatform('azure')
81
-
82
- expect(success).toHaveBeenCalledWith('Azure CLI (az) available')
83
- expect(warn).toHaveBeenCalledWith(expect.stringContaining('azure-devops extension not found'))
84
- })
85
-
86
- it('warns when az is not installed', async () => {
87
- commandExists.mockResolvedValue(false)
88
-
89
- await checkPlatform('azure')
90
-
91
- expect(warn).toHaveBeenCalledWith('Azure CLI (az) not found.')
92
- expect(success).not.toHaveBeenCalled()
93
- })
94
-
95
- it('warns when extension check throws', async () => {
96
- commandExists.mockResolvedValue(true)
97
- execa.mockRejectedValue(new Error('spawn error'))
98
-
99
- await checkPlatform('azure')
100
-
101
- expect(warn).toHaveBeenCalledWith('Could not check azure-devops extension. Run:')
102
- })
103
- })
104
- })
@@ -1,38 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest'
2
-
3
- vi.mock('../../utils/exec.js', () => ({
4
- commandExists: vi.fn(),
5
- header: vi.fn(),
6
- loading: vi.fn(),
7
- success: vi.fn(),
8
- warn: vi.fn(),
9
- info: vi.fn(),
10
- code: vi.fn(),
11
- }))
12
-
13
- import { commandExists, success, warn } from '../../utils/exec.js'
14
- import { checkRtk } from '../check-rtk.js'
15
-
16
- describe('checkRtk()', () => {
17
- beforeEach(() => {
18
- vi.clearAllMocks()
19
- })
20
-
21
- it('prints success when rtk is available', async () => {
22
- commandExists.mockResolvedValue(true)
23
-
24
- await checkRtk({ skipPrompt: true })
25
-
26
- expect(success).toHaveBeenCalledWith('rtk is available')
27
- expect(warn).not.toHaveBeenCalled()
28
- })
29
-
30
- it('prints warning with install instructions when rtk is not found', async () => {
31
- commandExists.mockResolvedValue(false)
32
-
33
- await checkRtk({ skipPrompt: true })
34
-
35
- expect(warn).toHaveBeenCalledWith('rtk not found on PATH.')
36
- expect(success).not.toHaveBeenCalled()
37
- })
38
- })
@@ -1,38 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest'
2
-
3
- vi.mock('../../utils/exec.js', () => ({
4
- header: vi.fn(),
5
- success: vi.fn(),
6
- }))
7
-
8
- vi.mock('@inquirer/prompts', () => ({
9
- select: vi.fn(),
10
- }))
11
-
12
- import { select } from '@inquirer/prompts'
13
- import { success } from '../../utils/exec.js'
14
- import { choosePlatform } from '../choose-platform.js'
15
-
16
- describe('choosePlatform()', () => {
17
- beforeEach(() => {
18
- vi.clearAllMocks()
19
- })
20
-
21
- it('returns "github" when user selects GitHub', async () => {
22
- select.mockResolvedValue('github')
23
-
24
- const result = await choosePlatform()
25
-
26
- expect(result).toBe('github')
27
- expect(success).toHaveBeenCalledWith('Platform: GitHub')
28
- })
29
-
30
- it('returns "azure" when user selects Azure DevOps', async () => {
31
- select.mockResolvedValue('azure')
32
-
33
- const result = await choosePlatform()
34
-
35
- expect(result).toBe('azure')
36
- expect(success).toHaveBeenCalledWith('Platform: Azure DevOps')
37
- })
38
- })
@@ -1,26 +0,0 @@
1
- import { commandExists, error, header, success } from '../utils/exec.js'
2
-
3
- export async function checkEnv() {
4
- header('Step 1, Checking environment')
5
-
6
- // Node version
7
- const nodeVersion = process.version
8
- const major = parseInt(nodeVersion.slice(1).split('.')[0], 10)
9
- if (major < 18) {
10
- error(`Node.js ${nodeVersion} detected. Version 18+ is required.`)
11
- process.exit(1)
12
- }
13
- success(`Node.js ${nodeVersion}`)
14
-
15
- // npm or pnpm
16
- const hasPnpm = await commandExists('pnpm')
17
- const hasNpm = await commandExists('npm')
18
-
19
- if (!hasPnpm && !hasNpm) {
20
- error('Neither npm nor pnpm found. Please install Node.js from https://nodejs.org')
21
- process.exit(1)
22
- }
23
-
24
- if (hasPnpm) success('pnpm available')
25
- else success('npm available')
26
- }