devvami 1.4.2 → 1.5.1

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 (96) hide show
  1. package/README.md +72 -0
  2. package/oclif.manifest.json +275 -235
  3. package/package.json +2 -1
  4. package/src/commands/auth/login.js +20 -16
  5. package/src/commands/changelog.js +12 -12
  6. package/src/commands/costs/get.js +14 -24
  7. package/src/commands/costs/trend.js +13 -24
  8. package/src/commands/create/repo.js +72 -54
  9. package/src/commands/docs/list.js +29 -25
  10. package/src/commands/docs/projects.js +58 -24
  11. package/src/commands/docs/read.js +56 -39
  12. package/src/commands/docs/search.js +37 -25
  13. package/src/commands/doctor.js +37 -35
  14. package/src/commands/dotfiles/add.js +51 -39
  15. package/src/commands/dotfiles/setup.js +62 -33
  16. package/src/commands/dotfiles/status.js +18 -18
  17. package/src/commands/dotfiles/sync.js +62 -46
  18. package/src/commands/init.js +143 -132
  19. package/src/commands/logs/index.js +10 -16
  20. package/src/commands/open.js +12 -12
  21. package/src/commands/pipeline/logs.js +8 -11
  22. package/src/commands/pipeline/rerun.js +21 -16
  23. package/src/commands/pipeline/status.js +28 -24
  24. package/src/commands/pr/create.js +40 -27
  25. package/src/commands/pr/detail.js +9 -7
  26. package/src/commands/pr/review.js +18 -19
  27. package/src/commands/pr/status.js +27 -21
  28. package/src/commands/prompts/browse.js +15 -15
  29. package/src/commands/prompts/download.js +15 -16
  30. package/src/commands/prompts/install-speckit.js +11 -12
  31. package/src/commands/prompts/list.js +12 -12
  32. package/src/commands/prompts/run.js +16 -19
  33. package/src/commands/repo/list.js +57 -41
  34. package/src/commands/search.js +20 -18
  35. package/src/commands/security/setup.js +38 -34
  36. package/src/commands/sync-config-ai/index.js +257 -0
  37. package/src/commands/tasks/assigned.js +43 -33
  38. package/src/commands/tasks/list.js +43 -33
  39. package/src/commands/tasks/today.js +32 -30
  40. package/src/commands/upgrade.js +18 -17
  41. package/src/commands/vuln/detail.js +8 -8
  42. package/src/commands/vuln/scan.js +39 -20
  43. package/src/commands/vuln/search.js +23 -18
  44. package/src/commands/welcome.js +2 -2
  45. package/src/commands/whoami.js +19 -23
  46. package/src/formatters/ai-config.js +215 -0
  47. package/src/formatters/charts.js +6 -23
  48. package/src/formatters/cost.js +1 -7
  49. package/src/formatters/dotfiles.js +48 -19
  50. package/src/formatters/markdown.js +11 -6
  51. package/src/formatters/openapi.js +7 -9
  52. package/src/formatters/prompts.js +69 -78
  53. package/src/formatters/security.js +2 -2
  54. package/src/formatters/status.js +1 -1
  55. package/src/formatters/table.js +1 -3
  56. package/src/formatters/vuln.js +33 -20
  57. package/src/help.js +162 -164
  58. package/src/hooks/init.js +1 -3
  59. package/src/hooks/postrun.js +5 -7
  60. package/src/index.js +1 -1
  61. package/src/services/ai-config-store.js +349 -0
  62. package/src/services/ai-env-deployer.js +650 -0
  63. package/src/services/ai-env-scanner.js +983 -0
  64. package/src/services/audit-detector.js +2 -2
  65. package/src/services/audit-runner.js +40 -31
  66. package/src/services/auth.js +9 -9
  67. package/src/services/awesome-copilot.js +7 -4
  68. package/src/services/aws-costs.js +22 -22
  69. package/src/services/clickup.js +26 -26
  70. package/src/services/cloudwatch-logs.js +5 -9
  71. package/src/services/config.js +13 -13
  72. package/src/services/docs.js +19 -20
  73. package/src/services/dotfiles.js +149 -51
  74. package/src/services/github.js +22 -24
  75. package/src/services/nvd.js +21 -31
  76. package/src/services/platform.js +2 -2
  77. package/src/services/prompts.js +23 -35
  78. package/src/services/security.js +135 -61
  79. package/src/services/shell.js +4 -4
  80. package/src/services/skills-sh.js +3 -9
  81. package/src/services/speckit.js +4 -7
  82. package/src/services/version-check.js +10 -10
  83. package/src/types.js +117 -0
  84. package/src/utils/aws-vault.js +18 -41
  85. package/src/utils/banner.js +5 -7
  86. package/src/utils/errors.js +42 -46
  87. package/src/utils/frontmatter.js +4 -4
  88. package/src/utils/gradient.js +18 -16
  89. package/src/utils/open-browser.js +3 -3
  90. package/src/utils/tui/form.js +1184 -0
  91. package/src/utils/tui/modal.js +15 -14
  92. package/src/utils/tui/navigable-table.js +16 -16
  93. package/src/utils/tui/tab-tui.js +1089 -0
  94. package/src/utils/typewriter.js +3 -3
  95. package/src/utils/welcome.js +18 -21
  96. package/src/validators/repo-name.js +2 -2
