create-pmos 0.517.0 → 0.519.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 +39 -73
- 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/state/discoveries.md +1 -1
- package/workspace/board-columns-test.js +1 -1
- package/workspace/board-programs-test.js +26 -7
- package/workspace/briefing-premium-board-test.js +3 -3
- package/workspace/calm-timeline-test.js +2 -2
- package/workspace/changelog.json +38 -0
- package/workspace/guide/data-freshness.md +26 -4
- package/workspace/guide/index.md +2 -2
- package/workspace/guide/next-prompt.md +4 -2
- package/workspace/guide/programs.md +2 -1
- package/workspace/guide/settings.md +1 -1
- package/workspace/lib/headless.js +12 -2
- package/workspace/lib/refresh-run.js +39 -2
- package/workspace/lib/routes-next-prompt.js +67 -27
- package/workspace/lib/routes-sources.js +6 -2
- package/workspace/lib/source-heal.js +140 -0
- package/workspace/package-lock.json +2 -2
- package/workspace/package.json +1 -1
- package/workspace/public/pm/bd-span.js +13 -17
- package/workspace/public/pm/cozy-evmodel.js +18 -1
- package/workspace/public/pm/cozy-nav.js +5 -5
- package/workspace/public/pm/cozy-settings.js +23 -16
- package/workspace/public/pm/premium-vw-guide.css +7 -2
- package/workspace/server.js +1 -1
|
@@ -25,15 +25,15 @@
|
|
|
25
25
|
* Adler's moments (batch 17 item 4-B, AdM4): one face per section, where Claude speaks. Updates: glasses while it checks or installs,
|
|
26
26
|
* holding the card when a version is ready, calm when up to date. General: holding the update card, else the Jira promise (only after
|
|
27
27
|
* Commit). A failure in the status line takes the honest face, and then the section's face steps back (one Adler per screen).
|
|
28
|
-
* The card at the bottom of General says when an update is ready. While a source
|
|
29
|
-
* it with
|
|
28
|
+
* The card at the bottom of General says when an update is ready. While a source needs you (lib/source-heal.js), an amber box at the top of every section names
|
|
29
|
+
* it with its one action and what Claude tried, and the place menu opens Settings at Connectors. Every write is the PM's press (pmPost carries the launch nonce).
|
|
30
30
|
* PMOS reads the sources and never posts to them.
|
|
31
31
|
* openSettings(section?) */
|
|
32
32
|
import { mountClaudeSetup } from './cozy-claude-setup.js';
|
|
33
33
|
import * as JL from './cozy-jl.js';
|
|
34
34
|
import { pmGet, pmPost, pressFetch } from './http.js';
|
|
35
35
|
import { esc, svg, ICON, toast, wsParam, wsQ } from './cozy-evui.js';
|
|
36
|
-
import { sourceRows,
|
|
36
|
+
import { sourceRows, bannerOf } from './cozy-evmodel.js';
|
|
37
37
|
import * as AD from './cozy-adler.js';
|
|
38
38
|
import * as SE from './cozy-seasons.js';
|
|
39
39
|
import { weeksOf, lineOf, storiesOf } from './upd-weeks.js';
|
|
@@ -182,11 +182,16 @@ function readsHtml() {
|
|
|
182
182
|
const L = T.lines ? [['Today', T.lines.readLine(s, ['calendar'])], ['Needs you', T.lines.readLine(s, ['initiatives', 'my-work', 'd:brief'])]].filter((x) => x[1]) : [];
|
|
183
183
|
return `${health}<div class="ev-reads">${rows}</div>${L.map(([k, v]) => `<p class="ev-small ev-mut ev-rl" data-reads="${esc(k)}"><b>${esc(k)}:</b> ${esc(v)}</p>`).join('')}`;
|
|
184
184
|
}
|
|
185
|
-
/** The amber box at the top of Settings
|
|
185
|
+
/** The amber box at the top of Settings, only when the PM must act on a source (self-heal, feedback batch 26 item 7). While Claude
|
|
186
|
+
* reads a source again by itself, or after it did, there is no box. The box names the one action and links to the exact place:
|
|
187
|
+
* the Claude connectors, Settings › Claude, or ↻ when only a press reads it. It says what Claude already tried. */
|
|
186
188
|
function staleHtml() {
|
|
187
|
-
const
|
|
188
|
-
if (!
|
|
189
|
-
|
|
189
|
+
const b = T.fresh && T.fresh.ok ? bannerOf(T.fresh.sources) : null;
|
|
190
|
+
if (!b) return '';
|
|
191
|
+
const a = b.action;
|
|
192
|
+
const act = a.read ? readBtn(b.id, a.label, 'ev-ib ev-ib-card')
|
|
193
|
+
: `<a class="ev-ib ev-ib-card" href="${esc(a.href || '#' + a.sec)}"${a.href ? ' target="_blank" rel="noopener"' : ` data-ev-sec="${esc(a.sec)}"`} aria-label="${esc(a.label)}" title="${esc(a.label)}">${svg(ICON.open, 18)}</a>`;
|
|
194
|
+
return `<div class="ev-warn ev-line ev-st-warn" id="srcWarn" data-cause="${esc(b.cause || '')}"><i class="ev-dot risk" aria-hidden="true"></i><p class="ev-grow"><b>${esc(b.title)}</b> ${esc(b.body)}${a.read ? '' : ' ' + esc(a.how)}</p>${act}</div>`;
|
|
190
195
|
}
|
|
191
196
|
function connectors() {
|
|
192
197
|
if (T.src === null) return readsHtml() + '<p class="ev-small ev-mut">Reading the connectors.</p>';
|
|
@@ -265,18 +270,19 @@ function claudeSec() {
|
|
|
265
270
|
return '<h4>Claude login and profile</h4><div data-claude-setup></div>'
|
|
266
271
|
+ trow('API key', keySub, keyRight)
|
|
267
272
|
+ (k.present && C.off ? trow('Runs on the API', 'Off: PMOS_GRILL_API is off in the environment.', '<span class="ev-pill">Off</span>') : '')
|
|
268
|
-
+ sharpenRows(
|
|
273
|
+
+ sharpenRows();
|
|
269
274
|
}
|
|
270
275
|
/* Settings › Claude › Sharpen prompts (batch 26 item 2; pm/next-prompt-ui.js, lib/routes-next-prompt.js): the suggestions after a reply, Sharpen as I
|
|
271
|
-
* type (
|
|
276
|
+
* type (on by default: both run as a background `claude -p` in the PM's own Claude session, Wawan 2026-11-04), the style, and Your own rules.
|
|
272
277
|
* The same style and switch are in the chat's Sharper card menu; a save here tells the chat (the event pmos:prompt-prefs). */
|
|
273
278
|
const NPK = { 'prompt.next': ['nextSet', 'next'], 'prompt.sharpen': ['sharpenSet', 'sharpen'], 'prompt.style': ['style', 'style'], 'prompt.rules': ['rulesText', 'rules'] }; // row key → [GET field, POST key]
|
|
274
279
|
const setVal = (k, d) => { const v = T.np ? T.np[NPK[k][0]] : undefined; return v !== undefined && v !== null ? v : d; };
|
|
275
|
-
function sharpenRows(
|
|
280
|
+
function sharpenRows() {
|
|
276
281
|
const next = setVal('prompt.next', true) !== false, sh = setVal('prompt.sharpen', 'auto'), style = setVal('prompt.style', 'engineer'), rules = String(setVal('prompt.rules', '') || '');
|
|
277
|
-
const on = sh
|
|
278
|
-
const
|
|
279
|
-
|
|
282
|
+
const on = sh !== 'off' && !(T.np && T.np.sharpen === false && sh === 'auto');
|
|
283
|
+
const down = T.np && T.np.apiDown;
|
|
284
|
+
const shSub = !on ? (down && down.auth ? 'Off for now: your API key was refused. Replace it under API key above.' : 'Off. No spinner and no Sharper card.')
|
|
285
|
+
: 'When you pause on a rough prompt, Claude writes a sharper version above the box. It runs in your Claude session and takes a few seconds.';
|
|
280
286
|
const styleSub = style === 'polish' ? 'Clearer and shorter, your meaning kept.' : style === 'own' ? (rules.trim() ? 'Your rules below.' : 'Write your rules below first.') : 'Builds the best prompt for the job.';
|
|
281
287
|
return '<h4>Sharpen prompts</h4>'
|
|
282
288
|
+ trow('Suggest the next prompt', 'After a reply, up to two prompts above the box. A tap puts one in the box. Nothing sends.', sw(next, 'data-ev-np="prompt.next"', 'Suggest the next prompt'))
|
|
@@ -315,8 +321,8 @@ function draw() {
|
|
|
315
321
|
// a redraw replaces the nodes: keep focus on the same control (by its data-ev-* key), else on the open section, never on the body
|
|
316
322
|
const ae = document.activeElement, had = ae && el.contains(ae), key = had ? [...ae.attributes].find((a) => a.name.startsWith('data-ev-')) : null;
|
|
317
323
|
const n = { connectors: T.src === null ? '' : Object.keys(SRC).filter((k) => T.src[k]).length + T.conn.filter((c) => !c.source && T.con[c.name]).length, workspaces: T.ws ? T.ws.filter((x) => !x.linked).length : '', updates: ready() ? '<span class="ev-pill y">1</span>' : '' };
|
|
318
|
-
const stale = T.fresh && T.fresh.ok ?
|
|
319
|
-
el.querySelector('.ev-st-nav').innerHTML = '<h2 class="ev-h2">Settings</h2>' + SECTIONS.map(([k, l]) => PAGE_LINKS[k] ? `<a href="${PAGE_LINKS[k]}" class="ev-mi">${esc(l)}</a>` : `<a href="#${k}" class="ev-mi" data-ev-sec="${k}"${T.sec === k ? ' aria-current="page"' : ''}>${esc(l)}${k === 'connectors' && stale ? '<i class="ev-dot risk" aria-label="A source
|
|
324
|
+
const stale = T.fresh && T.fresh.ok ? bannerOf(T.fresh.sources) : null;
|
|
325
|
+
el.querySelector('.ev-st-nav').innerHTML = '<h2 class="ev-h2">Settings</h2>' + SECTIONS.map(([k, l]) => PAGE_LINKS[k] ? `<a href="${PAGE_LINKS[k]}" class="ev-mi">${esc(l)}</a>` : `<a href="#${k}" class="ev-mi" data-ev-sec="${k}"${T.sec === k ? ' aria-current="page"' : ''}>${esc(l)}${k === 'connectors' && stale ? '<i class="ev-dot risk" aria-label="A source needs you" role="img"></i>' : ''}${n[k] !== undefined && n[k] !== '' ? `<span class="ev-k">${typeof n[k] === 'number' ? n[k] : n[k]}</span>` : ''}</a>`).join('');
|
|
320
326
|
const label = (SECTIONS.find((x) => x[0] === T.sec) || SECTIONS[0])[1];
|
|
321
327
|
const all = T.sec === 'connectors' ? `<button type="button" class="ev-ib" data-ev-readall aria-label="Read every source again" title="Read all again"${T.reading ? ' disabled' : ''}>${svg(RD, 18)}</button>` : '';
|
|
322
328
|
el.querySelector('.ev-st-main').innerHTML = staleHtml() + `<div class="ev-top"><h3 class="ev-h2" id="evStTitle">${esc(label)}</h3>${all}<button type="button" class="ev-ib" data-ev-close aria-label="Close settings" title="Close settings">${svg(ICON.close, 18)}</button></div>`
|
|
@@ -375,7 +381,7 @@ async function press(e) {
|
|
|
375
381
|
}
|
|
376
382
|
if (t.dataset.evSeg === 'prompt.style') { await savePrompt('prompt.style', t.dataset.v, 'Saved. Sharper prompts follow this style.'); return; }
|
|
377
383
|
if (t.dataset.evNp === 'prompt.next') { const on = setVal('prompt.next', true) === false; await savePrompt('prompt.next', on, on ? 'Saved. Claude suggests the next prompt after a reply.' : 'Saved. No suggestions after a reply.'); return; }
|
|
378
|
-
if (t.dataset.evNp === 'prompt.sharpen') { const
|
|
384
|
+
if (t.dataset.evNp === 'prompt.sharpen') { const sh = setVal('prompt.sharpen', 'auto'), was = sh !== 'off' && !(T.np && T.np.sharpen === false && sh === 'auto'); await savePrompt('prompt.sharpen', was ? 'off' : 'on', was ? 'Saved. Sharpen as I type is off.' : 'Saved. Sharpen as I type is on.'); return; }
|
|
379
385
|
if ('evRulesave' in t.dataset) { const ta = T.el.querySelector('#evRules'); await savePrompt('prompt.rules', ta ? ta.value.slice(0, 1000) : '', 'Saved. Your own rules are used when Sharpen as is Your own.'); return; }
|
|
380
386
|
if (t.dataset.evSeg && t.dataset.evSeg.startsWith('adler.')) { const r = await AD.savePref(pmPost, t.dataset.evSeg, t.dataset.v); T.msg = r && r.ok ? 'Saved.' : (r && r.error) || 'Not saved.'; draw(); return; }
|
|
381
387
|
if (t.dataset.evDress) {
|
|
@@ -512,6 +518,7 @@ async function load() {
|
|
|
512
518
|
export function openSettings(section) {
|
|
513
519
|
const el = mount();
|
|
514
520
|
if (section === 'dress') { T.sec = 'adler'; T.dress = true; } else if (section && BODY[section]) { T.sec = section; T.dress = false; }
|
|
521
|
+
else if (el.hidden) { T.sec = 'general'; T.dress = false; } // a fresh open with no section opens on General (R2), not on the section of the last visit
|
|
515
522
|
if (el.hidden) { const ae = document.activeElement; T.back = ae && ae !== document.body ? ae : null; T.ws = null; T.src = null; T.msg = ''; T.phase = ''; T.auto = false; T.wkOpen = new Set(); T.wkMore = new Set(); T.arc = false; T.fresh = null; T.note = {}; T.dset = {}; T.cl = null; T.gr = null; T.np = null; JL.reset(); }
|
|
516
523
|
el.hidden = false; document.getElementById('evStScrim').hidden = false; el.setAttribute('data-esc-layer', '');
|
|
517
524
|
draw();
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
@font-face{font-family:"Space Grotesk";src:url(/vendor/space-grotesk-var.woff2) format("woff2");font-weight:300 700;font-display:swap}
|
|
2
|
+
@font-face{font-family:"IBM Plex Mono";src:url(/vendor/ibm-plex-mono-400.woff2) format("woff2");font-weight:400;font-display:swap}
|
|
3
|
+
@font-face{font-family:"IBM Plex Mono";src:url(/vendor/ibm-plex-mono-500.woff2) format("woff2");font-weight:500;font-display:swap}
|
|
4
|
+
@font-face{font-family:"IBM Plex Mono";src:url(/vendor/ibm-plex-mono-700.woff2) format("woff2");font-weight:600 700;font-display:swap}
|
|
5
|
+
:root{--fw-regular:400;--fw-strong:600;--fs-field:16px;--fs-display:26px;--fs-page:26px;--fs-panel:18px;--fs-section:15px;--fs-row:15px;--fs-body:15px;--fs-meta:13px;--fs-label:13px;--fs-badge:13px;--lh-display:1.2;--lh-page:1.2;--lh-panel:1.3;--lh-section:1.35;--lh-row:1.4;--lh-body:1.6;--lh-meta:1.5;--lh-label:1.35;--lh-badge:1.2}
|
|
1
6
|
/* premium-vw-guide.css — the guide in the Viewer (premium-vw-guide.js; canvas Exploring › User guide, option B): a page rail on the left,
|
|
2
7
|
* the page on the right with its section chips. Under 720 px the rail hides and the list icon shows it over the page. Quiet: hairlines, one
|
|
3
8
|
* well for the open page, no colour but the chips' hover. */
|
|
4
|
-
.vwdoc.gd{padding:0}
|
|
9
|
+
.vwdoc.gd{padding:0;max-width:none}
|
|
5
10
|
.gd-wrap{container-type:inline-size;display:flex;align-items:flex-start;gap:20px;position:relative}
|
|
6
11
|
.gd-rail{width:248px;flex:none;position:sticky;top:0;max-height:calc(100vh - 140px);overflow:auto;padding:4px 4px 16px 0;display:flex;flex-direction:column;gap:2px}
|
|
7
|
-
.gd-read{flex:1;min-width:0}
|
|
12
|
+
.gd-read{flex:1;min-width:0;max-width:none}
|
|
8
13
|
.gd-tog{display:none}
|
|
9
14
|
.gd-find{display:flex;align-items:center;gap:8px;height:40px;padding:0 10px;margin:0 0 6px;border-radius:10px;background:var(--well);color:var(--ink-3)}
|
|
10
15
|
.gd-find .i{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;flex:none}
|
package/workspace/server.js
CHANGED
|
@@ -4475,7 +4475,7 @@ function startHeadless(base, workdir, kind, launchArgs, env, initialInput, addDi
|
|
|
4475
4475
|
// grandchild keeps the output pipes open after the run is stopped.
|
|
4476
4476
|
// Windows: `claude` installed by npm is claude.cmd, which spawn() cannot start by name (lib/win-command.js).
|
|
4477
4477
|
const run = winCommand.resolve(base.agent, { env });
|
|
4478
|
-
try { child = spawn(run.file, [...run.prefix, ...args], { cwd: workdir, env, stdio: ['pipe', 'pipe', 'pipe'], detached: true }); }
|
|
4478
|
+
try { child = spawn(run.file, [...run.prefix, ...args], { cwd: workdir, env: headlessLib.headlessEnv(env), stdio: ['pipe', 'pipe', 'pipe'], detached: true }); }
|
|
4479
4479
|
catch (e) {
|
|
4480
4480
|
s.state = 'exited'; s.note = spawnFailureAdvice(e, base.agent, false);
|
|
4481
4481
|
say(`\x1b[38;5;203m✗ ${s.note}\x1b[0m\n`); persist(s); pushSessions(); pushWorkspaces(); return s;
|