devvami 1.4.2 → 1.5.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/README.md +7 -0
- package/oclif.manifest.json +129 -89
- package/package.json +2 -1
- package/src/commands/auth/login.js +20 -16
- package/src/commands/changelog.js +12 -12
- package/src/commands/costs/get.js +14 -24
- package/src/commands/costs/trend.js +13 -24
- package/src/commands/create/repo.js +72 -54
- package/src/commands/docs/list.js +29 -25
- package/src/commands/docs/projects.js +58 -24
- package/src/commands/docs/read.js +56 -39
- package/src/commands/docs/search.js +37 -25
- package/src/commands/doctor.js +37 -35
- package/src/commands/dotfiles/add.js +51 -39
- package/src/commands/dotfiles/setup.js +62 -33
- package/src/commands/dotfiles/status.js +18 -18
- package/src/commands/dotfiles/sync.js +62 -46
- package/src/commands/init.js +143 -132
- package/src/commands/logs/index.js +10 -16
- package/src/commands/open.js +12 -12
- package/src/commands/pipeline/logs.js +8 -11
- package/src/commands/pipeline/rerun.js +21 -16
- package/src/commands/pipeline/status.js +28 -24
- package/src/commands/pr/create.js +40 -27
- package/src/commands/pr/detail.js +9 -7
- package/src/commands/pr/review.js +18 -19
- package/src/commands/pr/status.js +27 -21
- package/src/commands/prompts/browse.js +15 -15
- package/src/commands/prompts/download.js +15 -16
- package/src/commands/prompts/install-speckit.js +11 -12
- package/src/commands/prompts/list.js +12 -12
- package/src/commands/prompts/run.js +16 -19
- package/src/commands/repo/list.js +57 -41
- package/src/commands/search.js +20 -18
- package/src/commands/security/setup.js +38 -34
- package/src/commands/sync-config-ai/index.js +143 -0
- package/src/commands/tasks/assigned.js +43 -33
- package/src/commands/tasks/list.js +43 -33
- package/src/commands/tasks/today.js +32 -30
- package/src/commands/upgrade.js +18 -17
- package/src/commands/vuln/detail.js +8 -8
- package/src/commands/vuln/scan.js +39 -20
- package/src/commands/vuln/search.js +23 -18
- package/src/commands/welcome.js +2 -2
- package/src/commands/whoami.js +19 -23
- package/src/formatters/ai-config.js +127 -0
- package/src/formatters/charts.js +6 -23
- package/src/formatters/cost.js +1 -7
- package/src/formatters/dotfiles.js +48 -19
- package/src/formatters/markdown.js +11 -6
- package/src/formatters/openapi.js +7 -9
- package/src/formatters/prompts.js +69 -78
- package/src/formatters/security.js +2 -2
- package/src/formatters/status.js +1 -1
- package/src/formatters/table.js +1 -3
- package/src/formatters/vuln.js +33 -20
- package/src/help.js +162 -164
- package/src/hooks/init.js +1 -3
- package/src/hooks/postrun.js +5 -7
- package/src/index.js +1 -1
- package/src/services/ai-config-store.js +318 -0
- package/src/services/ai-env-deployer.js +444 -0
- package/src/services/ai-env-scanner.js +242 -0
- package/src/services/audit-detector.js +2 -2
- package/src/services/audit-runner.js +40 -31
- package/src/services/auth.js +9 -9
- package/src/services/awesome-copilot.js +7 -4
- package/src/services/aws-costs.js +22 -22
- package/src/services/clickup.js +26 -26
- package/src/services/cloudwatch-logs.js +5 -9
- package/src/services/config.js +13 -13
- package/src/services/docs.js +19 -20
- package/src/services/dotfiles.js +149 -51
- package/src/services/github.js +22 -24
- package/src/services/nvd.js +21 -31
- package/src/services/platform.js +2 -2
- package/src/services/prompts.js +23 -35
- package/src/services/security.js +135 -61
- package/src/services/shell.js +4 -4
- package/src/services/skills-sh.js +3 -9
- package/src/services/speckit.js +4 -7
- package/src/services/version-check.js +10 -10
- package/src/types.js +85 -0
- package/src/utils/aws-vault.js +18 -41
- package/src/utils/banner.js +5 -7
- package/src/utils/errors.js +42 -46
- package/src/utils/frontmatter.js +4 -4
- package/src/utils/gradient.js +18 -16
- package/src/utils/open-browser.js +3 -3
- package/src/utils/tui/form.js +1006 -0
- package/src/utils/tui/modal.js +15 -14
- package/src/utils/tui/navigable-table.js +16 -16
- package/src/utils/tui/tab-tui.js +800 -0
- package/src/utils/typewriter.js +3 -3
- package/src/utils/welcome.js +18 -21
- package/src/validators/repo-name.js +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {load} from 'js-yaml'
|
|
2
2
|
|
|
3
3
|
/** @import { APIEndpoint, AsyncChannel } from '../types.js' */
|
|
4
4
|
|
|
@@ -45,7 +45,7 @@ export function isAsyncApi(doc) {
|
|
|
45
45
|
export function parseOpenApi(content) {
|
|
46
46
|
const doc = parseYamlOrJson(content)
|
|
47
47
|
if (!doc || !isOpenApi(doc)) {
|
|
48
|
-
return {
|
|
48
|
+
return {endpoints: [], error: 'Not a valid OpenAPI/Swagger document'}
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
/** @type {APIEndpoint[]} */
|
|
@@ -58,9 +58,7 @@ export function parseOpenApi(content) {
|
|
|
58
58
|
if (!['get', 'post', 'put', 'patch', 'delete', 'head', 'options'].includes(method)) continue
|
|
59
59
|
const operation = /** @type {Record<string, unknown>} */ (op)
|
|
60
60
|
const rawParams = /** @type {Array<Record<string, unknown>>} */ (operation.parameters ?? [])
|
|
61
|
-
const parameters = rawParams
|
|
62
|
-
.map((p) => (p.required ? `${p.name}*` : String(p.name)))
|
|
63
|
-
.join(', ')
|
|
61
|
+
const parameters = rawParams.map((p) => (p.required ? `${p.name}*` : String(p.name))).join(', ')
|
|
64
62
|
endpoints.push({
|
|
65
63
|
method: method.toUpperCase(),
|
|
66
64
|
path,
|
|
@@ -70,7 +68,7 @@ export function parseOpenApi(content) {
|
|
|
70
68
|
}
|
|
71
69
|
}
|
|
72
70
|
|
|
73
|
-
return {
|
|
71
|
+
return {endpoints, error: null}
|
|
74
72
|
}
|
|
75
73
|
|
|
76
74
|
/**
|
|
@@ -81,7 +79,7 @@ export function parseOpenApi(content) {
|
|
|
81
79
|
export function parseAsyncApi(content) {
|
|
82
80
|
const doc = parseYamlOrJson(content)
|
|
83
81
|
if (!doc || !isAsyncApi(doc)) {
|
|
84
|
-
return {
|
|
82
|
+
return {channels: [], error: 'Not a valid AsyncAPI document'}
|
|
85
83
|
}
|
|
86
84
|
|
|
87
85
|
/** @type {AsyncChannel[]} */
|
|
@@ -98,7 +96,7 @@ export function parseAsyncApi(content) {
|
|
|
98
96
|
return String(ch.$ref ?? '').includes(channelName) || String(ch ?? '') === channelName
|
|
99
97
|
})
|
|
100
98
|
if (matchingOps.length === 0) {
|
|
101
|
-
channels.push({
|
|
99
|
+
channels.push({channel: channelName, operation: '—', summary: '', message: '—'})
|
|
102
100
|
}
|
|
103
101
|
for (const op of matchingOps) {
|
|
104
102
|
const msgTitle = resolveMessageTitle(op.messages)
|
|
@@ -129,7 +127,7 @@ export function parseAsyncApi(content) {
|
|
|
129
127
|
}
|
|
130
128
|
}
|
|
131
129
|
|
|
132
|
-
return {
|
|
130
|
+
return {channels, error: null}
|
|
133
131
|
}
|
|
134
132
|
|
|
135
133
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import chalk from 'chalk'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import {marked} from 'marked'
|
|
3
|
+
import {renderTable} from './table.js'
|
|
4
4
|
|
|
5
5
|
/** @import { Prompt, Skill, AwesomeEntry } from '../types.js' */
|
|
6
6
|
|
|
@@ -16,31 +16,28 @@ export function formatPromptTable(prompts) {
|
|
|
16
16
|
return chalk.dim('No prompts found.')
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
return renderTable(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
},
|
|
42
|
-
],
|
|
43
|
-
)
|
|
19
|
+
return renderTable(/** @type {Record<string, unknown>[]} */ (prompts), [
|
|
20
|
+
{
|
|
21
|
+
header: 'Title',
|
|
22
|
+
key: 'title',
|
|
23
|
+
width: 36,
|
|
24
|
+
colorize: (v) => chalk.hex('#FF9A5C')(v),
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
header: 'Category',
|
|
28
|
+
key: 'category',
|
|
29
|
+
width: 16,
|
|
30
|
+
format: (v) => v ?? '—',
|
|
31
|
+
colorize: (v) => chalk.hex('#4A9EFF')(v),
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
header: 'Description',
|
|
35
|
+
key: 'description',
|
|
36
|
+
width: 60,
|
|
37
|
+
format: (v) => v ?? '—',
|
|
38
|
+
colorize: (v) => chalk.white(v),
|
|
39
|
+
},
|
|
40
|
+
])
|
|
44
41
|
}
|
|
45
42
|
|
|
46
43
|
/**
|
|
@@ -63,7 +60,7 @@ export function formatPromptBody(prompt) {
|
|
|
63
60
|
.join('\n')
|
|
64
61
|
|
|
65
62
|
// Render markdown to plain terminal text by stripping HTML tags from marked output
|
|
66
|
-
const rendered = marked(prompt.body, {
|
|
63
|
+
const rendered = marked(prompt.body, {async: false})
|
|
67
64
|
const plain = String(rendered)
|
|
68
65
|
.replace(/<[^>]+>/g, '')
|
|
69
66
|
.replace(/&/g, '&')
|
|
@@ -91,31 +88,28 @@ export function formatSkillTable(skills) {
|
|
|
91
88
|
return chalk.dim('No skills found.')
|
|
92
89
|
}
|
|
93
90
|
|
|
94
|
-
return renderTable(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
},
|
|
117
|
-
],
|
|
118
|
-
)
|
|
91
|
+
return renderTable(/** @type {Record<string, unknown>[]} */ (skills), [
|
|
92
|
+
{
|
|
93
|
+
header: 'Name',
|
|
94
|
+
key: 'name',
|
|
95
|
+
width: 36,
|
|
96
|
+
colorize: (v) => chalk.hex('#FF9A5C')(v),
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
header: 'Installs',
|
|
100
|
+
key: 'installs',
|
|
101
|
+
width: 10,
|
|
102
|
+
format: (v) => (v != null ? String(v) : '—'),
|
|
103
|
+
colorize: (v) => chalk.hex('#4A9EFF')(v),
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
header: 'Description',
|
|
107
|
+
key: 'description',
|
|
108
|
+
width: 60,
|
|
109
|
+
format: (v) => v ?? '—',
|
|
110
|
+
colorize: (v) => chalk.white(v),
|
|
111
|
+
},
|
|
112
|
+
])
|
|
119
113
|
}
|
|
120
114
|
|
|
121
115
|
/**
|
|
@@ -131,29 +125,26 @@ export function formatAwesomeTable(entries, category) {
|
|
|
131
125
|
return chalk.dim(category ? `No entries found for category "${category}".` : 'No entries found.')
|
|
132
126
|
}
|
|
133
127
|
|
|
134
|
-
return renderTable(
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
},
|
|
157
|
-
],
|
|
158
|
-
)
|
|
128
|
+
return renderTable(/** @type {Record<string, unknown>[]} */ (entries), [
|
|
129
|
+
{
|
|
130
|
+
header: 'Name',
|
|
131
|
+
key: 'name',
|
|
132
|
+
width: 36,
|
|
133
|
+
colorize: (v) => chalk.hex('#FF9A5C')(v),
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
header: 'Category',
|
|
137
|
+
key: 'category',
|
|
138
|
+
width: 14,
|
|
139
|
+
format: (v) => v ?? '—',
|
|
140
|
+
colorize: (v) => chalk.hex('#4A9EFF')(v),
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
header: 'Description',
|
|
144
|
+
key: 'description',
|
|
145
|
+
width: 58,
|
|
146
|
+
format: (v) => v ?? '—',
|
|
147
|
+
colorize: (v) => chalk.white(v),
|
|
148
|
+
},
|
|
149
|
+
])
|
|
159
150
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import chalk from 'chalk'
|
|
2
|
-
import {
|
|
2
|
+
import {deriveOverallStatus} from '../services/security.js'
|
|
3
3
|
|
|
4
4
|
/** @import { SetupSession, SecurityToolStatus, PlatformInfo } from '../types.js' */
|
|
5
5
|
|
|
@@ -116,4 +116,4 @@ export function formatSecuritySummary(session, platformInfo) {
|
|
|
116
116
|
* @param {SecurityToolStatus[]} tools
|
|
117
117
|
* @returns {'success'|'partial'|'not-configured'}
|
|
118
118
|
*/
|
|
119
|
-
export {
|
|
119
|
+
export {deriveOverallStatus}
|
package/src/formatters/status.js
CHANGED
package/src/formatters/table.js
CHANGED
|
@@ -51,9 +51,7 @@ export function renderTable(rows, columns) {
|
|
|
51
51
|
})
|
|
52
52
|
|
|
53
53
|
// Header row
|
|
54
|
-
const header = columns
|
|
55
|
-
.map((col, i) => chalk.bold.white(col.header.padEnd(widths[i])))
|
|
56
|
-
.join(' ')
|
|
54
|
+
const header = columns.map((col, i) => chalk.bold.white(col.header.padEnd(widths[i]))).join(' ')
|
|
57
55
|
|
|
58
56
|
// Divider
|
|
59
57
|
const divider = chalk.dim(widths.map((w) => '─'.repeat(w)).join(' '))
|
package/src/formatters/vuln.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import chalk from 'chalk'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import {renderTable} from './table.js'
|
|
3
|
+
import {NVD_ATTRIBUTION} from '../services/nvd.js'
|
|
4
4
|
|
|
5
5
|
/** @import { CveSearchResult, CveDetail, VulnerabilityFinding, ScanResult } from '../types.js' */
|
|
6
6
|
|
|
@@ -11,11 +11,16 @@ import { NVD_ATTRIBUTION } from '../services/nvd.js'
|
|
|
11
11
|
*/
|
|
12
12
|
export function colorSeverity(severity) {
|
|
13
13
|
switch (severity) {
|
|
14
|
-
case 'Critical':
|
|
15
|
-
|
|
16
|
-
case '
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
case 'Critical':
|
|
15
|
+
return chalk.red.bold(severity)
|
|
16
|
+
case 'High':
|
|
17
|
+
return chalk.red(severity)
|
|
18
|
+
case 'Medium':
|
|
19
|
+
return chalk.yellow(severity)
|
|
20
|
+
case 'Low':
|
|
21
|
+
return chalk.blue(severity)
|
|
22
|
+
default:
|
|
23
|
+
return chalk.gray(severity)
|
|
19
24
|
}
|
|
20
25
|
}
|
|
21
26
|
|
|
@@ -83,16 +88,21 @@ export function formatCveSearchTable(results, keyword, days, totalResults) {
|
|
|
83
88
|
}))
|
|
84
89
|
|
|
85
90
|
const table = renderTable(rows, [
|
|
86
|
-
{
|
|
87
|
-
{
|
|
88
|
-
{
|
|
89
|
-
{
|
|
90
|
-
{
|
|
91
|
-
{
|
|
91
|
+
{header: 'CVE ID', key: 'id', colorize: (v) => chalk.cyan(v)},
|
|
92
|
+
{header: 'Severity', key: 'severity', colorize: (v) => colorSeverity(v)},
|
|
93
|
+
{header: 'Score', key: 'score', width: 5},
|
|
94
|
+
{header: 'Published', key: 'published', width: 10},
|
|
95
|
+
{header: 'Description', key: 'description', width: 90},
|
|
96
|
+
{header: 'Reference', key: 'reference', width: 45},
|
|
92
97
|
])
|
|
93
98
|
|
|
94
99
|
// Indent table by 2 spaces
|
|
95
|
-
lines.push(
|
|
100
|
+
lines.push(
|
|
101
|
+
table
|
|
102
|
+
.split('\n')
|
|
103
|
+
.map((l) => ` ${l}`)
|
|
104
|
+
.join('\n'),
|
|
105
|
+
)
|
|
96
106
|
lines.push('')
|
|
97
107
|
lines.push(`Showing ${results.length} of ${totalResults} results.`)
|
|
98
108
|
lines.push(chalk.dim(NVD_ATTRIBUTION))
|
|
@@ -250,14 +260,17 @@ export function formatFindingsTable(findings) {
|
|
|
250
260
|
}))
|
|
251
261
|
|
|
252
262
|
const table = renderTable(rows, [
|
|
253
|
-
{
|
|
254
|
-
{
|
|
255
|
-
{
|
|
256
|
-
{
|
|
257
|
-
{
|
|
263
|
+
{header: 'Package', key: 'pkg', width: 20},
|
|
264
|
+
{header: 'Version', key: 'version', width: 12},
|
|
265
|
+
{header: 'Severity', key: 'severity', colorize: (v) => colorSeverity(v)},
|
|
266
|
+
{header: 'CVE', key: 'cve', colorize: (v) => (v !== '—' ? chalk.cyan(v) : chalk.gray(v))},
|
|
267
|
+
{header: 'Title', key: 'title', width: 40},
|
|
258
268
|
])
|
|
259
269
|
|
|
260
|
-
return table
|
|
270
|
+
return table
|
|
271
|
+
.split('\n')
|
|
272
|
+
.map((l) => ` ${l}`)
|
|
273
|
+
.join('\n')
|
|
261
274
|
}
|
|
262
275
|
|
|
263
276
|
/**
|