@ngocsangairvds/vsaf 4.1.5 → 4.1.7
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/package.json +1 -1
- package/skills/vds-skill/_shared/config-check.js +3 -3
- package/skills/vds-skill/_shared/credentials.js +1 -1
- package/skills/vds-skill/create-bitbucket-pr/SKILL.md +3 -3
- package/skills/vds-skill/create-bitbucket-pr/scripts/create-pr.js +1 -1
- package/skills/vds-skill/create-jira-epic/SKILL.md +3 -3
- package/skills/vds-skill/create-jira-epic/scripts/create-epic.js +1 -1
- package/skills/vds-skill/install-deps.mjs +74 -23
- package/skills/vds-skill/push-prd/SKILL.md +2 -2
- package/skills/vds-skill/push-srs/SKILL.md +2 -2
- package/skills/vds-skill/search-confluence/SKILL.md +2 -2
- package/skills/vds-skill/search-confluence/scripts/search.js +2 -2
- package/skills/vds-skill/vds-scripts-skill/SKILL.md +11 -8
package/package.json
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
* config-check.js — reusable pre-flight checker for vds-skill-* SKILL.md files.
|
|
6
6
|
*
|
|
7
7
|
* Usage:
|
|
8
|
-
* node config-check.js --cmd vds-cli --env
|
|
8
|
+
* node config-check.js --cmd vds-cli --env INTERNAL_CONFLUENCE_TOKEN
|
|
9
9
|
*
|
|
10
10
|
* Output (matches legacy bash format):
|
|
11
11
|
* OK — all checks pass
|
|
12
|
-
* BLOCKED — missing: vds-cli
|
|
12
|
+
* BLOCKED — missing: vds-cli JIRA_TOKEN — something missing
|
|
13
13
|
* NOTE: /path/to/cmd exists but fails to run — broken shim detected
|
|
14
14
|
*/
|
|
15
15
|
|
|
@@ -72,5 +72,5 @@ if (missing.length === 0) {
|
|
|
72
72
|
console.log('OK');
|
|
73
73
|
} else {
|
|
74
74
|
console.log(`BLOCKED — missing: ${missing.join(' ')}`);
|
|
75
|
-
console.log('Fix: edit ~/.vds
|
|
75
|
+
console.log('Fix: edit ~/.vds/.env (or run: vsaf install vds-skill)');
|
|
76
76
|
}
|
|
@@ -9,7 +9,7 @@ const { execFileSync } = require('child_process');
|
|
|
9
9
|
const IS_WIN = process.platform === 'win32';
|
|
10
10
|
|
|
11
11
|
function getConfigPath() {
|
|
12
|
-
return process.env.VSAF_CONFIG_FILE || join(homedir(), '.vds', '
|
|
12
|
+
return process.env.VSAF_CONFIG_FILE || join(homedir(), '.vds', '.env');
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
function parseEnvFile(filePath) {
|
|
@@ -12,7 +12,7 @@ Create a Bitbucket PR on Viettel internal Bitbucket via `vds-cli`.
|
|
|
12
12
|
Before doing anything, run this check via Bash tool:
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
node .claude/skills/_shared/vds-skill/config-check.js --cmd vds-cli --env
|
|
15
|
+
node .claude/skills/_shared/vds-skill/config-check.js --cmd vds-cli --env BITBUCKET_TOKEN
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
If BLOCKED: tell the user exactly what's missing and how to fix, then STOP. Do NOT fabricate output. `--dry-run` mode skips credential + vds-cli checks.
|
|
@@ -22,7 +22,7 @@ If BLOCKED: tell the user exactly what's missing and how to fix, then STOP. Do N
|
|
|
22
22
|
- `vds-cli` installed (for non-dry-run)
|
|
23
23
|
- Inside a git repo with remote pointing to `bitbucket.digital.vn`
|
|
24
24
|
- On a named branch (not detached HEAD)
|
|
25
|
-
- `
|
|
25
|
+
- `BITBUCKET_TOKEN` in `~/.vds/.env`
|
|
26
26
|
|
|
27
27
|
## Usage
|
|
28
28
|
|
|
@@ -40,7 +40,7 @@ If BLOCKED: tell the user exactly what's missing and how to fix, then STOP. Do N
|
|
|
40
40
|
2. Extract PROJECT/REPO from remote URL
|
|
41
41
|
3. Determine source branch (current) + target (default `master`)
|
|
42
42
|
4. Auto-detect description from `.vsaf/docs/features/*/09-ship.md` or `.vsaf/docs/hotfixes/*/03-ship.md`
|
|
43
|
-
5. Lazy-prompt `
|
|
43
|
+
5. Lazy-prompt `BITBUCKET_TOKEN` if not set
|
|
44
44
|
6. Confirm with user before executing
|
|
45
45
|
7. Run `vds-cli bitbucket pr create $PROJECT/$REPO --source ... --target ... --title ... --description-file ... --yes --json-only`
|
|
46
46
|
|
|
@@ -106,7 +106,7 @@ if (!cmdCheck.found) {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
(async () => {
|
|
109
|
-
if (!await ensureEnv('
|
|
109
|
+
if (!await ensureEnv('BITBUCKET_TOKEN', 'Enter Bitbucket personal access token')) process.exit(1);
|
|
110
110
|
|
|
111
111
|
console.log('About to create PR:');
|
|
112
112
|
console.log(` Project/Repo: ${project}/${repo}`);
|
|
@@ -12,7 +12,7 @@ Create a Jira Epic on Viettel Jira based on a PRD markdown file.
|
|
|
12
12
|
Before doing anything, run this check via Bash tool:
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
node .claude/skills/_shared/vds-skill/config-check.js --cmd vds-cli --env
|
|
15
|
+
node .claude/skills/_shared/vds-skill/config-check.js --cmd vds-cli --env JIRA_TOKEN,VDS_JIRA_PROJECT_DEFAULT
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
If BLOCKED: tell the user exactly what's missing and how to fix, then STOP. Do NOT fabricate output. `--dry-run` mode skips credential + vds-cli checks.
|
|
@@ -21,7 +21,7 @@ If BLOCKED: tell the user exactly what's missing and how to fix, then STOP. Do N
|
|
|
21
21
|
|
|
22
22
|
- `vds-cli` installed (for non-dry-run)
|
|
23
23
|
- A PRD file exists at `.vsaf/docs/features/{feature}/02-prd.md`
|
|
24
|
-
- `
|
|
24
|
+
- `JIRA_TOKEN` + `VDS_JIRA_PROJECT_DEFAULT` in `~/.vds/.env`
|
|
25
25
|
|
|
26
26
|
## Usage
|
|
27
27
|
|
|
@@ -37,7 +37,7 @@ If BLOCKED: tell the user exactly what's missing and how to fix, then STOP. Do N
|
|
|
37
37
|
|
|
38
38
|
1. Locate PRD file (or use `--description-file`)
|
|
39
39
|
2. Extract summary from PRD's first H1 heading
|
|
40
|
-
3. Lazy-prompt `
|
|
40
|
+
3. Lazy-prompt `JIRA_TOKEN` + `VDS_JIRA_PROJECT_DEFAULT` if missing
|
|
41
41
|
4. Confirm with user
|
|
42
42
|
5. Run `vds-cli jira create --project KEY --issuetype Epic --summary ... --description-file ... --yes --json-only`
|
|
43
43
|
6. Save returned epic key to `<feature-dir>/jira-epic-key.txt`
|
|
@@ -76,7 +76,7 @@ if (!cmdCheck.found) {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
(async () => {
|
|
79
|
-
if (!await ensureEnv('
|
|
79
|
+
if (!await ensureEnv('JIRA_TOKEN', 'Enter Jira personal access token')) process.exit(1);
|
|
80
80
|
if (!await ensureEnv('VDS_JIRA_PROJECT_DEFAULT', 'Enter default Jira project key (e.g. NTTC)', false)) process.exit(1);
|
|
81
81
|
|
|
82
82
|
projectKey = projectKey || process.env.VDS_JIRA_PROJECT_DEFAULT;
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* VDS Skill Pack — credential & config setup
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Merges credential stubs into ~/.vds/.env (the shared VDS env file
|
|
7
|
+
* that all orchestrators read via pydantic-settings).
|
|
8
8
|
*
|
|
9
9
|
* Usage:
|
|
10
10
|
* node install-deps.mjs [projectPath]
|
|
@@ -20,14 +20,19 @@ const packDir = process.argv[3] || dirname(new URL(import.meta.url).pathname);
|
|
|
20
20
|
// ── Config ──
|
|
21
21
|
|
|
22
22
|
const VDS_DIR = join(homedir(), '.vds');
|
|
23
|
-
const CONFIG_FILE = join(VDS_DIR, '
|
|
23
|
+
const CONFIG_FILE = join(VDS_DIR, '.env');
|
|
24
24
|
|
|
25
25
|
const REQUIRED_VARS = [
|
|
26
|
-
|
|
27
|
-
{ name: '
|
|
28
|
-
{ name: '
|
|
29
|
-
{ name: '
|
|
30
|
-
|
|
26
|
+
// Personal Access Tokens — primary auth (one token per service)
|
|
27
|
+
{ name: 'INTERNAL_CONFLUENCE_TOKEN', desc: 'Confluence internal server PAT', skills: 'push-prd, push-srs, search-confluence' },
|
|
28
|
+
{ name: 'JIRA_TOKEN', desc: 'Jira personal access token', skills: 'create-jira-epic, search-confluence' },
|
|
29
|
+
{ name: 'BITBUCKET_TOKEN', desc: 'Bitbucket personal access token', skills: 'create-bitbucket-pr' },
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
// Optional — basic auth fallback (only needed if PATs not available)
|
|
33
|
+
const OPTIONAL_VARS = [
|
|
34
|
+
{ name: 'VDS_USERNAME', desc: 'VDS username (basic auth fallback)', skills: 'confluence, jira, bitbucket' },
|
|
35
|
+
{ name: 'VDS_PASSWORD', desc: 'VDS password (basic auth fallback)', skills: 'confluence, jira, bitbucket' },
|
|
31
36
|
];
|
|
32
37
|
|
|
33
38
|
// ── Helpers ──
|
|
@@ -75,12 +80,14 @@ for (const v of REQUIRED_VARS) {
|
|
|
75
80
|
if (!existsSync(CONFIG_FILE)) {
|
|
76
81
|
// Create fresh template
|
|
77
82
|
const lines = [
|
|
78
|
-
'# VDS
|
|
79
|
-
'# File: ~/.vds
|
|
80
|
-
'# Permissions: 600 (auto-set by
|
|
83
|
+
'# VDS shared environment — credential config',
|
|
84
|
+
'# File: ~/.vds/.env',
|
|
85
|
+
'# Permissions: 600 (auto-set by installer)',
|
|
81
86
|
'#',
|
|
82
|
-
'#
|
|
83
|
-
'#
|
|
87
|
+
'# Set per-service Personal Access Tokens (recommended):',
|
|
88
|
+
'# INTERNAL_CONFLUENCE_TOKEN, JIRA_TOKEN, BITBUCKET_TOKEN',
|
|
89
|
+
'# Or basic auth fallback: VDS_USERNAME + VDS_PASSWORD (works for all services)',
|
|
90
|
+
'# To rotate a credential: update the value here, orchestrators pick it up next run.',
|
|
84
91
|
'',
|
|
85
92
|
];
|
|
86
93
|
|
|
@@ -91,6 +98,14 @@ if (!existsSync(CONFIG_FILE)) {
|
|
|
91
98
|
lines.push('');
|
|
92
99
|
}
|
|
93
100
|
|
|
101
|
+
lines.push('# --- Basic auth fallback (optional, only if PATs not available) ---');
|
|
102
|
+
lines.push('');
|
|
103
|
+
for (const v of OPTIONAL_VARS) {
|
|
104
|
+
lines.push(`# ${v.desc}`);
|
|
105
|
+
lines.push(`# ${v.name}=`);
|
|
106
|
+
}
|
|
107
|
+
lines.push('');
|
|
108
|
+
|
|
94
109
|
writeFileSync(CONFIG_FILE, lines.join('\n'));
|
|
95
110
|
if (process.platform !== 'win32') {
|
|
96
111
|
chmodSync(CONFIG_FILE, 0o600);
|
|
@@ -193,7 +208,10 @@ if (!vdsCliFound && vdsScriptsDir) {
|
|
|
193
208
|
// Check vds-scripts has valid structure (pyproject.toml = uv project)
|
|
194
209
|
if (existsSync(join(vdsScriptsDir, 'pyproject.toml'))) {
|
|
195
210
|
mkdirSync(wrapperDir, { recursive: true });
|
|
196
|
-
|
|
211
|
+
|
|
212
|
+
if (process.platform === 'win32') {
|
|
213
|
+
// Windows: Node.js wrapper + .cmd shim
|
|
214
|
+
const wrapperContent = `#!/usr/bin/env node
|
|
197
215
|
// Project-local vds-cli wrapper — created by vsaf install vds-skill
|
|
198
216
|
const { execFileSync } = require('child_process');
|
|
199
217
|
try {
|
|
@@ -202,20 +220,53 @@ try {
|
|
|
202
220
|
process.exit(e.status || 1);
|
|
203
221
|
}
|
|
204
222
|
`;
|
|
205
|
-
|
|
206
|
-
if (process.platform !== 'win32') {
|
|
207
|
-
chmodSync(wrapperPath, 0o755);
|
|
208
|
-
} else {
|
|
223
|
+
writeFileSync(wrapperPath, wrapperContent);
|
|
209
224
|
writeFileSync(wrapperPath + '.cmd', `@node "%~dp0\\vds-cli" %*\r\n`);
|
|
225
|
+
} else {
|
|
226
|
+
// Unix: pure bash wrapper — no node/nvm dependency
|
|
227
|
+
const wrapperContent = `#!/usr/bin/env bash
|
|
228
|
+
# Project-local vds-cli wrapper — created by vsaf install vds-skill
|
|
229
|
+
# Uses bash instead of node to avoid nvm/node PATH issues
|
|
230
|
+
exec uv run --directory ${JSON.stringify(vdsScriptsDir)} --package vds-cli vds-cli "$@"
|
|
231
|
+
`;
|
|
232
|
+
writeFileSync(wrapperPath, wrapperContent);
|
|
233
|
+
chmodSync(wrapperPath, 0o755);
|
|
210
234
|
}
|
|
211
235
|
log('✅', `vds-cli wrapper created: ${wrapperPath}`);
|
|
212
236
|
log(' ', `Points to: ${vdsScriptsDir}`);
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
237
|
+
|
|
238
|
+
// Auto-register .claude/bin in CLAUDE.md so Claude Code always finds vds-cli
|
|
239
|
+
const claudeMdPath = join(projectPath, 'CLAUDE.md');
|
|
240
|
+
try {
|
|
241
|
+
const content = existsSync(claudeMdPath) ? readFileSync(claudeMdPath, 'utf-8') : '';
|
|
242
|
+
const pathExport = 'export PATH=".claude/bin:$PATH"';
|
|
243
|
+
if (!content.includes('.claude/bin')) {
|
|
244
|
+
const block = `\n\n## vds-cli PATH\n\nBefore running any \`vds-cli\` command, prepend the local bin directory:\n\`\`\`bash\n${pathExport}\n\`\`\`\nOr use the full path: \`.claude/bin/vds-cli\`\n`;
|
|
245
|
+
writeFileSync(claudeMdPath, content + block);
|
|
246
|
+
log('✅', 'PATH hint added to CLAUDE.md');
|
|
247
|
+
}
|
|
248
|
+
} catch {
|
|
249
|
+
// CLAUDE.md update is best-effort
|
|
218
250
|
}
|
|
251
|
+
|
|
252
|
+
// Also add Bash permission for .claude/bin/vds-cli in settings.local.json
|
|
253
|
+
const settingsPath = join(projectPath, '.claude', 'settings.local.json');
|
|
254
|
+
try {
|
|
255
|
+
const settings = existsSync(settingsPath)
|
|
256
|
+
? JSON.parse(readFileSync(settingsPath, 'utf-8'))
|
|
257
|
+
: {};
|
|
258
|
+
if (!settings.permissions) settings.permissions = {};
|
|
259
|
+
if (!settings.permissions.allow) settings.permissions.allow = [];
|
|
260
|
+
const vdsRule = 'Bash(.claude/bin/vds-cli *)';
|
|
261
|
+
if (!settings.permissions.allow.some(r => r.includes('.claude/bin/vds-cli'))) {
|
|
262
|
+
settings.permissions.allow.push(vdsRule);
|
|
263
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
|
|
264
|
+
log('✅', 'vds-cli permission added to settings.local.json');
|
|
265
|
+
}
|
|
266
|
+
} catch {
|
|
267
|
+
// settings update is best-effort
|
|
268
|
+
}
|
|
269
|
+
|
|
219
270
|
vdsCliFound = true;
|
|
220
271
|
}
|
|
221
272
|
}
|
|
@@ -17,7 +17,7 @@ Publish the current PRD to Viettel Confluence via `vds-cli` — create a new pag
|
|
|
17
17
|
Before doing anything, run this check via Bash tool:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
node .claude/skills/_shared/vds-skill/config-check.js --cmd vds-cli --env
|
|
20
|
+
node .claude/skills/_shared/vds-skill/config-check.js --cmd vds-cli --env INTERNAL_CONFLUENCE_TOKEN,VDS_CONFLUENCE_SPACE_DEFAULT
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
If BLOCKED: tell the user exactly what's missing and how to fix, then STOP. Do NOT fabricate output.
|
|
@@ -26,7 +26,7 @@ If BLOCKED: tell the user exactly what's missing and how to fix, then STOP. Do N
|
|
|
26
26
|
|
|
27
27
|
- `vds-cli` installed
|
|
28
28
|
- A PRD markdown file must exist
|
|
29
|
-
- `
|
|
29
|
+
- `INTERNAL_CONFLUENCE_TOKEN` + `VDS_CONFLUENCE_SPACE_DEFAULT` in `~/.vds/.env`
|
|
30
30
|
- Confluence parent page configured in `.vsaf/config.yaml` (or lazy-prompted)
|
|
31
31
|
|
|
32
32
|
## Steps
|
|
@@ -17,7 +17,7 @@ Publish the current SRS to Viettel Confluence via `vds-cli` — create or update
|
|
|
17
17
|
Before doing anything, run this check via Bash tool:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
node .claude/skills/_shared/vds-skill/config-check.js --cmd vds-cli --env
|
|
20
|
+
node .claude/skills/_shared/vds-skill/config-check.js --cmd vds-cli --env INTERNAL_CONFLUENCE_TOKEN,VDS_CONFLUENCE_SPACE_DEFAULT
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
If BLOCKED: tell the user exactly what's missing and how to fix, then STOP. Do NOT fabricate output.
|
|
@@ -26,7 +26,7 @@ If BLOCKED: tell the user exactly what's missing and how to fix, then STOP. Do N
|
|
|
26
26
|
|
|
27
27
|
- `vds-cli` installed
|
|
28
28
|
- An SRS markdown file must exist
|
|
29
|
-
- `
|
|
29
|
+
- `INTERNAL_CONFLUENCE_TOKEN` + `VDS_CONFLUENCE_SPACE_DEFAULT` in `~/.vds/.env`
|
|
30
30
|
- Confluence parent page in config or lazy-prompted
|
|
31
31
|
|
|
32
32
|
## Steps
|
|
@@ -12,7 +12,7 @@ Search Viettel Confluence + Jira for pages/tickets related to a feature, then wr
|
|
|
12
12
|
Before doing anything, run this check via Bash tool:
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
node .claude/skills/_shared/vds-skill/config-check.js --cmd vds-cli --env
|
|
15
|
+
node .claude/skills/_shared/vds-skill/config-check.js --cmd vds-cli --env INTERNAL_CONFLUENCE_TOKEN,JIRA_TOKEN,VDS_CONFLUENCE_SPACE_DEFAULT,VDS_JIRA_PROJECT_DEFAULT
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
If BLOCKED: tell the user exactly what's missing and how to fix, then STOP. Do NOT fabricate output. `--dry-run` mode skips vds-cli check.
|
|
@@ -21,7 +21,7 @@ If BLOCKED: tell the user exactly what's missing and how to fix, then STOP. Do N
|
|
|
21
21
|
|
|
22
22
|
- `vds-cli` installed
|
|
23
23
|
- Inside a project root with `.vsaf/docs/features/`
|
|
24
|
-
- `
|
|
24
|
+
- `INTERNAL_CONFLUENCE_TOKEN`, `JIRA_TOKEN`, `VDS_CONFLUENCE_SPACE_DEFAULT`, `VDS_JIRA_PROJECT_DEFAULT` in `~/.vds/.env`
|
|
25
25
|
|
|
26
26
|
## Usage
|
|
27
27
|
|
|
@@ -57,8 +57,8 @@ if (!cmdCheck.found) {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
(async () => {
|
|
60
|
-
if (!await ensureEnv('
|
|
61
|
-
if (!await ensureEnv('
|
|
60
|
+
if (!await ensureEnv('INTERNAL_CONFLUENCE_TOKEN', 'Enter Confluence internal server PAT')) process.exit(1);
|
|
61
|
+
if (!await ensureEnv('JIRA_TOKEN', 'Enter Jira personal access token')) process.exit(1);
|
|
62
62
|
if (!await ensureEnv('VDS_CONFLUENCE_SPACE_DEFAULT', 'Enter default Confluence space key (e.g. ENG)', false)) process.exit(1);
|
|
63
63
|
if (!await ensureEnv('VDS_JIRA_PROJECT_DEFAULT', 'Enter default Jira project key (e.g. NTTC)', false)) process.exit(1);
|
|
64
64
|
|
|
@@ -48,19 +48,22 @@ Do **not** use this skill as the authoritative deep runbook for:
|
|
|
48
48
|
|
|
49
49
|
## Primary Command Entry Points
|
|
50
50
|
|
|
51
|
+
**Resolution order** — try each in sequence, use the first that works:
|
|
52
|
+
|
|
51
53
|
```bash
|
|
52
|
-
#
|
|
54
|
+
# 1. Project-local wrapper (recommended — works with nvm, no PATH setup needed)
|
|
55
|
+
.claude/bin/vds-cli --help
|
|
56
|
+
.claude/bin/vds-cli confluence --help
|
|
57
|
+
.claude/bin/vds-cli jira --help
|
|
58
|
+
.claude/bin/vds-cli bitbucket --help
|
|
59
|
+
|
|
60
|
+
# 2. On PATH (if user added .claude/bin to PATH or installed globally)
|
|
53
61
|
vds-cli --help
|
|
54
|
-
vds-cli confluence --help
|
|
55
|
-
vds-cli jira --help
|
|
56
|
-
vds-cli bitbucket --help
|
|
57
|
-
vds-cli git --help
|
|
58
62
|
|
|
59
|
-
# Direct uv invocation — project-local
|
|
63
|
+
# 3. Direct uv invocation — project-local fallback
|
|
60
64
|
uv run --directory .claude/vds-scripts --package vds-cli vds-cli --help
|
|
61
|
-
uv run --directory .claude/vds-scripts --package audit_orchestrator vds-audit --help
|
|
62
65
|
|
|
63
|
-
# Direct uv invocation — global fallback
|
|
66
|
+
# 4. Direct uv invocation — global fallback
|
|
64
67
|
uv run --directory ~/.claude/vds-scripts --package vds-cli vds-cli --help
|
|
65
68
|
```
|
|
66
69
|
|