devvami 1.1.1 → 1.2.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/oclif.manifest.json +180 -117
- package/package.json +1 -1
- package/src/commands/init.js +4 -2
- package/src/commands/prompts/run.js +19 -1
- package/src/commands/security/setup.js +249 -0
- package/src/commands/welcome.js +17 -0
- package/src/formatters/security.js +119 -0
- package/src/help.js +8 -0
- package/src/services/clickup.js +9 -3
- package/src/services/docs.js +5 -1
- package/src/services/prompts.js +2 -2
- package/src/services/security.js +634 -0
- package/src/types.js +66 -0
- package/src/utils/welcome.js +173 -0
package/src/types.js
CHANGED
|
@@ -260,3 +260,69 @@
|
|
|
260
260
|
* @property {string} owner - GitHub owner (org or user)
|
|
261
261
|
* @property {string} repo - Repository name
|
|
262
262
|
*/
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* @typedef {Object} SecurityTool
|
|
266
|
+
* @property {string} id - Unique identifier (e.g., "aws-vault", "pass", "gpg", "gcm", "osxkeychain")
|
|
267
|
+
* @property {string} displayName - Human-readable name for UI output
|
|
268
|
+
* @property {'aws'|'git'|'dependency'} role - What the tool protects; 'dependency' = required by another tool
|
|
269
|
+
* @property {'not-installed'|'installed'|'misconfigured'|'skipped'|'n/a'} status - Status after check phase
|
|
270
|
+
* @property {Platform[]} platforms - Platforms where this tool applies
|
|
271
|
+
* @property {string|null} version - Detected version string, if available
|
|
272
|
+
* @property {string|null} hint - Actionable message when status is 'misconfigured' or 'not-installed'
|
|
273
|
+
*/
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* @typedef {Object} SetupStep
|
|
277
|
+
* @property {string} id - Unique step identifier (e.g., "install-aws-vault", "init-pass")
|
|
278
|
+
* @property {string} label - Human-readable description shown to the developer
|
|
279
|
+
* @property {string} toolId - The SecurityTool this step belongs to
|
|
280
|
+
* @property {'check'|'install'|'configure'|'verify'} type - Step category
|
|
281
|
+
* @property {() => Promise<StepResult>} run - Async function that executes the step
|
|
282
|
+
* @property {boolean} requiresConfirmation - True for 'install' and 'configure' steps
|
|
283
|
+
* @property {boolean} [skippable] - True if the developer can skip this step without breaking subsequent steps
|
|
284
|
+
* @property {boolean} [gpgInteractive] - True if the step spawns GPG interactively (requires stdio:inherit)
|
|
285
|
+
*/
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* @typedef {Object} StepResult
|
|
289
|
+
* @property {'success'|'skipped'|'failed'} status
|
|
290
|
+
* @property {string} [message] - Human-readable outcome message
|
|
291
|
+
* @property {string} [hint] - Actionable recovery suggestion shown only when status is 'failed'
|
|
292
|
+
* @property {string} [hintUrl] - Documentation URL to include with the hint
|
|
293
|
+
*/
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* @typedef {Object} SetupSession
|
|
297
|
+
* @property {Platform} platform - Detected platform for this run
|
|
298
|
+
* @property {'aws'|'git'|'both'} selection - What the developer chose to set up
|
|
299
|
+
* @property {SetupStep[]} steps - Ordered list of steps for this session
|
|
300
|
+
* @property {Map<string, StepResult>} results - Map of stepId → StepResult
|
|
301
|
+
* @property {'in-progress'|'completed'|'failed'|'cancelled'} overallStatus - Aggregate status
|
|
302
|
+
*/
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* @typedef {Object} GpgKey
|
|
306
|
+
* @property {string} id - Long key ID (16-character hex)
|
|
307
|
+
* @property {string} fingerprint - Full 40-character fingerprint
|
|
308
|
+
* @property {string} name - Associated name from the key's UID
|
|
309
|
+
* @property {string} email - Associated email from the key's UID
|
|
310
|
+
* @property {string|null} expiry - Expiry date as ISO8601 string, or null if no expiry
|
|
311
|
+
*/
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* @typedef {Object} SecurityToolStatus
|
|
315
|
+
* @property {string} id - Tool id
|
|
316
|
+
* @property {string} displayName - Human-readable name
|
|
317
|
+
* @property {'not-installed'|'installed'|'misconfigured'|'n/a'} status - Current status
|
|
318
|
+
* @property {string|null} version - Detected version, if any
|
|
319
|
+
* @property {string|null} hint - Recovery hint if misconfigured
|
|
320
|
+
*/
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* @typedef {Object} SecuritySetupJsonResult
|
|
324
|
+
* @property {Platform} platform - Detected platform
|
|
325
|
+
* @property {'aws'|'git'|'both'|null} selection - Selection made (null for --json health check)
|
|
326
|
+
* @property {SecurityToolStatus[]} tools - Status of each applicable tool
|
|
327
|
+
* @property {'success'|'partial'|'not-configured'} overallStatus - Aggregate status
|
|
328
|
+
*/
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import chalk from 'chalk'
|
|
2
|
+
import { printBanner } from './banner.js'
|
|
3
|
+
import { isColorEnabled } from './gradient.js'
|
|
4
|
+
import { typewriterLine } from './typewriter.js'
|
|
5
|
+
|
|
6
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
7
|
+
|
|
8
|
+
const STAGGER = 150
|
|
9
|
+
const delay = (ms) => new Promise((r) => setTimeout(r, ms))
|
|
10
|
+
const out = (line) => process.stdout.write(line + '\n')
|
|
11
|
+
const nl = () => process.stdout.write('\n')
|
|
12
|
+
|
|
13
|
+
// ─── Color palette ────────────────────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
const p = isColorEnabled
|
|
16
|
+
? {
|
|
17
|
+
sep: (t) => chalk.hex('#4A9EFF').dim(t),
|
|
18
|
+
cyan: (t) => chalk.hex('#00D4FF').bold(t),
|
|
19
|
+
green: (t) => chalk.hex('#00FF88').bold(t),
|
|
20
|
+
pink: (t) => chalk.hex('#FF3399').bold(t),
|
|
21
|
+
gold: (t) => chalk.hex('#FFD700').bold(t),
|
|
22
|
+
orange: (t) => chalk.hex('#FF6B2B').bold(t),
|
|
23
|
+
blue: (t) => chalk.hex('#4A9EFF')(t),
|
|
24
|
+
white: (t) => chalk.white(t),
|
|
25
|
+
dim: (t) => chalk.dim(t),
|
|
26
|
+
}
|
|
27
|
+
: Object.fromEntries(
|
|
28
|
+
['sep', 'cyan', 'green', 'pink', 'gold', 'orange', 'blue', 'white', 'dim'].map((k) => [
|
|
29
|
+
k,
|
|
30
|
+
(t) => t,
|
|
31
|
+
]),
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Build a ruler-style section header.
|
|
38
|
+
* Example: " 🔐 SUPPLY CHAIN SECURITY ──────────────────────────────"
|
|
39
|
+
* No right-side border: dashes trail right, no alignment required.
|
|
40
|
+
*
|
|
41
|
+
* @param {string} icon
|
|
42
|
+
* @param {string} label
|
|
43
|
+
* @param {(t: string) => string} colorFn
|
|
44
|
+
* @returns {string}
|
|
45
|
+
*/
|
|
46
|
+
function ruler(icon, label, colorFn) {
|
|
47
|
+
return colorFn(` ${icon} ${label} `) + p.sep('─'.repeat(40))
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ─── Welcome screen ───────────────────────────────────────────────────────────
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Print the full cyberpunk dvmi welcome screen.
|
|
54
|
+
* Shows the animated DVMI logo followed by a styled mission dashboard.
|
|
55
|
+
* Falls back to plain text in non-TTY / NO_COLOR / CI environments.
|
|
56
|
+
*
|
|
57
|
+
* @param {string} [version=''] - CLI version string (e.g. '2.1.0')
|
|
58
|
+
* @returns {Promise<void>}
|
|
59
|
+
*/
|
|
60
|
+
export async function printWelcomeScreen(version = '') {
|
|
61
|
+
// ── 1. Animated DVMI logo ──────────────────────────────────────────────────
|
|
62
|
+
await printBanner()
|
|
63
|
+
|
|
64
|
+
// ── 2. Badge line (typewriter with brand gradient) ─────────────────────────
|
|
65
|
+
const versionTag = version ? `v${version} · ` : ''
|
|
66
|
+
await typewriterLine(` ◆ Developer Mission Interface · ${versionTag}Node >= 24`)
|
|
67
|
+
|
|
68
|
+
// ── 3. Connection established ──────────────────────────────────────────────
|
|
69
|
+
await delay(STAGGER)
|
|
70
|
+
nl()
|
|
71
|
+
out(p.sep(' ' + '─'.repeat(72)))
|
|
72
|
+
nl()
|
|
73
|
+
out(p.cyan(' LINK ESTABLISHED'))
|
|
74
|
+
nl()
|
|
75
|
+
out(p.white(' dvmi consolidates the operational surface of modern software delivery into'))
|
|
76
|
+
out(p.white(' one deterministic CLI experience. Instead of context switching across browser'))
|
|
77
|
+
out(p.white(' tabs, dashboards, and disconnected tools, you run critical workflows from a'))
|
|
78
|
+
out(p.white(' single terminal interface: consistent output, predictable behavior, full control.'))
|
|
79
|
+
|
|
80
|
+
// ── 4. Mission profile ─────────────────────────────────────────────────────
|
|
81
|
+
await delay(STAGGER)
|
|
82
|
+
nl()
|
|
83
|
+
out(ruler('⚙️ ', 'MISSION PROFILE :: WHAT THIS CLI DOES', p.cyan))
|
|
84
|
+
nl()
|
|
85
|
+
const mission = [
|
|
86
|
+
'discover and manage repositories across your GitHub organization',
|
|
87
|
+
'handle pull requests with faster review and decision flow',
|
|
88
|
+
'monitor CI/CD pipelines, inspect failures, rerun with intent',
|
|
89
|
+
'query and read technical documentation without leaving the shell',
|
|
90
|
+
'track execution priorities through task-oriented commands',
|
|
91
|
+
'inspect cloud costs early, before budget drift becomes an incident',
|
|
92
|
+
]
|
|
93
|
+
for (const line of mission) {
|
|
94
|
+
out(p.dim(' - ') + p.white(line))
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ── 5. Supply chain security ───────────────────────────────────────────────
|
|
98
|
+
await delay(STAGGER)
|
|
99
|
+
nl()
|
|
100
|
+
out(ruler('🔐', "SUPPLY CHAIN SECURITY :: VERIFY, DON'T GUESS", p.green))
|
|
101
|
+
nl()
|
|
102
|
+
out(p.dim(' dvmi takes a security-first but pragmatic approach to software delivery:'))
|
|
103
|
+
nl()
|
|
104
|
+
const security = [
|
|
105
|
+
'artifact integrity and provenance-aware delivery workflow',
|
|
106
|
+
'dependency visibility with an SBOM mindset (SPDX / CycloneDX)',
|
|
107
|
+
'continuous hygiene on dependency risk and secret exposure',
|
|
108
|
+
'credential management via OS-native secure storage (keychain)',
|
|
109
|
+
'less improvised shell procedures, more repeatable safe operations',
|
|
110
|
+
]
|
|
111
|
+
for (const line of security) {
|
|
112
|
+
out(p.green(' ▸ ') + p.white(line))
|
|
113
|
+
}
|
|
114
|
+
nl()
|
|
115
|
+
out(p.dim(' Objective: reduce the risk surface without slowing down delivery.'))
|
|
116
|
+
|
|
117
|
+
// ── 6. DevEx high-velocity ─────────────────────────────────────────────────
|
|
118
|
+
await delay(STAGGER)
|
|
119
|
+
nl()
|
|
120
|
+
out(ruler('⚡', 'DEVEX HIGH-VELOCITY :: STAY IN FLOW', p.pink))
|
|
121
|
+
nl()
|
|
122
|
+
out(p.dim(' dvmi is designed to lower cognitive cost and keep you in flow:'))
|
|
123
|
+
nl()
|
|
124
|
+
const devex = [
|
|
125
|
+
'less context switching between tools and dashboards',
|
|
126
|
+
'less time spent hunting down "where did this break"',
|
|
127
|
+
'faster "what is blocked / what is next" decision loops',
|
|
128
|
+
'scriptable, composable output for automation and team workflows',
|
|
129
|
+
]
|
|
130
|
+
for (const line of devex) {
|
|
131
|
+
out(p.pink(' ▸ ') + p.white(line))
|
|
132
|
+
}
|
|
133
|
+
nl()
|
|
134
|
+
out(p.dim(' No noise added. Operational signal only.'))
|
|
135
|
+
|
|
136
|
+
// ── 7. Delivery reliability ────────────────────────────────────────────────
|
|
137
|
+
await delay(STAGGER)
|
|
138
|
+
nl()
|
|
139
|
+
out(ruler('📡', 'DELIVERY RELIABILITY :: SHIP WITH CONTROL', p.orange))
|
|
140
|
+
nl()
|
|
141
|
+
out(p.white(' From PR readiness to pipeline health to release confidence,'))
|
|
142
|
+
out(p.white(' dvmi moves teams from reactive debugging to proactive control.'))
|
|
143
|
+
nl()
|
|
144
|
+
out(p.white(' Reliability is treated as a habit, not a phase.'))
|
|
145
|
+
|
|
146
|
+
// ── 8. Boot sequence ───────────────────────────────────────────────────────
|
|
147
|
+
await delay(STAGGER)
|
|
148
|
+
nl()
|
|
149
|
+
out(ruler('🚀', 'BOOT SEQUENCE', p.gold))
|
|
150
|
+
nl()
|
|
151
|
+
|
|
152
|
+
/** @type {Array<[string, string]>} */
|
|
153
|
+
const commands = [
|
|
154
|
+
['dvmi init', 'configure your workspace'],
|
|
155
|
+
['dvmi auth login', 'connect GitHub & ClickUp'],
|
|
156
|
+
['dvmi pr status', 'open pull requests'],
|
|
157
|
+
['dvmi pipeline status', 'CI/CD health check'],
|
|
158
|
+
['dvmi tasks today', 'focus mode: what to ship today'],
|
|
159
|
+
['dvmi costs get', 'AWS bill reality check'],
|
|
160
|
+
['dvmi doctor', 'diagnose config issues'],
|
|
161
|
+
]
|
|
162
|
+
for (const [cmd, comment] of commands) {
|
|
163
|
+
out(' ' + p.blue('$ ' + cmd.padEnd(24)) + p.dim('# ' + comment))
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ── 9. Closing ─────────────────────────────────────────────────────────────
|
|
167
|
+
await delay(STAGGER)
|
|
168
|
+
nl()
|
|
169
|
+
out(p.sep(' ' + '─'.repeat(72)))
|
|
170
|
+
nl()
|
|
171
|
+
out(p.dim(' DVMI PROTOCOL: ') + p.cyan('Ship fast. Verify everything.'))
|
|
172
|
+
nl()
|
|
173
|
+
}
|