@hanzlaa/rcode 2.3.4 → 2.3.6
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/cli/config.js +3 -3
- package/cli/context.js +5 -5
- package/cli/doctor.js +2 -2
- package/cli/github-sync.js +1 -1
- package/cli/index.js +4 -3
- package/cli/install.js +116 -33
- package/cli/lib/model-profiles.cjs +8 -1
- package/cli/postinstall.js +4 -4
- package/cli/set-mode.js +2 -2
- package/cli/set-profile.js +2 -2
- package/cli/uninstall.js +2 -2
- package/cli/update.js +3 -3
- package/dist/rcode.js +1290 -235
- package/package.json +10 -10
package/cli/config.js
CHANGED
|
@@ -90,7 +90,7 @@ module.exports = function config(args) {
|
|
|
90
90
|
const rihalDir = path.join(cwd, '.rihal');
|
|
91
91
|
if (!fs.existsSync(rihalDir) && !opts.global) {
|
|
92
92
|
console.error(`❌ No .rihal/ directory found in ${cwd}`);
|
|
93
|
-
console.error(` Run '
|
|
93
|
+
console.error(` Run 'rcode install' first, or use --global to manage user defaults.`);
|
|
94
94
|
process.exit(1);
|
|
95
95
|
}
|
|
96
96
|
printListing(cwd);
|
|
@@ -118,7 +118,7 @@ module.exports = function config(args) {
|
|
|
118
118
|
// For global writes, we don't need .rihal/ to exist
|
|
119
119
|
if (scope === 'project' && !fs.existsSync(path.join(cwd, '.rihal'))) {
|
|
120
120
|
console.error(`❌ No .rihal/ directory found in ${cwd}`);
|
|
121
|
-
console.error(` Run '
|
|
121
|
+
console.error(` Run 'rcode install' first, or use --global.`);
|
|
122
122
|
process.exit(1);
|
|
123
123
|
}
|
|
124
124
|
|
|
@@ -137,6 +137,6 @@ module.exports = function config(args) {
|
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
console.error(`❌ Too many arguments.`);
|
|
140
|
-
console.error(` Usage:
|
|
140
|
+
console.error(` Usage: rcode config [--global] [key] [value]`);
|
|
141
141
|
process.exit(1);
|
|
142
142
|
};
|
package/cli/context.js
CHANGED
|
@@ -35,7 +35,7 @@ function parseArgs(args) {
|
|
|
35
35
|
else if (arg === '--install-hook') opts.installHook = true;
|
|
36
36
|
else {
|
|
37
37
|
console.error(`Unknown flag: ${arg}`);
|
|
38
|
-
console.error(`Usage:
|
|
38
|
+
console.error(`Usage: rcode context [--check|--refresh|--install-hook]`);
|
|
39
39
|
process.exit(1);
|
|
40
40
|
}
|
|
41
41
|
}
|
|
@@ -45,7 +45,7 @@ function parseArgs(args) {
|
|
|
45
45
|
function ensureRihalDir(cwd) {
|
|
46
46
|
if (!fs.existsSync(path.join(cwd, '.rihal'))) {
|
|
47
47
|
console.error(`❌ No .rihal/ directory found in ${cwd}`);
|
|
48
|
-
console.error(` Run '
|
|
48
|
+
console.error(` Run 'rcode install' first.`);
|
|
49
49
|
process.exit(1);
|
|
50
50
|
}
|
|
51
51
|
}
|
|
@@ -155,10 +155,10 @@ function installHook(cwd) {
|
|
|
155
155
|
|
|
156
156
|
const hookContent = `#!/bin/sh
|
|
157
157
|
# Rihal Code — memory bank freshness check
|
|
158
|
-
# Installed by:
|
|
158
|
+
# Installed by: rcode context --install-hook
|
|
159
159
|
# Non-blocking: prints a one-line warning if the memory bank is stale.
|
|
160
|
-
if command -v
|
|
161
|
-
output=$(
|
|
160
|
+
if command -v rcode >/dev/null 2>&1; then
|
|
161
|
+
output=$(rcode context --check 2>&1)
|
|
162
162
|
if [ $? -ne 0 ]; then
|
|
163
163
|
echo ""
|
|
164
164
|
echo "⚠ Rihal memory bank is stale — run /rihal:init in your editor to refresh."
|
package/cli/doctor.js
CHANGED
|
@@ -92,7 +92,7 @@ function runPreflight(cwd, packageRoot) {
|
|
|
92
92
|
checks.push({
|
|
93
93
|
label: '.rihal/ state',
|
|
94
94
|
status: 'warn',
|
|
95
|
-
message: 'not initialized in this directory (run `
|
|
95
|
+
message: 'not initialized in this directory (run `rcode install`)',
|
|
96
96
|
});
|
|
97
97
|
}
|
|
98
98
|
|
|
@@ -196,7 +196,7 @@ function runPreflight(cwd, packageRoot) {
|
|
|
196
196
|
checks.push({
|
|
197
197
|
label: 'Memory bank',
|
|
198
198
|
status: 'warn',
|
|
199
|
-
message: `STALE — ${staleness.reasons[0]}${staleness.reasons.length > 1 ? ` (+${staleness.reasons.length - 1} more)` : ''}
|
|
199
|
+
message: `STALE — ${staleness.reasons[0]}${staleness.reasons.length > 1 ? ` (+${staleness.reasons.length - 1} more)` : ''}`,
|
|
200
200
|
});
|
|
201
201
|
}
|
|
202
202
|
}
|
package/cli/github-sync.js
CHANGED
|
@@ -446,7 +446,7 @@ async function main(args) {
|
|
|
446
446
|
// ------ Precondition: .rihal/ exists ------
|
|
447
447
|
const state = loadState(cwd);
|
|
448
448
|
if (!state) {
|
|
449
|
-
console.error(`❌ No .rihal/state.json found. Run '
|
|
449
|
+
console.error(`❌ No .rihal/state.json found. Run 'rcode install' first.`);
|
|
450
450
|
process.exit(1);
|
|
451
451
|
}
|
|
452
452
|
console.log(` ✓ Project: ${state.project_name || '(unnamed)'}`);
|
package/cli/index.js
CHANGED
|
@@ -47,7 +47,7 @@ function printHelp() {
|
|
|
47
47
|
Context-aware AI team methodology. See tiers: \`rihal-code tiers\`
|
|
48
48
|
|
|
49
49
|
Usage:
|
|
50
|
-
|
|
50
|
+
rcode <command>
|
|
51
51
|
|
|
52
52
|
📦 PROJECT
|
|
53
53
|
install Install Rihal Code into the current project
|
|
@@ -78,8 +78,9 @@ Usage:
|
|
|
78
78
|
|
|
79
79
|
Getting started:
|
|
80
80
|
cd my-project
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
rcode install # set up agents + slash commands
|
|
82
|
+
rcode tiers # see the Golden Path
|
|
83
|
+
rcode set-profile # choose model profile (quality | balanced | budget)
|
|
83
84
|
|
|
84
85
|
Documentation: https://github.com/hanzlahabib/rihal-code
|
|
85
86
|
`.trim());
|
package/cli/install.js
CHANGED
|
@@ -62,6 +62,7 @@ const fg = require('fast-glob');
|
|
|
62
62
|
const { z } = require('zod');
|
|
63
63
|
const semver = require('semver');
|
|
64
64
|
const { createTwoFilesPatch } = require('diff');
|
|
65
|
+
const clack = require('@clack/prompts');
|
|
65
66
|
|
|
66
67
|
// Output helpers: always respect NO_COLOR / non-TTY (picocolors handles this).
|
|
67
68
|
const ok = (s) => pc.green('✓') + ' ' + s;
|
|
@@ -1486,7 +1487,7 @@ function runInstallHealthCheck(target, counts) {
|
|
|
1486
1487
|
console.log('');
|
|
1487
1488
|
console.log(' ' + fail(`${fails} health check${fails === 1 ? '' : 's'} failed — install may be broken.`));
|
|
1488
1489
|
console.log(dim(' Debug: node .rihal/bin/rihal-tools.cjs state read && ls -la .rihal/'));
|
|
1489
|
-
console.log(dim(' Reinstall:
|
|
1490
|
+
console.log(dim(' Reinstall: rcode install . --force'));
|
|
1490
1491
|
console.log('');
|
|
1491
1492
|
return false;
|
|
1492
1493
|
}
|
|
@@ -1498,40 +1499,19 @@ async function main() {
|
|
|
1498
1499
|
const argv = process.argv.slice(2);
|
|
1499
1500
|
const opts = parseArgs(argv);
|
|
1500
1501
|
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
{ default: opts.target }
|
|
1509
|
-
);
|
|
1510
|
-
const resolved = path.resolve(answer.trim() || opts.target);
|
|
1511
|
-
opts.target = resolved;
|
|
1512
|
-
opts.projectName = path.basename(resolved);
|
|
1513
|
-
|
|
1514
|
-
const ideAnswer = await askChoice(
|
|
1515
|
-
'Which editor are you installing for?',
|
|
1516
|
-
{
|
|
1517
|
-
choices: [
|
|
1518
|
-
{ id: 'claude', label: 'Claude Code' },
|
|
1519
|
-
{ id: 'cursor', label: 'Cursor' },
|
|
1520
|
-
{ id: 'gemini', label: 'Gemini CLI' },
|
|
1521
|
-
{ id: 'all', label: 'All (Claude + Cursor + Gemini)' },
|
|
1522
|
-
],
|
|
1523
|
-
default: 'claude',
|
|
1524
|
-
}
|
|
1525
|
-
);
|
|
1526
|
-
opts.ide = ideAnswer[0];
|
|
1527
|
-
console.log('');
|
|
1528
|
-
} catch (err) {
|
|
1529
|
-
if (err.name === 'PromptAbortError') process.exit(0);
|
|
1530
|
-
throw err;
|
|
1531
|
-
}
|
|
1502
|
+
if (opts.help) { printHelp(); return; }
|
|
1503
|
+
|
|
1504
|
+
// ── Non-interactive fast path (--yes / CI / piped stdin) ─────────────────
|
|
1505
|
+
const interactive = !opts.yes && process.stdin.isTTY && !process.env.CI;
|
|
1506
|
+
|
|
1507
|
+
if (interactive) {
|
|
1508
|
+
await runInstallWizard(opts);
|
|
1532
1509
|
}
|
|
1533
1510
|
|
|
1534
|
-
|
|
1511
|
+
try {
|
|
1512
|
+
const code = await install(opts);
|
|
1513
|
+
process.exit(code);
|
|
1514
|
+
} catch (err) {
|
|
1535
1515
|
if (err.code === 'EACCES' || err.code === 'EPERM') {
|
|
1536
1516
|
console.error(`✖ Permission denied: ${err.path || err.message}`);
|
|
1537
1517
|
process.exit(1);
|
|
@@ -1543,7 +1523,110 @@ async function main() {
|
|
|
1543
1523
|
console.error(`✖ Install failed: ${err.message}`);
|
|
1544
1524
|
if (process.env.DEBUG) console.error(err.stack);
|
|
1545
1525
|
process.exit(1);
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
/**
|
|
1530
|
+
* Interactive install wizard powered by @clack/prompts.
|
|
1531
|
+
* Mutates opts in-place. Exits 0 on cancel.
|
|
1532
|
+
*/
|
|
1533
|
+
async function runInstallWizard(opts) {
|
|
1534
|
+
const { intro, outro, text, select, confirm, isCancel, cancel, note } = clack;
|
|
1535
|
+
const pkgVersion = readPackageVersion();
|
|
1536
|
+
|
|
1537
|
+
console.log('');
|
|
1538
|
+
intro(pc.bold('🕌 Rihal Code') + pc.dim(` v${pkgVersion}`));
|
|
1539
|
+
|
|
1540
|
+
// ── 1. Install directory ──────────────────────────────────────────────
|
|
1541
|
+
if (!opts.targetProvided) {
|
|
1542
|
+
const dir = await text({
|
|
1543
|
+
message: 'Install directory?',
|
|
1544
|
+
placeholder: opts.target,
|
|
1545
|
+
defaultValue: opts.target,
|
|
1546
|
+
initialValue: opts.target,
|
|
1547
|
+
});
|
|
1548
|
+
if (isCancel(dir)) { cancel('Installation cancelled.'); process.exit(0); }
|
|
1549
|
+
const resolved = path.resolve((dir || opts.target).trim());
|
|
1550
|
+
opts.target = resolved;
|
|
1551
|
+
opts.projectName = path.basename(resolved);
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
// ── 2. Editor / LLM ──────────────────────────────────────────────────
|
|
1555
|
+
const editorChoice = await select({
|
|
1556
|
+
message: 'Which editor are you installing for?',
|
|
1557
|
+
options: [
|
|
1558
|
+
{ value: 'claude', label: 'Claude Code', hint: 'recommended' },
|
|
1559
|
+
{ value: 'cursor', label: 'Cursor' },
|
|
1560
|
+
{ value: 'gemini', label: 'Gemini CLI', hint: 'coming soon' },
|
|
1561
|
+
],
|
|
1562
|
+
initialValue: opts.ide || 'claude',
|
|
1546
1563
|
});
|
|
1564
|
+
if (isCancel(editorChoice)) { cancel('Installation cancelled.'); process.exit(0); }
|
|
1565
|
+
opts.ide = editorChoice;
|
|
1566
|
+
|
|
1567
|
+
// ── 3. Communication language ─────────────────────────────────────────
|
|
1568
|
+
const langChoice = await select({
|
|
1569
|
+
message: 'Communication language?',
|
|
1570
|
+
options: [
|
|
1571
|
+
{ value: 'English', label: 'English' },
|
|
1572
|
+
{ value: 'Arabic', label: 'Arabic (العربية)' },
|
|
1573
|
+
{ value: 'French', label: 'French (Français)' },
|
|
1574
|
+
{ value: 'Spanish', label: 'Spanish (Español)' },
|
|
1575
|
+
{ value: 'Urdu', label: 'Urdu (اردو)' },
|
|
1576
|
+
],
|
|
1577
|
+
initialValue: opts.language || 'English',
|
|
1578
|
+
});
|
|
1579
|
+
if (isCancel(langChoice)) { cancel('Installation cancelled.'); process.exit(0); }
|
|
1580
|
+
opts.language = langChoice;
|
|
1581
|
+
|
|
1582
|
+
// ── 4. Agent mode ─────────────────────────────────────────────────────
|
|
1583
|
+
const modeChoice = await select({
|
|
1584
|
+
message: 'Agent mode?',
|
|
1585
|
+
options: [
|
|
1586
|
+
{ value: 'guided', label: 'Guided', hint: 'confirm at key decision gates' },
|
|
1587
|
+
{ value: 'yolo', label: 'Yolo', hint: 'fully autonomous — no confirmation' },
|
|
1588
|
+
],
|
|
1589
|
+
initialValue: opts.mode || 'guided',
|
|
1590
|
+
});
|
|
1591
|
+
if (isCancel(modeChoice)) { cancel('Installation cancelled.'); process.exit(0); }
|
|
1592
|
+
opts.mode = modeChoice;
|
|
1593
|
+
|
|
1594
|
+
// ── 5. Planning artifacts ─────────────────────────────────────────────
|
|
1595
|
+
const planningChoice = await select({
|
|
1596
|
+
message: 'Where should planning artifacts (.planning/) be saved?',
|
|
1597
|
+
options: [
|
|
1598
|
+
{ value: true, label: 'Commit to git', hint: 'recommended — team sees the same plans' },
|
|
1599
|
+
{ value: false, label: 'Keep local', hint: 'gitignore — good for sensitive PRDs' },
|
|
1600
|
+
],
|
|
1601
|
+
initialValue: true,
|
|
1602
|
+
});
|
|
1603
|
+
if (isCancel(planningChoice)) { cancel('Installation cancelled.'); process.exit(0); }
|
|
1604
|
+
opts.commitPlanning = planningChoice;
|
|
1605
|
+
|
|
1606
|
+
// ── 6. User name ──────────────────────────────────────────────────────
|
|
1607
|
+
const nameInput = await text({
|
|
1608
|
+
message: 'Your name? (used in agent responses)',
|
|
1609
|
+
placeholder: opts.userName,
|
|
1610
|
+
defaultValue: opts.userName,
|
|
1611
|
+
initialValue: opts.userName,
|
|
1612
|
+
});
|
|
1613
|
+
if (isCancel(nameInput)) { cancel('Installation cancelled.'); process.exit(0); }
|
|
1614
|
+
opts.userName = (nameInput || opts.userName).trim();
|
|
1615
|
+
|
|
1616
|
+
// ── Summary before install ────────────────────────────────────────────
|
|
1617
|
+
note(
|
|
1618
|
+
[
|
|
1619
|
+
`${pc.dim('Directory:')} ${opts.target}`,
|
|
1620
|
+
`${pc.dim('Editor:')} ${opts.ide}`,
|
|
1621
|
+
`${pc.dim('Language:')} ${opts.language}`,
|
|
1622
|
+
`${pc.dim('Mode:')} ${opts.mode}`,
|
|
1623
|
+
`${pc.dim('Planning:')} ${opts.commitPlanning ? 'committed to git' : 'kept local (gitignored)'}`,
|
|
1624
|
+
`${pc.dim('User:')} ${opts.userName}`,
|
|
1625
|
+
].join('\n'),
|
|
1626
|
+
'Installing with these settings'
|
|
1627
|
+
);
|
|
1628
|
+
|
|
1629
|
+
console.log('');
|
|
1547
1630
|
}
|
|
1548
1631
|
|
|
1549
1632
|
if (require.main === module) main();
|
|
@@ -20,7 +20,14 @@
|
|
|
20
20
|
const fs = require('fs');
|
|
21
21
|
const path = require('path');
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
function findPackageRoot(dir) {
|
|
24
|
+
while (dir !== require('path').parse(dir).root) {
|
|
25
|
+
if (fs.existsSync(path.join(dir, 'package.json'))) return dir;
|
|
26
|
+
dir = path.dirname(dir);
|
|
27
|
+
}
|
|
28
|
+
throw new Error('Could not find package root');
|
|
29
|
+
}
|
|
30
|
+
const PACKAGE_ROOT = findPackageRoot(__dirname);
|
|
24
31
|
const PROFILES_PATH = path.join(PACKAGE_ROOT, 'rihal/config/model-profiles.json');
|
|
25
32
|
|
|
26
33
|
let _cached = null;
|
package/cli/postinstall.js
CHANGED
|
@@ -11,8 +11,8 @@ console.log(`
|
|
|
11
11
|
🕌 Rihal Code installed.
|
|
12
12
|
|
|
13
13
|
First-time setup:
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
rcode install # set up agents + slash commands
|
|
15
|
+
rcode tiers # see the tier map
|
|
16
16
|
|
|
17
17
|
🌱 The Golden Path (say these phrases in your AI IDE):
|
|
18
18
|
1. "scaffold a new project" → rihal-scaffold-project
|
|
@@ -24,8 +24,8 @@ First-time setup:
|
|
|
24
24
|
7. "sprint status" → rihal-sprint-status
|
|
25
25
|
|
|
26
26
|
More:
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
rcode help # all commands (grouped)
|
|
28
|
+
rcode dashboard # view-only Diwan on :7717
|
|
29
29
|
|
|
30
30
|
Docs: https://github.com/hanzlahabib/rihal-code
|
|
31
31
|
Tiers: docs/TIERS.md · Standards: docs/STANDARDS.md
|
package/cli/set-mode.js
CHANGED
|
@@ -45,7 +45,7 @@ module.exports = function setMode(args) {
|
|
|
45
45
|
|
|
46
46
|
if (!fs.existsSync(rihalDir)) {
|
|
47
47
|
console.error(`❌ No .rihal/ directory found in ${cwd}`);
|
|
48
|
-
console.error(` Run '
|
|
48
|
+
console.error(` Run 'rcode install' first.`);
|
|
49
49
|
process.exit(1);
|
|
50
50
|
}
|
|
51
51
|
|
|
@@ -62,7 +62,7 @@ module.exports = function setMode(args) {
|
|
|
62
62
|
console.log(` ${MODE_DESCRIPTIONS[mode]}`);
|
|
63
63
|
console.log();
|
|
64
64
|
}
|
|
65
|
-
console.log(`Usage:
|
|
65
|
+
console.log(`Usage: rcode set-mode <${[...VALID_COMMUNICATION_MODES].join('|')}>`);
|
|
66
66
|
console.log();
|
|
67
67
|
return;
|
|
68
68
|
}
|
package/cli/set-profile.js
CHANGED
|
@@ -30,7 +30,7 @@ module.exports = function setProfile(args) {
|
|
|
30
30
|
|
|
31
31
|
if (!fs.existsSync(rihalDir)) {
|
|
32
32
|
console.error(`❌ No .rihal/ directory found in ${cwd}`);
|
|
33
|
-
console.error(` Run '
|
|
33
|
+
console.error(` Run 'rcode install' first.`);
|
|
34
34
|
process.exit(1);
|
|
35
35
|
}
|
|
36
36
|
|
|
@@ -55,7 +55,7 @@ module.exports = function setProfile(args) {
|
|
|
55
55
|
console.log(` • ${name}${marker}`);
|
|
56
56
|
console.log(` ${p.description}`);
|
|
57
57
|
}
|
|
58
|
-
console.log(`\nUsage:
|
|
58
|
+
console.log(`\nUsage: rcode set-profile <name>`);
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
61
61
|
|
package/cli/uninstall.js
CHANGED
|
@@ -377,7 +377,7 @@ async function runUninstall(args) {
|
|
|
377
377
|
console.log(`\n❌ Rihal Code is not installed in this directory.`);
|
|
378
378
|
console.log(` Nothing to uninstall.`);
|
|
379
379
|
console.log();
|
|
380
|
-
console.log(` To install:
|
|
380
|
+
console.log(` To install: rcode install`);
|
|
381
381
|
console.log();
|
|
382
382
|
return;
|
|
383
383
|
}
|
|
@@ -589,7 +589,7 @@ async function runUninstall(args) {
|
|
|
589
589
|
|
|
590
590
|
// Hint about reinstalling
|
|
591
591
|
console.log(`\nTo reinstall later:`);
|
|
592
|
-
console.log(`
|
|
592
|
+
console.log(` rcode install`);
|
|
593
593
|
}
|
|
594
594
|
|
|
595
595
|
// Direct invocation — allow `node cli/uninstall.js [flags]` to run end-to-end.
|
package/cli/update.js
CHANGED
|
@@ -233,7 +233,7 @@ async function runUpdate(args, { packageRoot, packageJson }) {
|
|
|
233
233
|
const configPath = path.join(cwd, '.rihal/config.json');
|
|
234
234
|
if (!fs.existsSync(configPath)) {
|
|
235
235
|
console.error(`\n❌ Rihal Code is not installed in this directory.`);
|
|
236
|
-
console.error(` To install:
|
|
236
|
+
console.error(` To install: rcode install\n`);
|
|
237
237
|
process.exit(1);
|
|
238
238
|
}
|
|
239
239
|
|
|
@@ -251,7 +251,7 @@ async function runUpdate(args, { packageRoot, packageJson }) {
|
|
|
251
251
|
const editors = detectInstalledEditors(cwd);
|
|
252
252
|
if (editors.length === 0) {
|
|
253
253
|
console.error(`\n❌ No editor install detected.`);
|
|
254
|
-
console.error(` Run '
|
|
254
|
+
console.error(` Run 'rcode install' to set up at least one editor first.\n`);
|
|
255
255
|
process.exit(1);
|
|
256
256
|
}
|
|
257
257
|
|
|
@@ -355,7 +355,7 @@ async function runUpdate(args, { packageRoot, packageJson }) {
|
|
|
355
355
|
if (hasDrift) {
|
|
356
356
|
console.log(`⚠ Post-update verification found drift:`);
|
|
357
357
|
console.log(formatReport(reports));
|
|
358
|
-
console.log(`\n Run '
|
|
358
|
+
console.log(`\n Run 'rcode doctor' for details, or re-run update to retry.`);
|
|
359
359
|
} else {
|
|
360
360
|
console.log(` ✓ Post-update verification passed.`);
|
|
361
361
|
}
|