package/src/help.js CHANGED
@@ -1,13 +1,13 @@
1
- import { Help } from '@oclif/core'
1
+ import {Help} from '@oclif/core'
2
2
  import chalk from 'chalk'
3
- import { isColorEnabled } from './utils/gradient.js'
4
- import { printBanner } from './utils/banner.js'
3
+ import {isColorEnabled} from './utils/gradient.js'
4
+ import {printBanner} from './utils/banner.js'
5
5
 
6
6
  // ─── Brand palette (flat — no gradient on help rows) ────────────────────────
7
- const ORANGE = '#FF6B2B'
7
+ const ORANGE = '#FF6B2B'
8
8
  const LIGHT_ORANGE = '#FF9A5C'
9
- const DIM_BLUE = '#4A9EFF'
10
- const DIM_GRAY = '#888888'
9
+ const DIM_BLUE = '#4A9EFF'
10
+ const DIM_GRAY = '#888888'
11
11
 
12
12
  // Strip ANSI escape codes
13
13
  const ANSI_RE = /\x1B\[[0-?]*[ -/]*[@-~]/g
@@ -27,92 +27,91 @@ const CATEGORIES = [
27
27
  {
28
28
  title: 'GitHub & Documentazione',
29
29
  cmds: [
30
- { id: 'repo:list', hint: '[--language] [--search]' },
31
- { id: 'docs:read', hint: '[FILE] [--repo] [--raw] [--render]' },
32
- { id: 'docs:list', hint: '[--repo] [--search]' },
33
- { id: 'docs:search', hint: '<TERM> [--repo]' },
34
- { id: 'docs:projects', hint: '[--search]' },
35
- { id: 'create:repo', hint: '[TEMPLATE] [--list] [--name]' },
36
- { id: 'search', hint: '<QUERY>' },
37
- { id: 'open', hint: '<TARGET>' },
30
+ {id: 'repo:list', hint: '[--language] [--search]'},
31
+ {id: 'docs:read', hint: '[FILE] [--repo] [--raw] [--render]'},
32
+ {id: 'docs:list', hint: '[--repo] [--search]'},
33
+ {id: 'docs:search', hint: '<TERM> [--repo]'},
34
+ {id: 'docs:projects', hint: '[--search]'},
35
+ {id: 'create:repo', hint: '[TEMPLATE] [--list] [--name]'},
36
+ {id: 'search', hint: '<QUERY>'},
37
+ {id: 'open', hint: '<TARGET>'},
38
38
  ],
39
39
  },
40
40
  {
41
41
  title: 'Pull Request',
42
42
  cmds: [
43
- { id: 'pr:create', hint: '' },
44
- { id: 'pr:status', hint: '' },
45
- { id: 'pr:detail', hint: '<PR_NUMBER> --repo <owner/repo>' },
46
- { id: 'pr:review', hint: '' },
43
+ {id: 'pr:create', hint: ''},
44
+ {id: 'pr:status', hint: ''},
45
+ {id: 'pr:detail', hint: '<PR_NUMBER> --repo <owner/repo>'},
46
+ {id: 'pr:review', hint: ''},
47
47
  ],
48
48
  },
49
49
  {
50
50
  title: 'Pipeline & DevOps',
51
51
  cmds: [
52
- { id: 'pipeline:status', hint: '[--repo] [--branch]' },
53
- { id: 'pipeline:rerun', hint: '<RUN_ID> --repo <repo>' },
54
- { id: 'pipeline:logs', hint: '<RUN_ID> --repo <repo>' },
55
- { id: 'changelog', hint: '' },
52
+ {id: 'pipeline:status', hint: '[--repo] [--branch]'},
53
+ {id: 'pipeline:rerun', hint: '<RUN_ID> --repo <repo>'},
54
+ {id: 'pipeline:logs', hint: '<RUN_ID> --repo <repo>'},
55
+ {id: 'changelog', hint: ''},
56
56
  ],
57
57
  },
58
58
  {
59
59
  title: 'Tasks (ClickUp)',
60
60
  cmds: [
61
- { id: 'tasks:list', hint: '[--status] [--search]' },
62
- { id: 'tasks:today', hint: '' },
63
- { id: 'tasks:assigned', hint: '[--status] [--search]' },
61
+ {id: 'tasks:list', hint: '[--status] [--search]'},
62
+ {id: 'tasks:today', hint: ''},
63
+ {id: 'tasks:assigned', hint: '[--status] [--search]'},
64
64
  ],
65
65
  },
66
66
  {
67
67
  title: 'Cloud & Costi',
68
68
  cmds: [
69
- { id: 'costs:get', hint: '[SERVICE] [--period] [--group-by] [--tag-key]' },
70
- { id: 'costs:trend', hint: '[--group-by] [--tag-key] [--line]' },
71
- { id: 'logs', hint: '[--group] [--filter] [--since] [--limit] [--region]' },
69
+ {id: 'costs:get', hint: '[SERVICE] [--period] [--group-by] [--tag-key]'},
70
+ {id: 'costs:trend', hint: '[--group-by] [--tag-key] [--line]'},
71
+ {id: 'logs', hint: '[--group] [--filter] [--since] [--limit] [--region]'},
72
72
  ],
73
73
  },
74
74
  {
75
75
  title: 'AI Prompts',
76
76
  cmds: [
77
- { id: 'prompts:list', hint: '[--filter]' },
78
- { id: 'prompts:download', hint: '<PATH> [--overwrite]' },
79
- { id: 'prompts:browse', hint: '[--source] [--query] [--category]' },
80
- { id: 'prompts:install-speckit', hint: '[--force]' },
81
- { id: 'prompts:run', hint: '[PATH] [--tool]' },
77
+ {id: 'prompts:list', hint: '[--filter]'},
78
+ {id: 'prompts:download', hint: '<PATH> [--overwrite]'},
79
+ {id: 'prompts:browse', hint: '[--source] [--query] [--category]'},
80
+ {id: 'prompts:install-speckit', hint: '[--force]'},
81
+ {id: 'prompts:run', hint: '[PATH] [--tool]'},
82
+ {id: 'sync-config-ai', hint: '[--json]'},
82
83
  ],
83
84
  },
84
85
  {
85
86
  title: 'Sicurezza & Credenziali',
86
- cmds: [
87
- { id: 'security:setup', hint: '[--json]' },
88
- ],
87
+ cmds: [{id: 'security:setup', hint: '[--json]'}],
89
88
  },
90
89
  {
91
90
  title: 'CVE & Vulnerabilità',
92
91
  cmds: [
93
- { id: 'vuln:search', hint: '[KEYWORD] [--days] [--severity] [--limit]' },
94
- { id: 'vuln:detail', hint: '<CVE-ID> [--open]' },
95
- { id: 'vuln:scan', hint: '[--severity] [--no-fail] [--report]' },
92
+ {id: 'vuln:search', hint: '[KEYWORD] [--days] [--severity] [--limit]'},
93
+ {id: 'vuln:detail', hint: '<CVE-ID> [--open]'},
94
+ {id: 'vuln:scan', hint: '[--severity] [--no-fail] [--report]'},
96
95
  ],
97
96
  },
98
97
  {
99
98
  title: 'Dotfiles & Cifratura',
100
99
  cmds: [
101
- { id: 'dotfiles:setup', hint: '[--json]' },
102
- { id: 'dotfiles:add', hint: '[FILES...] [--encrypt]' },
103
- { id: 'dotfiles:status', hint: '[--json]' },
104
- { id: 'dotfiles:sync', hint: '[--push] [--pull] [--dry-run]' },
100
+ {id: 'dotfiles:setup', hint: '[--json]'},
101
+ {id: 'dotfiles:add', hint: '[FILES...] [--encrypt]'},
102
+ {id: 'dotfiles:status', hint: '[--json]'},
103
+ {id: 'dotfiles:sync', hint: '[--push] [--pull] [--dry-run]'},
105
104
  ],
106
105
  },
107
106
  {
108
107
  title: 'Setup & Ambiente',
109
108
  cmds: [
110
- { id: 'init', hint: '[--dry-run]' },
111
- { id: 'doctor', hint: '' },
112
- { id: 'auth:login', hint: '' },
113
- { id: 'whoami', hint: '' },
114
- { id: 'welcome', hint: '' },
115
- { id: 'upgrade', hint: '' },
109
+ {id: 'init', hint: '[--dry-run]'},
110
+ {id: 'doctor', hint: ''},
111
+ {id: 'auth:login', hint: ''},
112
+ {id: 'whoami', hint: ''},
113
+ {id: 'welcome', hint: ''},
114
+ {id: 'upgrade', hint: ''},
116
115
  ],
117
116
  },
118
117
  ]
@@ -126,31 +125,30 @@ const CATEGORIES = [
126
125
  * - Gradient solo sul logo; tutto il resto usa colori flat chalk
127
126
  */
128
127
  export default class CustomHelp extends Help {
128
+ /**
129
+ * Root help override: banner animato → layout categorizzato.
130
+ * Override di showRootHelp() (async) per evitare che formatRoot() (sync)
131
+ * debba attendere la Promise del banner.
132
+ * @returns {Promise<void>}
133
+ */
134
+ async showRootHelp() {
135
+ // Animated logo — identical to `dvmi init` (no-ops in CI/non-TTY)
136
+ await printBanner()
137
+
138
+ // Version check: uses cached result (populated by init hook) — 800 ms timeout
139
+ let versionInfo = null
140
+ try {
141
+ const {checkForUpdate} = await import('./services/version-check.js')
142
+ versionInfo = await Promise.race([
143
+ checkForUpdate(),
144
+ new Promise((resolve) => setTimeout(() => resolve(null), 800)),
145
+ ])
146
+ } catch {
147
+ // never block help output
148
+ }
129
149
 
130
- /**
131
- * Root help override: banner animato → layout categorizzato.
132
- * Override di showRootHelp() (async) per evitare che formatRoot() (sync)
133
- * debba attendere la Promise del banner.
134
- * @returns {Promise<void>}
135
- */
136
- async showRootHelp() {
137
- // Animated logo — identical to `dvmi init` (no-ops in CI/non-TTY)
138
- await printBanner()
139
-
140
- // Version check: uses cached result (populated by init hook) — 800 ms timeout
141
- let versionInfo = null
142
- try {
143
- const { checkForUpdate } = await import('./services/version-check.js')
144
- versionInfo = await Promise.race([
145
- checkForUpdate(),
146
- new Promise((resolve) => setTimeout(() => resolve(null), 800)),
147
- ])
148
- } catch {
149
- // never block help output
150
- }
151
-
152
- this.log(this.#buildRootLayout(versionInfo))
153
- }
150
+ this.log(this.#buildRootLayout(versionInfo))
151
+ }
154
152
 
155
153
  /**
156
154
  * @param {import('@oclif/core').Interfaces.Topic[]} topics
@@ -179,69 +177,64 @@ export default class CustomHelp extends Help {
179
177
 
180
178
  // ─── Private helpers ──────────────────────────────────────────────────────
181
179
 
182
- /**
183
- * Build the full categorized root help layout.
184
- * @param {{ hasUpdate: boolean, current: string, latest: string|null }|null} [versionInfo]
185
- * @returns {string}
186
- */
180
+ /**
181
+ * Build the full categorized root help layout.
182
+ * @param {{ hasUpdate: boolean, current: string, latest: string|null }|null} [versionInfo]
183
+ * @returns {string}
184
+ */
187
185
  #buildRootLayout(versionInfo = null) {
188
186
  /** @type {Map<string, import('@oclif/core').Command.Cached>} */
189
187
  const cmdMap = new Map(this.config.commands.map((c) => [c.id, c]))
190
188
 
191
189
  /** @type {Array<{cmd: string, note: string}>} */
192
190
  const EXAMPLES = [
193
- { cmd: 'dvmi prompts list', note: 'Sfoglia prompt AI dal tuo repository' },
194
- { cmd: 'dvmi prompts list --filter refactor', note: 'Filtra prompt per parola chiave' },
195
- { cmd: 'dvmi prompts download coding/refactor-prompt.md', note: 'Scarica un prompt localmente' },
196
- { cmd: 'dvmi prompts browse skills --query refactor', note: 'Cerca skill su skills.sh' },
197
- { cmd: 'dvmi prompts browse awesome --category agents', note: 'Sfoglia awesome-copilot agents' },
198
- { cmd: 'dvmi prompts run coding/refactor-prompt.md --tool opencode', note: 'Esegui un prompt con opencode' },
199
- { cmd: 'dvmi docs read', note: 'Leggi il README del repo corrente' },
200
- { cmd: 'dvmi docs search "authentication"', note: 'Cerca nei docs del repo corrente' },
201
- { cmd: 'dvmi repo list --search "api"', note: 'Filtra repository per nome' },
202
- { cmd: 'dvmi pr status', note: 'PR aperte e review in attesa' },
203
- { cmd: 'dvmi pipeline status', note: 'Ultimi workflow CI/CD' },
204
- { cmd: 'dvmi tasks list --search "bug"', note: 'Cerca task ClickUp' },
205
- { cmd: 'dvmi tasks today', note: 'Task in lavorazione oggi' },
206
- { cmd: 'dvmi costs get --period mtd', note: 'Costi AWS mese corrente per servizio' },
207
- { cmd: 'dvmi costs get --group-by tag --tag-key env', note: 'Costi raggruppati per tag env' },
208
- { cmd: 'dvmi costs trend --line', note: 'Trend costi 2 mesi (grafico lineare)' },
209
- { cmd: 'dvmi costs get --json', note: 'Costi AWS in formato JSON' },
210
- { cmd: 'dvmi logs', note: 'Sfoglia log CloudWatch in modo interattivo' },
211
- { cmd: 'dvmi logs --group /aws/lambda/my-fn --since 24h', note: 'Log Lambda ultimi 24h' },
212
- { cmd: 'dvmi logs --group /aws/lambda/my-fn --filter "ERROR"', note: 'Filtra eventi ERROR su un log group' },
213
- { cmd: 'dvmi security setup --json', note: 'Controlla lo stato degli strumenti di sicurezza' },
214
- { cmd: 'dvmi security setup', note: 'Wizard interattivo: installa aws-vault e GCM' },
215
- { cmd: 'dvmi dotfiles setup', note: 'Configura chezmoi con cifratura age' },
216
- { cmd: 'dvmi dotfiles add ~/.zshrc ~/.gitconfig', note: 'Aggiungi dotfile a chezmoi' },
217
- { cmd: 'dvmi dotfiles status --json', note: 'Stato dotfile gestiti (JSON)' },
218
- { cmd: 'dvmi dotfiles sync --push', note: 'Push dotfile al repository remoto' },
219
- { cmd: 'dvmi welcome', note: 'Dashboard missione dvmi con intro animata' },
220
- { cmd: 'dvmi vuln search openssl', note: 'Cerca CVE recenti per keyword' },
221
- { cmd: 'dvmi vuln search log4j --days 30 --severity critical', note: 'CVE critiche Log4j negli ultimi 30 giorni' },
222
- { cmd: 'dvmi vuln detail CVE-2021-44228', note: 'Dettaglio completo di una CVE' },
223
- { cmd: 'dvmi vuln detail CVE-2021-44228 --open', note: 'Apri la prima referenza nel browser' },
224
- { cmd: 'dvmi vuln scan', note: 'Scansiona dipendenze del progetto corrente' },
225
- { cmd: 'dvmi vuln scan --severity high --no-fail', note: 'Scansione senza bloccare CI (solo high+)' },
226
- { cmd: 'dvmi vuln scan --report ./vuln-report.md', note: 'Esporta report Markdown delle vulnerabilità' },
191
+ {cmd: 'dvmi prompts list', note: 'Sfoglia prompt AI dal tuo repository'},
192
+ {cmd: 'dvmi prompts list --filter refactor', note: 'Filtra prompt per parola chiave'},
193
+ {cmd: 'dvmi prompts download coding/refactor-prompt.md', note: 'Scarica un prompt localmente'},
194
+ {cmd: 'dvmi prompts browse skills --query refactor', note: 'Cerca skill su skills.sh'},
195
+ {cmd: 'dvmi prompts browse awesome --category agents', note: 'Sfoglia awesome-copilot agents'},
196
+ {cmd: 'dvmi prompts run coding/refactor-prompt.md --tool opencode', note: 'Esegui un prompt con opencode'},
197
+ {cmd: 'dvmi docs read', note: 'Leggi il README del repo corrente'},
198
+ {cmd: 'dvmi docs search "authentication"', note: 'Cerca nei docs del repo corrente'},
199
+ {cmd: 'dvmi repo list --search "api"', note: 'Filtra repository per nome'},
200
+ {cmd: 'dvmi pr status', note: 'PR aperte e review in attesa'},
201
+ {cmd: 'dvmi pipeline status', note: 'Ultimi workflow CI/CD'},
202
+ {cmd: 'dvmi tasks list --search "bug"', note: 'Cerca task ClickUp'},
203
+ {cmd: 'dvmi tasks today', note: 'Task in lavorazione oggi'},
204
+ {cmd: 'dvmi costs get --period mtd', note: 'Costi AWS mese corrente per servizio'},
205
+ {cmd: 'dvmi costs get --group-by tag --tag-key env', note: 'Costi raggruppati per tag env'},
206
+ {cmd: 'dvmi costs trend --line', note: 'Trend costi 2 mesi (grafico lineare)'},
207
+ {cmd: 'dvmi costs get --json', note: 'Costi AWS in formato JSON'},
208
+ {cmd: 'dvmi logs', note: 'Sfoglia log CloudWatch in modo interattivo'},
209
+ {cmd: 'dvmi logs --group /aws/lambda/my-fn --since 24h', note: 'Log Lambda ultimi 24h'},
210
+ {cmd: 'dvmi logs --group /aws/lambda/my-fn --filter "ERROR"', note: 'Filtra eventi ERROR su un log group'},
211
+ {cmd: 'dvmi security setup --json', note: 'Controlla lo stato degli strumenti di sicurezza'},
212
+ {cmd: 'dvmi security setup', note: 'Wizard interattivo: installa aws-vault e GCM'},
213
+ {cmd: 'dvmi dotfiles setup', note: 'Configura chezmoi con cifratura age'},
214
+ {cmd: 'dvmi dotfiles add ~/.zshrc ~/.gitconfig', note: 'Aggiungi dotfile a chezmoi'},
215
+ {cmd: 'dvmi dotfiles status --json', note: 'Stato dotfile gestiti (JSON)'},
216
+ {cmd: 'dvmi dotfiles sync --push', note: 'Push dotfile al repository remoto'},
217
+ {cmd: 'dvmi welcome', note: 'Dashboard missione dvmi con intro animata'},
218
+ {cmd: 'dvmi vuln search openssl', note: 'Cerca CVE recenti per keyword'},
219
+ {cmd: 'dvmi vuln search log4j --days 30 --severity critical', note: 'CVE critiche Log4j negli ultimi 30 giorni'},
220
+ {cmd: 'dvmi vuln detail CVE-2021-44228', note: 'Dettaglio completo di una CVE'},
221
+ {cmd: 'dvmi vuln detail CVE-2021-44228 --open', note: 'Apri la prima referenza nel browser'},
222
+ {cmd: 'dvmi vuln scan', note: 'Scansiona dipendenze del progetto corrente'},
223
+ {cmd: 'dvmi vuln scan --severity high --no-fail', note: 'Scansione senza bloccare CI (solo high+)'},
224
+ {cmd: 'dvmi vuln scan --report ./vuln-report.md', note: 'Esporta report Markdown delle vulnerabilità'},
227
225
  ]
228
226
 
229
227
  const lines = []
230
228
 
231
- // ── Usage ──────────────────────────────────────────────────────────────
232
- lines.push(this.#sectionHeader('USAGE'))
233
- lines.push(
234
- ' ' + (isColorEnabled ? chalk.hex(ORANGE).bold('dvmi') : 'dvmi') +
235
- chalk.dim(' <COMANDO> [FLAGS]\n'),
236
- )
229
+ // ── Usage ──────────────────────────────────────────────────────────────
230
+ lines.push(this.#sectionHeader('USAGE'))
231
+ lines.push(' ' + (isColorEnabled ? chalk.hex(ORANGE).bold('dvmi') : 'dvmi') + chalk.dim(' <COMANDO> [FLAGS]\n'))
237
232
 
238
233
  // ── Comandi per categoria ──────────────────────────────────────────────
239
234
  lines.push(this.#sectionHeader('COMMANDS'))
240
235
 
241
236
  for (const cat of CATEGORIES) {
242
- lines.push(
243
- ' ' + (isColorEnabled ? chalk.hex(ORANGE).bold(cat.title) : cat.title),
244
- )
237
+ lines.push(' ' + (isColorEnabled ? chalk.hex(ORANGE).bold(cat.title) : cat.title))
245
238
 
246
239
  for (const entry of cat.cmds) {
247
240
  const cmd = cmdMap.get(entry.id)
@@ -249,17 +242,14 @@ export default class CustomHelp extends Help {
249
242
 
250
243
  const displayId = entry.id.replaceAll(':', ' ')
251
244
  const hint = entry.hint || ''
252
- const desc = cmd.summary ?? (typeof cmd.description === 'string'
253
- ? cmd.description.split('\n')[0]
254
- : '')
245
+ const desc = cmd.summary ?? (typeof cmd.description === 'string' ? cmd.description.split('\n')[0] : '')
255
246
 
256
247
  // Left column (name + flags hint), right-padded to align descriptions
257
248
  const rawLeft = ' ' + displayId + (hint ? ' ' + hint : '')
258
249
  const pad = ' '.repeat(Math.max(2, 50 - rawLeft.length))
259
250
 
260
251
  const leftPart = isColorEnabled
261
- ? ' ' + chalk.hex(LIGHT_ORANGE).bold(displayId) +
262
- (hint ? ' ' + chalk.dim(hint) : '')
252
+ ? ' ' + chalk.hex(LIGHT_ORANGE).bold(displayId) + (hint ? ' ' + chalk.dim(hint) : '')
263
253
  : rawLeft
264
254
 
265
255
  lines.push(leftPart + pad + chalk.dim(desc))
@@ -270,8 +260,8 @@ export default class CustomHelp extends Help {
270
260
 
271
261
  // ── Flag globali ───────────────────────────────────────────────────────
272
262
  lines.push(this.#sectionHeader('GLOBAL FLAGS'))
273
- lines.push(this.#flagLine('-h, --help', 'Mostra aiuto per un comando'))
274
- lines.push(this.#flagLine(' --json', 'Output in formato JSON strutturato'))
263
+ lines.push(this.#flagLine('-h, --help', 'Mostra aiuto per un comando'))
264
+ lines.push(this.#flagLine(' --json', 'Output in formato JSON strutturato'))
275
265
  lines.push(this.#flagLine('-v, --version', 'Versione installata'))
276
266
  lines.push('')
277
267
 
@@ -281,39 +271,49 @@ export default class CustomHelp extends Help {
281
271
  const maxCmdLen = Math.max(...EXAMPLES.map((e) => e.cmd.length))
282
272
  for (const ex of EXAMPLES) {
283
273
  const pad = ' '.repeat(maxCmdLen - ex.cmd.length + 4)
284
- const sub = ex.cmd.replace(/^dvmi /, '')
285
- const formatted = isColorEnabled
286
- ? chalk.dim('$') + ' ' + chalk.hex(ORANGE).bold('dvmi') + ' ' +
287
- chalk.white(sub) + pad + chalk.hex(DIM_GRAY)(ex.note)
288
- : '$ ' + ex.cmd + pad + ex.note
274
+ const sub = ex.cmd.replace(/^dvmi /, '')
275
+ const formatted = isColorEnabled
276
+ ? chalk.dim('$') +
277
+ ' ' +
278
+ chalk.hex(ORANGE).bold('dvmi') +
279
+ ' ' +
280
+ chalk.white(sub) +
281
+ pad +
282
+ chalk.hex(DIM_GRAY)(ex.note)
283
+ : '$ ' + ex.cmd + pad + ex.note
289
284
  lines.push(' ' + formatted)
290
285
  }
291
286
 
292
- lines.push('')
293
-
294
- // ── Versione + update notice ───────────────────────────────────────────
295
- const current = versionInfo?.current ?? this.config.version
296
- const versionStr = isColorEnabled
297
- ? chalk.dim('version ') + chalk.hex(DIM_BLUE)(current)
298
- : `version ${current}`
299
-
300
- if (versionInfo?.hasUpdate && versionInfo.latest) {
301
- const updateStr = isColorEnabled
302
- ? chalk.yellow('update disponibile: ') +
303
- chalk.dim(current) + chalk.yellow(' → ') + chalk.green(versionInfo.latest) +
304
- chalk.dim(' (esegui ') + chalk.hex(LIGHT_ORANGE)('dvmi upgrade') + chalk.dim(')')
305
- : `update disponibile: ${current} → ${versionInfo.latest} (esegui dvmi upgrade)`
306
- lines.push(' ' + versionStr + chalk.dim(' · ') + updateStr)
307
- } else {
308
- lines.push(' ' + versionStr)
309
- }
310
-
311
- lines.push(
312
- ' ' + chalk.dim('Approfondisci:') + ' ' +
313
- chalk.hex(DIM_BLUE)('dvmi <COMANDO> --help') +
314
- chalk.dim(' · ') +
315
- chalk.hex(DIM_BLUE)('dvmi <TOPIC> --help') + '\n',
316
- )
287
+ lines.push('')
288
+
289
+ // ── Versione + update notice ───────────────────────────────────────────
290
+ const current = versionInfo?.current ?? this.config.version
291
+ const versionStr = isColorEnabled ? chalk.dim('version ') + chalk.hex(DIM_BLUE)(current) : `version ${current}`
292
+
293
+ if (versionInfo?.hasUpdate && versionInfo.latest) {
294
+ const updateStr = isColorEnabled
295
+ ? chalk.yellow('update disponibile: ') +
296
+ chalk.dim(current) +
297
+ chalk.yellow(' ') +
298
+ chalk.green(versionInfo.latest) +
299
+ chalk.dim(' (esegui ') +
300
+ chalk.hex(LIGHT_ORANGE)('dvmi upgrade') +
301
+ chalk.dim(')')
302
+ : `update disponibile: ${current} ${versionInfo.latest} (esegui dvmi upgrade)`
303
+ lines.push(' ' + versionStr + chalk.dim(' · ') + updateStr)
304
+ } else {
305
+ lines.push(' ' + versionStr)
306
+ }
307
+
308
+ lines.push(
309
+ ' ' +
310
+ chalk.dim('Approfondisci:') +
311
+ ' ' +
312
+ chalk.hex(DIM_BLUE)('dvmi <COMANDO> --help') +
313
+ chalk.dim(' · ') +
314
+ chalk.hex(DIM_BLUE)('dvmi <TOPIC> --help') +
315
+ '\n',
316
+ )
317
317
 
318
318
  return lines.join('\n')
319
319
  }
@@ -379,12 +379,10 @@ export default class CustomHelp extends Help {
379
379
  const plain = strip(line)
380
380
  if (!plain.trim()) return line
381
381
 
382
- // Example lines: "$ dvmi …"
383
- if (plain.includes('$ dvmi') || plain.trim().startsWith('$ dvmi')) {
384
- return plain.replace(/\$ (dvmi\S*)/g, (_, cmd) =>
385
- '$ ' + chalk.hex(ORANGE).bold(cmd),
386
- )
387
- }
382
+ // Example lines: "$ dvmi …"
383
+ if (plain.includes('$ dvmi') || plain.trim().startsWith('$ dvmi')) {
384
+ return plain.replace(/\$ (dvmi\S*)/g, (_, cmd) => '$ ' + chalk.hex(ORANGE).bold(cmd))
385
+ }
388
386
 
389
387
  // Flag rows: "--flag desc" or "-f, --flag desc"
390
388
  const flagMatch = plain.match(/^(\s{2,})((?:-\w,\s*)?--[\w-]+)(\s+)(.*)$/)
package/src/hooks/init.js CHANGED
@@ -3,7 +3,5 @@
3
3
  */
4
4
  export const init = async () => {
5
5
  // Fire-and-forget version check — result used by postrun hook
6
- import('../services/version-check.js')
7
- .then(({ checkForUpdate }) => checkForUpdate())
8
- .catch(() => null) // never block command execution
6
+ import('../services/version-check.js').then(({checkForUpdate}) => checkForUpdate()).catch(() => null) // never block command execution
9
7
  }
@@ -5,13 +5,11 @@ import chalk from 'chalk'
5
5
  */
6
6
  export const postrun = async () => {
7
7
  try {
8
- const { checkForUpdate } = await import('../services/version-check.js')
9
- const { hasUpdate, current, latest } = await checkForUpdate()
10
- if (hasUpdate && latest) {
11
- process.stderr.write(
12
- chalk.dim(`\nUpdate available: ${current} → ${chalk.green(latest)}. Run \`dvmi upgrade\`\n`),
13
- )
14
- }
8
+ const {checkForUpdate} = await import('../services/version-check.js')
9
+ const {hasUpdate, current, latest} = await checkForUpdate()
10
+ if (hasUpdate && latest) {
11
+ process.stderr.write(chalk.dim(`\nUpdate available: ${current} → ${chalk.green(latest)}. Run \`dvmi upgrade\`\n`))
12
+ }
15
13
  } catch {
16
14
  // Never interrupt user flow
17
15
  }
package/src/index.js CHANGED
@@ -1 +1 @@
1
- export { run } from '@oclif/core'
1
+ export {run} from '@oclif/core'