@pacaf/wizard-ux 3.6.7 → 3.6.8
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/dist/index.html
CHANGED
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
}
|
|
29
29
|
@keyframes spin { to { transform: rotate(360deg); } }
|
|
30
30
|
</style>
|
|
31
|
-
<script type="module" crossorigin src="/assets/index-
|
|
31
|
+
<script type="module" crossorigin src="/assets/index-BId92dEF.js"></script>
|
|
32
32
|
</head>
|
|
33
33
|
<body>
|
|
34
34
|
<div id="root"><div id="boot"><div class="ring"></div></div></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pacaf/wizard-ux",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.8",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Browser-based setup wizard for Power Apps Code Apps.",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"dev": "node server/index.mjs",
|
|
64
64
|
"build": "vite build",
|
|
65
65
|
"preview": "vite preview --port 5174",
|
|
66
|
-
"test": "node --test server/steps/05-environments.test.mjs",
|
|
66
|
+
"test": "node --test server/steps/05-environments.test.mjs server/lib/process-runner.test.mjs",
|
|
67
67
|
"postinstall": "node scripts/fix-pty-perms.mjs"
|
|
68
68
|
}
|
|
69
69
|
}
|
|
@@ -16,7 +16,7 @@ class Run extends EventEmitter {
|
|
|
16
16
|
constructor(id) {
|
|
17
17
|
super();
|
|
18
18
|
this.id = id;
|
|
19
|
-
this.lines = []; // { stream: 'stdout'|'stderr', text, ts }
|
|
19
|
+
this.lines = []; // { stream: 'stdout'|'stderr', level: 'info'|'warn'|'error', text, ts }
|
|
20
20
|
this.status = 'pending'; // pending | running | done | error
|
|
21
21
|
this.exitCode = null;
|
|
22
22
|
this.error = null;
|
|
@@ -25,12 +25,17 @@ class Run extends EventEmitter {
|
|
|
25
25
|
this.child = null;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
push(stream, text) {
|
|
28
|
+
push(stream, text, level = 'info') {
|
|
29
29
|
// Defense-in-depth: scrub any secret-shaped values from text before it
|
|
30
30
|
// hits the SSE log buffer. The buffer is streamed to the browser and
|
|
31
31
|
// rendered in the UI; never let a real secret land there.
|
|
32
32
|
const safe = SCRUB.scrubSecrets(text);
|
|
33
|
-
|
|
33
|
+
// `level` reflects INTENT, not the OS pipe. Raw subprocess stderr is
|
|
34
|
+
// 'info' by default — git, npm, vitest and pac all write normal progress
|
|
35
|
+
// to stderr, so the pipe alone must never imply a warning. Only the
|
|
36
|
+
// wizard's own log.warn/log.fail set 'warn'/'error'. The UI keys its
|
|
37
|
+
// warning banner and red coloring off `level`, not `stream`.
|
|
38
|
+
const evt = { stream, level, text: safe, ts: Date.now() };
|
|
34
39
|
this.lines.push(evt);
|
|
35
40
|
if (this.lines.length > 1000) this.lines.shift();
|
|
36
41
|
this.emit('line', evt);
|
|
@@ -106,8 +111,8 @@ export async function runInline(run, fn) {
|
|
|
106
111
|
const log = {
|
|
107
112
|
info: (msg) => run.push('stdout', `${msg}\n`),
|
|
108
113
|
ok: (msg) => run.push('stdout', `✓ ${msg}\n`),
|
|
109
|
-
warn: (msg) => run.push('stderr', `⚠ ${msg}\n
|
|
110
|
-
fail: (msg) => run.push('stderr', `✗ ${msg}\n
|
|
114
|
+
warn: (msg) => run.push('stderr', `⚠ ${msg}\n`, 'warn'),
|
|
115
|
+
fail: (msg) => run.push('stderr', `✗ ${msg}\n`, 'error'),
|
|
111
116
|
};
|
|
112
117
|
try {
|
|
113
118
|
const result = await fn(log);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { newRun, runInline } from './process-runner.mjs';
|
|
4
|
+
|
|
5
|
+
// The UI decides whether to show the "review items" / agent-triage banner from
|
|
6
|
+
// each log line's `level`, NOT its OS pipe. Raw subprocess stderr (git, npm,
|
|
7
|
+
// vitest, pac all write normal progress to stderr) must stay 'info', or every
|
|
8
|
+
// successful step falsely looks like it finished with warnings.
|
|
9
|
+
|
|
10
|
+
test('raw stderr lines are tagged info, not warn', () => {
|
|
11
|
+
const run = newRun();
|
|
12
|
+
run.push('stderr', 'Cloning into ...\n'); // typical git/npm stderr chatter
|
|
13
|
+
const line = run.lines.at(-1);
|
|
14
|
+
assert.equal(line.stream, 'stderr');
|
|
15
|
+
assert.equal(line.level, 'info');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('raw stdout lines are tagged info', () => {
|
|
19
|
+
const run = newRun();
|
|
20
|
+
run.push('stdout', 'hello\n');
|
|
21
|
+
assert.equal(run.lines.at(-1).level, 'info');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('log.warn raises level to warn; log.fail to error; log.ok/info stay info', async () => {
|
|
25
|
+
const run = newRun();
|
|
26
|
+
await runInline(run, async (log) => {
|
|
27
|
+
log.ok('all good');
|
|
28
|
+
log.info('fyi');
|
|
29
|
+
log.warn('optional thing missing');
|
|
30
|
+
log.fail('something broke');
|
|
31
|
+
});
|
|
32
|
+
const byText = (needle) => run.lines.find((l) => l.text.includes(needle));
|
|
33
|
+
assert.equal(byText('all good').level, 'info');
|
|
34
|
+
assert.equal(byText('fyi').level, 'info');
|
|
35
|
+
assert.equal(byText('optional thing missing').level, 'warn');
|
|
36
|
+
assert.equal(byText('something broke').level, 'error');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('only warn/error lines would trigger the warning banner', async () => {
|
|
40
|
+
const run = newRun();
|
|
41
|
+
// Simulate a successful step that shelled out (stderr chatter) and logged ok.
|
|
42
|
+
run.push('stderr', 'npm notice ...\n');
|
|
43
|
+
await runInline(run, async (log) => { log.ok('done'); });
|
|
44
|
+
const hasWarnings = run.lines.some((l) => l.level === 'warn' || l.level === 'error');
|
|
45
|
+
assert.equal(hasWarnings, false);
|
|
46
|
+
});
|
|
@@ -207,8 +207,12 @@ export default {
|
|
|
207
207
|
// Note: The Dataverse-skills plugin manages its own Python SDK installation
|
|
208
208
|
// via the dv-connect skill. No separate pip install needed here.
|
|
209
209
|
|
|
210
|
-
// Dataverse Python SDK (PowerPlatform-Dataverse-Client + pandas) —
|
|
211
|
-
//
|
|
210
|
+
// Dataverse Python SDK (PowerPlatform-Dataverse-Client + pandas) — purely
|
|
211
|
+
// informational. It is NOT needed for scaffold/build/deploy, and the
|
|
212
|
+
// Dataverse-skills plugin installs it on demand via dv-connect. Emit at
|
|
213
|
+
// info level (not warn) so its absence never trips the step's warning /
|
|
214
|
+
// triage banner — telling the user to pip-install something they don't
|
|
215
|
+
// need yet is exactly the noise we want to avoid.
|
|
212
216
|
const sdkOk = detectDataverseSdk(pythonCmd);
|
|
213
217
|
if (sdkOk) {
|
|
214
218
|
checks.push({ name: 'Dataverse Python SDK', ok: true, value: 'available', hint: null });
|
|
@@ -218,10 +222,10 @@ export default {
|
|
|
218
222
|
name: 'Dataverse Python SDK',
|
|
219
223
|
ok: false,
|
|
220
224
|
value: null,
|
|
221
|
-
hint: '
|
|
225
|
+
hint: 'Optional — dv-connect installs it when you start Dataverse work (pip install PowerPlatform-Dataverse-Client pandas)',
|
|
222
226
|
optional: true,
|
|
223
227
|
});
|
|
224
|
-
log.
|
|
228
|
+
log.info('Dataverse Python SDK not found (optional — dv-connect installs it later when you start Dataverse work)');
|
|
225
229
|
}
|
|
226
230
|
|
|
227
231
|
// Dataverse-skills plugin — HARD GATE. All Dataverse work in this template
|