Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,6 @@ Desktop.ini
# ─── Internal / non-public ────────────────────────────────────────────────────
.specify/
.opencode/
.claude/
specs/
TODO.md
96 changes: 38 additions & 58 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,91 +7,71 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.0.0] - 2026-03-20
## [1.5.0] - 2026-04-01

### Added

- Initial public release of Devvami
- DevEx CLI for developers and teams
- Commands: auth, costs, create, docs, pipeline, pr, repo, tasks
- Support for GitHub, AWS, and task management integrations
- Configuration wizard and environment diagnostics


### 🐛 Bug Fixes

* **tasks:** correct today filter to use date range and exclude closed status ([#10](https://github.com/santagostino/cli-santagostino/issues/10)) ([36003e4](https://github.com/santagostino/cli-santagostino/commit/36003e4e2ace164b913ad9954794f5d3381e25a4))

## [1.7.0](https://github.com/santagostino/cli-santagostino/compare/v1.6.0...v1.7.0) (2026-03-19)

### ✨ Features

* **help:** add animated SNTG logo and categorized command layout ([#9](https://github.com/santagostino/cli-santagostino/issues/9)) ([58c5581](https://github.com/santagostino/cli-santagostino/commit/58c5581e99123b6ce66ebbdd2fd42a2990534a80))

## [1.6.0](https://github.com/santagostino/cli-santagostino/compare/v1.5.0...v1.6.0) (2026-03-19)
- `dvmi sync-config-ai` — interactive TUI to manage AI coding tool configurations (MCP servers, commands, skills, agents) across VS Code Copilot, Claude Code, OpenCode, Gemini CLI, and GitHub Copilot CLI
- 5-tab TUI layout: Environments (read-only) + dedicated tab per category type (MCPs | Commands | Skills | Agents)
- Inline forms with Environments multi-select filtered by compatibility matrix
- OpenCode global detection via `~/.config/opencode/`
- `--json` flag for non-interactive / CI use

### ✨ Features
## [1.4.2] - 2026-03-29

* **docs:** add sntg docs commands (list, read, search, projects) ([#8](https://github.com/santagostino/cli-santagostino/issues/8)) ([be92259](https://github.com/santagostino/cli-santagostino/commit/be92259ffdcb6a82b6f6cc11df4c736f9c71828a))
### Changed

## [1.5.0](https://github.com/santagostino/cli-santagostino/compare/v1.4.0...v1.5.0) (2026-03-19)
- **vuln:** extend navigable TUI table to `dvmi vuln scan` ([#10](https://github.com/savez/devvami/issues/10))

### ✨ Features
## [1.4.1] - 2026-03-29

* improve list tables with search, colors and remove repo limit ([#7](https://github.com/santagostino/cli-santagostino/issues/7)) ([4ad25fb](https://github.com/santagostino/cli-santagostino/commit/4ad25fbaa1d827d5ca41672b22c29c8507e410a6))
### Changed

## [1.4.0](https://github.com/santagostino/cli-santagostino/compare/v1.3.0...v1.4.0) (2026-03-18)
- **vuln:** interactive CVE table with navigable TUI and modal overlay — spec 006 ([#9](https://github.com/savez/devvami/issues/9))

### ✨ Features
## [1.4.0] - 2026-03-28

* add link column to tasks, fix today filter timezone/status, add clickup to whoami ([#6](https://github.com/santagostino/cli-santagostino/issues/6)) ([2db8a41](https://github.com/santagostino/cli-santagostino/commit/2db8a41c74d85a84eb010c84dcc84d990798d4a6))

### 🐛 Bug Fixes
### Added

* **ci:** disable footer-max-line-length to allow semantic-release changelog URLs ([4a4b392](https://github.com/santagostino/cli-santagostino/commit/4a4b392ab6a880f28cf3c009508a72bf13466044))
- **dotfiles:** `dvmi dotfiles` commands — setup, add, sync, status — with age encryption and chezmoi integration ([#8](https://github.com/savez/devvami/issues/8))

## [1.3.0](https://github.com/santagostino/cli-santagostino/compare/v1.2.0...v1.3.0) (2026-03-18)
## [1.3.0] - 2026-03-27

### ✨ Features
### Added

* add ClickUp configuration wizard & remove branch create command ([b8c3634](https://github.com/santagostino/cli-santagostino/commit/b8c36348c45df904f02f06227e9ad210bc7a88ab))
* add ClickUp configuration wizard to init command ([085defe](https://github.com/santagostino/cli-santagostino/commit/085defe562fd83bf699d2883ad535ddf9e321ec6))
- **aws:** `dvmi costs trend`, CloudWatch logs (`dvmi logs`), and aws-vault integration ([#7](https://github.com/savez/devvami/issues/7))

## [1.2.0](https://github.com/santagostino/cli-santagostino/compare/v1.1.0...v1.2.0) (2026-03-18)
## [1.2.0] - 2026-03-25

### ✨ Features
### Added

* aggiunge pr detail con QA steps/comments e pr review dedicato ([66b8f76](https://github.com/santagostino/cli-santagostino/commit/66b8f764b7d2a474b913d6c1e2a69d35cb16f26c))
* sntg pr detail + sntg pr review ([bcf9da1](https://github.com/santagostino/cli-santagostino/commit/bcf9da113ab8881e21c12766f292d1f90443e03e))
- **security:** `dvmi security setup` wizard with automated security checks ([#6](https://github.com/savez/devvami/issues/6))
- Welcome message on first run

## [1.1.0](https://github.com/santagostino/cli-santagostino/compare/v1.0.0...v1.1.0) (2026-03-18)
## [1.1.2] - 2026-03-24

### ✨ Features
### Fixed

* **cli:** redesign visivo con gradient animato, emoji e spinner brand-styled ([e452f25](https://github.com/santagostino/cli-santagostino/commit/e452f25f85523a4a34a4e8a79bfd16c123cdef25))
* **cli:** redesign visivo con gradient animato, emoji e spinner brand-styled ([313d718](https://github.com/santagostino/cli-santagostino/commit/313d71893229af4d14bde051f8610c48d2bc984f))
- **init:** stop ora spinner before interactive prompts to prevent TTY freeze on macOS ([#5](https://github.com/savez/devvami/issues/5))

### 🐛 Bug Fixes
## [1.1.1] - 2026-03-23

* **cli:** rimuovi --registry da npm install in upgrade per evitare 404 sulle dipendenze ([0fe4395](https://github.com/santagostino/cli-santagostino/commit/0fe4395b6a2c42fa93917bd4a8132927f33e4c40))
* **cli:** version check usa gh releases API invece di npm view ([0e78496](https://github.com/santagostino/cli-santagostino/commit/0e7849652d5606113838862f80e5ca594b3ca116))
### Fixed

## 1.0.0 (2026-03-18)
- Apply security fixes and add pre-push version sync hook ([#4](https://github.com/savez/devvami/issues/4))
- Apply 7 security fixes from ZeroTrustino audit ([#3](https://github.com/savez/devvami/issues/3))

### ✨ Features
## [1.1.0] - 2026-03-23

* refactor commands as pure topics and improve help discoverability ([0dda165](https://github.com/santagostino/cli-santagostino/commit/0dda165385f4df665148dba19af24b238a527e93))
### Added

### 🐛 Bug Fixes
- **prompts:** AI prompt hub — `dvmi prompts browse`, `download`, `run`, `list` ([#2](https://github.com/savez/devvami/issues/2))

* **ci:** aggiungi pnpm-lock.yaml al repo e rimuovilo dal gitignore ([77abeca](https://github.com/santagostino/cli-santagostino/commit/77abeca996e9339b844940089794e87b14e5432d))
* correggere sntg upgrade che non rilevava nuove versioni ([a922655](https://github.com/santagostino/cli-santagostino/commit/a922655bcda93dff89026dab786b1a2affb9c850))
* **ci:** disabilita body-max-line-length e rimuovi eslint-disable sec… ([4c99d98](https://github.com/santagostino/cli-santagostino/commit/4c99d9856800d4e7070d15545770b42af4b63980))
* **ci:** disabilita body-max-line-length e rimuovi eslint-disable security non valido ([b75f872](https://github.com/santagostino/cli-santagostino/commit/b75f872eacf038b921cbfbc981065a0401650c87))
* **ci:** rimuovi import readFile inutilizzato nel test version-check ([a630458](https://github.com/santagostino/cli-santagostino/commit/a630458a1f1d97b9f961fd1411c81dd1a0f564b9))
## [1.0.0] - 2026-03-20

### 📚 Documentation
### Added

* aggiungi README con istruzioni installazione e aggiornamento CLI ([4ecb16b](https://github.com/santagostino/cli-santagostino/commit/4ecb16bc7b7780732077ba1c5b899947383c3f77))
* migliora README e aggiungi TODO.md al gitignore ([5116dc9](https://github.com/santagostino/cli-santagostino/commit/5116dc9f37f542843b47a07afe6daaf341e805eb))
* README in stile opensource con badge, emoji e sezione sviluppo locale ([ad720b5](https://github.com/santagostino/cli-santagostino/commit/ad720b59cbf700986861ab074da70ba4eccf8166))
- Initial public open-source release of Devvami
- Commands: `auth`, `costs`, `create`, `docs`, `pipeline`, `pr`, `repo`, `tasks`, `branch`, `doctor`, `init`, `upgrade`, `whoami`
- GitHub, AWS, and ClickUp integrations
- Configuration wizard (`dvmi init`) and environment diagnostics (`dvmi doctor`)
29 changes: 29 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# devvami Development Guidelines

Auto-generated from all feature plans. Last updated: 2026-04-01

## Active Technologies

- JavaScript (ESM, `.js`) with JSDoc — Node.js >= 24 + `@oclif/core` v4, `chalk` v5, `ora` v8, `execa` v9 — zero new TUI dependencies (007-sync-ai-config-tui)

## Project Structure

```text
src/
tests/
```

## Commands

npm test && npm run lint

## Code Style

JavaScript (ESM, `.js`) with JSDoc — Node.js >= 24: Follow standard conventions

## Recent Changes

- 007-sync-ai-config-tui: Added JavaScript (ESM, `.js`) with JSDoc — Node.js >= 24 + `@oclif/core` v4, `chalk` v5, `ora` v8, `execa` v9 — zero new TUI dependencies

<!-- MANUAL ADDITIONS START -->
<!-- MANUAL ADDITIONS END -->
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "devvami",
"description": "DevEx CLI for developers and teams — manage repos, PRs, pipelines, tasks, and costs from the terminal",
"version": "1.4.2",
"version": "1.5.0",
"author": "",
"type": "module",
"bin": {
Expand Down Expand Up @@ -139,6 +139,7 @@
"test:integration": "vitest run --project integration",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
"pretest": "oclif manifest",
"prepack": "oclif manifest",
"postpack": "shx rm -f oclif.manifest.json",
"prepare": "lefthook install"
Expand Down
36 changes: 20 additions & 16 deletions src/commands/auth/login.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Command, Flags } from '@oclif/core'
import {Command, Flags} from '@oclif/core'
import chalk from 'chalk'
import ora from 'ora'
import { checkGitHubAuth, loginGitHub, checkAWSAuth, loginAWS } from '../../services/auth.js'
import { loadConfig } from '../../services/config.js'
import {checkGitHubAuth, loginGitHub, checkAWSAuth, loginAWS} from '../../services/auth.js'
import {loadConfig} from '../../services/config.js'

export default class AuthLogin extends Command {
static description = 'Autenticazione centralizzata GitHub + AWS'
Expand All @@ -16,58 +16,62 @@ export default class AuthLogin extends Command {
static enableJsonFlag = true

static flags = {
github: Flags.boolean({ description: 'Solo autenticazione GitHub', default: false }),
aws: Flags.boolean({ description: 'Solo autenticazione AWS', default: false }),
verbose: Flags.boolean({ description: 'Output dettagliato', default: false }),
github: Flags.boolean({description: 'Solo autenticazione GitHub', default: false}),
aws: Flags.boolean({description: 'Solo autenticazione AWS', default: false}),
verbose: Flags.boolean({description: 'Output dettagliato', default: false}),
}

async run() {
const { flags } = await this.parse(AuthLogin)
const {flags} = await this.parse(AuthLogin)
const isJson = flags.json
const doGitHub = !flags.aws || flags.github
const doAWS = !flags.github || flags.aws

const result = { github: null, aws: null }
const result = {github: null, aws: null}

// GitHub auth
if (doGitHub) {
const spinner = isJson ? null : ora({ spinner: 'arc', color: false, text: chalk.hex('#FF6B2B')('Checking GitHub auth...') }).start()
const spinner = isJson
? null
: ora({spinner: 'arc', color: false, text: chalk.hex('#FF6B2B')('Checking GitHub auth...')}).start()
let ghStatus = await checkGitHubAuth()

if (ghStatus.authenticated) {
spinner?.succeed(`GitHub: already authenticated as @${ghStatus.username}`)
result.github = { status: 'ok', username: ghStatus.username, org: '' }
result.github = {status: 'ok', username: ghStatus.username, org: ''}
} else {
if (spinner) spinner.text = 'Logging in to GitHub...'
ghStatus = await loginGitHub()
if (ghStatus.authenticated) {
spinner?.succeed(`GitHub: authenticated as @${ghStatus.username}`)
result.github = { status: 'ok', username: ghStatus.username, org: '' }
result.github = {status: 'ok', username: ghStatus.username, org: ''}
} else {
spinner?.fail('GitHub authentication failed')
result.github = { status: 'error', error: ghStatus.error }
result.github = {status: 'error', error: ghStatus.error}
}
}
}

// AWS auth
if (doAWS) {
const config = await loadConfig()
const spinner = isJson ? null : ora({ spinner: 'arc', color: false, text: chalk.hex('#FF6B2B')('Checking AWS auth...') }).start()
const spinner = isJson
? null
: ora({spinner: 'arc', color: false, text: chalk.hex('#FF6B2B')('Checking AWS auth...')}).start()
let awsStatus = await checkAWSAuth()

if (awsStatus.authenticated) {
spinner?.succeed(`AWS: session active for account ${awsStatus.account}`)
result.aws = { status: 'ok', account: awsStatus.account, role: awsStatus.role }
result.aws = {status: 'ok', account: awsStatus.account, role: awsStatus.role}
} else {
if (spinner) spinner.text = 'Logging in to AWS via aws-vault...'
awsStatus = await loginAWS(config.awsProfile || 'default')
if (awsStatus.authenticated) {
spinner?.succeed(`AWS: logged in to account ${awsStatus.account}`)
result.aws = { status: 'ok', account: awsStatus.account, role: awsStatus.role }
result.aws = {status: 'ok', account: awsStatus.account, role: awsStatus.role}
} else {
spinner?.fail('AWS authentication failed')
result.aws = { status: 'error', error: awsStatus.error }
result.aws = {status: 'error', error: awsStatus.error}
}
}
}
Expand Down
24 changes: 12 additions & 12 deletions src/commands/changelog.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Command, Flags } from '@oclif/core'
import { writeFile } from 'node:fs/promises'
import { exec } from '../services/shell.js'
import {Command, Flags} from '@oclif/core'
import {writeFile} from 'node:fs/promises'
import {exec} from '../services/shell.js'

/**
* Parse a conventional commit message.
Expand All @@ -10,7 +10,7 @@ import { exec } from '../services/shell.js'
function parseConventionalCommit(message) {
const match = message.match(/^(\w+)(?:\(([^)]+)\))?!?: (.+)/)
if (!match) return null
return { type: match[1], scope: match[2] ?? '', description: match[3] }
return {type: match[1], scope: match[2] ?? '', description: match[3]}
}

export default class Changelog extends Command {
Expand All @@ -25,13 +25,13 @@ export default class Changelog extends Command {
static enableJsonFlag = true

static flags = {
from: Flags.string({ description: 'Tag o commit di partenza (default: ultimo tag)' }),
to: Flags.string({ description: 'Commit finale (default: HEAD)', default: 'HEAD' }),
output: Flags.string({ description: 'Scrivi su file (default: stdout)' }),
from: Flags.string({description: 'Tag o commit di partenza (default: ultimo tag)'}),
to: Flags.string({description: 'Commit finale (default: HEAD)', default: 'HEAD'}),
output: Flags.string({description: 'Scrivi su file (default: stdout)'}),
}

async run() {
const { flags } = await this.parse(Changelog)
const {flags} = await this.parse(Changelog)
const isJson = flags.json

// Determine from ref
Expand All @@ -51,21 +51,21 @@ export default class Changelog extends Command {
const lines = logResult.stdout.split('\n').filter(Boolean)

/** @type {Record<string, Array<{ message: string, hash: string }>>} */
const sections = { feat: [], fix: [], chore: [], docs: [], refactor: [], test: [], other: [] }
const sections = {feat: [], fix: [], chore: [], docs: [], refactor: [], test: [], other: []}

for (const line of lines) {
const [message, hash] = line.split('|')
const parsed = parseConventionalCommit(message)
const type = parsed?.type ?? 'other'
const entry = { message: message.trim(), hash: hash?.slice(0, 7) ?? '' }
const entry = {message: message.trim(), hash: hash?.slice(0, 7) ?? ''}
if (type in sections) {
sections[type].push(entry)
} else {
sections.other.push(entry)
}
}

if (isJson) return { from: from || 'beginning', to: flags.to, sections }
if (isJson) return {from: from || 'beginning', to: flags.to, sections}

// Build markdown
const title = `## [Unreleased]${from ? ` (since ${from})` : ''}`
Expand Down Expand Up @@ -97,6 +97,6 @@ export default class Changelog extends Command {
this.log(output)
}

return { from: from || 'beginning', to: flags.to, sections }
return {from: from || 'beginning', to: flags.to, sections}
}
}
Loading
Loading