create-pmos 0.79.0 → 0.81.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/package.json +1 -1
- package/payload/KIT-VERSION +1 -1
- package/payload/planning/evals/eval-calibration.md +1 -1
- package/payload/planning/okrs/health-budgets.md +1 -1
- package/payload/scripts/workflow-state.js +2 -2
- package/payload/state/discoveries.md +1 -1
- package/workspace/guide/layout.md +3 -1
- package/workspace/guide/notes.md +9 -5
- package/workspace/lib/engine/workflow-state.js +2 -2
- package/workspace/lib/notes-final.js +93 -13
- package/workspace/lib/notes-qwen.js +182 -0
- package/workspace/lib/notes-qwen.py +62 -0
- package/workspace/lib/notes-whisper.js +3 -2
- package/workspace/lib/routes-notes.js +21 -3
- package/workspace/package-lock.json +2 -2
- package/workspace/package.json +1 -1
- package/workspace/public/pm/app.js +3 -1
- package/workspace/public/pm/components.css +61 -56
- package/workspace/public/pm/dest-today.js +3 -2
- package/workspace/public/pm/dom.js +60 -0
- package/workspace/public/pm/roadmap.js +2 -2
- package/workspace/public/pm/topbar.js +4 -1
- package/workspace/public/pm/view-notes.js +9 -7
- package/workspace/run-tests.js +5 -5
- package/workspace/test-lists/meeting-notes.json +5 -3
- package/workspace/test-timings.json +1 -0
|
@@ -397,7 +397,7 @@ async function finalSetup(ctx) {
|
|
|
397
397
|
const ws = wsOf(ctx);
|
|
398
398
|
const r = await pmPost('/api/notes/final-setup', ws ? { ws } : {});
|
|
399
399
|
banner = r && r.ok && r.started
|
|
400
|
-
? { tone: 'ok', text: 'A terminal opened with the setup commands typed in. Read them and press Enter there. The downloads are about
|
|
400
|
+
? { tone: 'ok', text: 'A terminal opened with the setup commands typed in. Read them and press Enter there. The downloads are about 6 GB. Then open Settings again.' }
|
|
401
401
|
: { tone: 'bad', text: 'No terminal opened' + (r && r.reason ? ': ' + r.reason : '') + '. Run this in a terminal: ' + ((r && r.command) || '') };
|
|
402
402
|
ctx.setState({});
|
|
403
403
|
}
|
|
@@ -783,9 +783,11 @@ function openSettings(ctx, n) {
|
|
|
783
783
|
const parts = [];
|
|
784
784
|
parts.push(el('div', { class: 'nt-set', 'data-nt-whisper': w ? (w.ready ? 'ready' : 'missing') : 'unknown' },
|
|
785
785
|
el('div', { class: 'nt-set__head' }, 'Local transcription'),
|
|
786
|
-
el('p', { class: 'nt-hint'
|
|
786
|
+
el('p', { class: 'nt-hint', 'data-nt-live-engine': w ? (w.live || '') : null }, !w ? 'Reading …'
|
|
787
|
+
: w.live === 'qwen' ? 'Qwen3-ASR is set up. The microphone and the meeting are transcribed on this machine, in English, Chinese or Indonesian.'
|
|
788
|
+
: w.ready ? 'Whisper is set up. The microphone and the meeting are transcribed on this machine.'
|
|
787
789
|
: 'Whisper is not set up (' + w.missing.map((m) => (m === 'program' ? 'the program' : 'the model, ' + w.model_size)).join(' and ') + ' missing). The setup installs whisper.cpp with Homebrew and downloads the model.'),
|
|
788
|
-
w && w.models ? field({ label: 'Model', kind: 'select', value: w.model, options: w.models,
|
|
790
|
+
w && w.models && w.live !== 'qwen' ? field({ label: 'Model', kind: 'select', value: w.model, options: w.models,
|
|
789
791
|
onCommit: (v) => setSwitch(ctx, { model: v }).then(() => { h.close(); openSettings(ctx, n); }), attrs: { 'data-nt-model': '' } }) : null,
|
|
790
792
|
w && !w.ready ? button({ label: 'Set up in a terminal', onClick: () => { h.close(); whisperSetup(ctx); }, attrs: { 'data-nt-whisper-setup': '' } }) : null,
|
|
791
793
|
w && w.ready && w.languages ? field({ label: 'Language spoken in the meeting', kind: 'select', value: w.language, options: w.languages,
|
|
@@ -797,15 +799,15 @@ function openSettings(ctx, n) {
|
|
|
797
799
|
: 'No audio is kept: each clip is deleted once it is transcribed, and a meeting cannot be replayed.') : null));
|
|
798
800
|
const fp = w && w.final;
|
|
799
801
|
if (fp) {
|
|
800
|
-
const have = [fp.transcriber === 'parakeet' ? 'Parakeet' : fp.transcriber === 'whisper' ? 'Whisper with beam search' : null,
|
|
802
|
+
const have = [fp.transcriber === 'qwen' ? 'Qwen3-ASR' : fp.transcriber === 'parakeet' ? 'Parakeet' : fp.transcriber === 'whisper' ? 'Whisper with beam search' : null,
|
|
801
803
|
fp.vad ? 'speech detection' : null, fp.speakers ? 'speaker separation' : null].filter(Boolean);
|
|
802
804
|
parts.push(el('div', { class: 'nt-set', 'data-nt-final-set': fp.ready ? 'ready' : 'missing' },
|
|
803
805
|
el('div', { class: 'nt-set__head' }, 'Final notes after Stop'),
|
|
804
806
|
el('p', { class: 'nt-hint' }, fp.ready
|
|
805
807
|
? 'After Stop, the whole meeting is transcribed again on this machine (' + have.join(', ') + '), and your agent session writes the notes from it.'
|
|
806
808
|
: 'Set up local transcription first. After Stop, the whole meeting is then transcribed again on this machine, and your agent session writes the notes from it.'),
|
|
807
|
-
fp.missing.length ? el('p', { class: 'nt-hint', 'data-nt-final-missing': '' }, 'For better notes, set up ' + fp.missing.map((m) => (m === 'parakeet' ? 'Parakeet (more accurate in English)' : m === 'vad' ? 'speech detection' : 'speaker separation')).join(', ')
|
|
808
|
-
+ '. The setup installs them into the workspace\'s own folder; the downloads are about
|
|
809
|
+
fp.missing.length ? el('p', { class: 'nt-hint', 'data-nt-final-missing': '' }, 'For better notes, set up ' + fp.missing.map((m) => (m === 'qwen' ? 'Qwen3-ASR (English, Chinese and Indonesian, more accurate)' : m === 'parakeet' ? 'Parakeet (more accurate in English)' : m === 'vad' ? 'speech detection' : 'speaker separation')).join(', ')
|
|
810
|
+
+ '. The setup installs them into the workspace\'s own folder; the downloads are about 6 GB.') : null,
|
|
809
811
|
fp.missing.length ? button({ label: 'Set up in a terminal', onClick: () => { h.close(); finalSetup(ctx); }, attrs: { 'data-nt-final-setup': '' } }) : null,
|
|
810
812
|
field({ label: 'Fetch Wispr Flow notes after the meeting', kind: 'check', value: w.wispr !== false,
|
|
811
813
|
onCommit: (v) => setSwitch(ctx, { wispr: v }).then(() => { h.close(); openSettings(ctx, n); }), attrs: { 'data-nt-wispr-switch': '' } }),
|
|
@@ -1263,7 +1265,7 @@ function finalTranscript(ctx, n, opts) {
|
|
|
1263
1265
|
});
|
|
1264
1266
|
const box = el('div', { class: 'nt-lines', 'data-nt-transcript': 'final' }, lines);
|
|
1265
1267
|
const where = opts.inline ? 'inline' : 'full';
|
|
1266
|
-
const how = [n.final.engine === 'parakeet' ? 'Parakeet' : 'Whisper', n.final.diarized ? 'speakers told apart' : null].filter(Boolean).join(', ');
|
|
1268
|
+
const how = [n.final.engine === 'qwen' ? 'Qwen3-ASR' : n.final.engine === 'parakeet' ? 'Parakeet' : 'Whisper', n.final.diarized ? 'speakers told apart' : null].filter(Boolean).join(', ');
|
|
1267
1269
|
const d = el('details', { class: 'nt-trans', 'data-nt-part': 'transcript', open: transcriptOpen[where] },
|
|
1268
1270
|
el('summary', { class: 'nt-sec__h nt-fold' }, 'Transcript', el('span', { class: 'nt-src' }, ' · from the whole recording (' + how + '), ' + rows.length + (rows.length === 1 ? ' line' : ' lines'))),
|
|
1269
1271
|
button({ label: 'Show the live transcript', variant: 'ghost', size: 'sm', onClick: () => { liveTranscript = true; ctx.setState({}); }, attrs: { 'data-nt-live-transcript': '' } }), box);
|
package/workspace/run-tests.js
CHANGED
|
@@ -18,10 +18,10 @@
|
|
|
18
18
|
* file in exactly one shard), and --check fails when a suite on disk is in no list, so a new suite
|
|
19
19
|
* that nobody wired in is a red build rather than a suite that runs nowhere.
|
|
20
20
|
*
|
|
21
|
-
* --changed
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
21
|
+
* --changed narrows the group to the suites a diff against REF (default origin/main) can reach, and
|
|
22
|
+
* runs the whole group whenever it cannot tell. The local inner loop uses it, and so does Workspace
|
|
23
|
+
* CI for the browser group on a PR (ci-browser-after-merge): every browser suite still runs after the
|
|
24
|
+
* merge on main, and kit-publish waits for that run. See changedSuites() for the rule.
|
|
25
25
|
*
|
|
26
26
|
* Output: a suite's own output is buffered and printed whole when it finishes, so lines from two
|
|
27
27
|
* suites never interleave. A passing suite prints its last lines; --verbose prints all of it.
|
|
@@ -256,7 +256,7 @@ async function main() {
|
|
|
256
256
|
if (changed) {
|
|
257
257
|
const ref = changed === true ? 'origin/main' : changed;
|
|
258
258
|
const pick = changedSuites(list, ref);
|
|
259
|
-
console.log(`run-tests: --changed against ${ref}: ${pick.why}. ${pick.suites.length} of ${list.length} suites run here;
|
|
259
|
+
console.log(`run-tests: --changed against ${ref}: ${pick.why}. ${pick.suites.length} of ${list.length} suites run here; every suite runs on main after the merge.`);
|
|
260
260
|
list = pick.suites;
|
|
261
261
|
if (!list.length) return;
|
|
262
262
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_comment": "meeting-notes Runs 1 to
|
|
2
|
+
"_comment": "meeting-notes Runs 1 to 10: the Notes engine and routes (notes.test.js), local Whisper, line labels and repository checks (notes-listen.test.js), the final pass after Stop and the Wispr Flow fetch (notes-final.test.js), Qwen3-ASR kept loaded (notes-qwen.test.js), and the Notes view in a browser (pm-notes-test.js).",
|
|
3
3
|
"modules": [
|
|
4
4
|
"notes.test.js",
|
|
5
5
|
"notes-listen.test.js",
|
|
6
|
-
"notes-final.test.js"
|
|
6
|
+
"notes-final.test.js",
|
|
7
|
+
"notes-qwen.test.js"
|
|
7
8
|
],
|
|
8
9
|
"panels": [
|
|
9
10
|
"pm-notes-test.js"
|
|
@@ -12,6 +13,7 @@
|
|
|
12
13
|
"notes.test.js": 12,
|
|
13
14
|
"pm-notes-test.js": 40,
|
|
14
15
|
"notes-listen.test.js": 10,
|
|
15
|
-
"notes-final.test.js": 6
|
|
16
|
+
"notes-final.test.js": 6,
|
|
17
|
+
"notes-qwen.test.js": 4
|
|
16
18
|
}
|
|
17
19
|
}
|