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.
@@ -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 3 GB. Then open Settings again.' }
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' }, !w ? 'Reading …' : w.ready ? 'Whisper is set up. The microphone and the meeting are transcribed on this machine.'
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 3 GB.') : null,
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);
@@ -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 is for the LOCAL inner loop only. It narrows the group to the suites a diff against REF
22
- * (default origin/main) can reach, and runs the whole group whenever it cannot tell. CI never passes
23
- * it: Workspace CI runs every suite on every PR, so a suite --changed leaves out still runs before
24
- * the merge. See changedSuites() for the rule.
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; CI runs all ${list.length}.`);
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 9: 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), and the Notes view in a browser (pm-notes-test.js).",
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
  }
@@ -53,6 +53,7 @@
53
53
  "no-network.test.js": 1,
54
54
  "notes-final.test.js": 2,
55
55
  "notes-listen.test.js": 2,
56
+ "notes-qwen.test.js": 2,
56
57
  "notes.test.js": 5,
57
58
  "online-mode.test.js": 1,
58
59
  "people.test.js": 2,