@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ngocsangairvds/vsaf",
3
- "version": "4.1.5",
3
+ "version": "4.1.7",
4
4
  "description": "logging step",
5
5
  "main": "packages/core/dist/index.js",
6
6
  "types": "packages/core/dist/index.d.ts",
@@ -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 VDS_CONFLUENCE_TOKEN,VDS_CONFLUENCE_SPACE_DEFAULT
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 VDS_JIRA_TOKEN — something missing
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/sdlc-config.env (or run: vsaf install vds-skill)');
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', 'sdlc-config.env');
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 VDS_BITBUCKET_TOKEN
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
- - `VDS_BITBUCKET_TOKEN` in `~/.vds/sdlc-config.env`
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 `VDS_BITBUCKET_TOKEN` if not set
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('VDS_BITBUCKET_TOKEN', 'Enter VDS Bitbucket personal access token')) process.exit(1);
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 VDS_JIRA_TOKEN,VDS_JIRA_PROJECT_DEFAULT
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
- - `VDS_JIRA_TOKEN` + `VDS_JIRA_PROJECT_DEFAULT` in `~/.vds/sdlc-config.env`
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 `VDS_JIRA_TOKEN` + `VDS_JIRA_PROJECT_DEFAULT` if missing
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('VDS_JIRA_TOKEN', 'Enter VDS Jira personal access token')) process.exit(1);
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
- * Creates ~/.vds/sdlc-config.env template with all required
7
- * environment variables for vds-skill-* skills.
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, 'sdlc-config.env');
23
+ const CONFIG_FILE = join(VDS_DIR, '.env');
24
24
 
25
25
  const REQUIRED_VARS = [
26
- { name: 'VDS_CONFLUENCE_TOKEN', desc: 'Confluence personal access token', skills: 'push-prd, push-srs, search-confluence' },
27
- { name: 'VDS_JIRA_TOKEN', desc: 'Jira personal access token', skills: 'create-jira-epic, search-confluence' },
28
- { name: 'VDS_BITBUCKET_TOKEN', desc: 'Bitbucket personal access token', skills: 'create-bitbucket-pr' },
29
- { name: 'VDS_CONFLUENCE_SPACE_DEFAULT', desc: 'Default Confluence space key (e.g. CEP)', skills: 'push-prd, push-srs, search-confluence' },
30
- { name: 'VDS_JIRA_PROJECT_DEFAULT', desc: 'Default Jira project key (e.g. NTTC)', skills: 'create-jira-epic, search-confluence' },
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 Skill Pack — credential config',
79
- '# File: ~/.vds/sdlc-config.env',
80
- '# Permissions: 600 (auto-set by credentials.js)',
83
+ '# VDS shared environment — credential config',
84
+ '# File: ~/.vds/.env',
85
+ '# Permissions: 600 (auto-set by installer)',
81
86
  '#',
82
- '# Fill in the values below. Skills will use these automatically.',
83
- '# To rotate a token: update the value here, skills pick it up next run.',
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
- const wrapperContent = `#!/usr/bin/env node
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
- writeFileSync(wrapperPath, wrapperContent);
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
- if (process.platform === 'win32') {
214
- log('💡', 'Add to PATH: set "PATH=.claude\\bin;%PATH%"');
215
- log(' ', 'PowerShell: $env:PATH = ".claude\\bin;$env:PATH"');
216
- } else {
217
- log('💡', 'Add to PATH: export PATH=".claude/bin:$PATH"');
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 VDS_CONFLUENCE_TOKEN,VDS_CONFLUENCE_SPACE_DEFAULT
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
- - `VDS_CONFLUENCE_TOKEN` + `VDS_CONFLUENCE_SPACE_DEFAULT` in `~/.vds/sdlc-config.env`
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 VDS_CONFLUENCE_TOKEN,VDS_CONFLUENCE_SPACE_DEFAULT
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
- - `VDS_CONFLUENCE_TOKEN` + `VDS_CONFLUENCE_SPACE_DEFAULT` in `~/.vds/sdlc-config.env`
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 VDS_CONFLUENCE_TOKEN,VDS_JIRA_TOKEN,VDS_CONFLUENCE_SPACE_DEFAULT,VDS_JIRA_PROJECT_DEFAULT
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
- - `VDS_CONFLUENCE_TOKEN`, `VDS_JIRA_TOKEN`, `VDS_CONFLUENCE_SPACE_DEFAULT`, `VDS_JIRA_PROJECT_DEFAULT` in `~/.vds/sdlc-config.env`
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('VDS_CONFLUENCE_TOKEN', 'Enter VDS Confluence personal access token')) process.exit(1);
61
- if (!await ensureEnv('VDS_JIRA_TOKEN', 'Enter VDS Jira personal access token')) process.exit(1);
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
- # Via vds-cli on PATH (recommended — MCP-registered)
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