create-pmos 0.523.0 → 0.524.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.
Files changed (61) hide show
  1. package/package.json +44 -16
  2. package/payload/KIT-VERSION +1 -1
  3. package/payload/planning/evals/eval-calibration.md +1 -1
  4. package/payload/planning/okrs/health-budgets.md +1 -1
  5. package/payload/state/discoveries.md +1 -1
  6. package/workspace/changelog.json +43 -0
  7. package/workspace/guide/agent-capabilities.md +6 -3
  8. package/workspace/guide/home.md +1 -1
  9. package/workspace/guide/horizon-scan.md +2 -2
  10. package/workspace/guide/idle-lab.md +46 -0
  11. package/workspace/guide/index.md +2 -0
  12. package/workspace/guide/moments.md +43 -0
  13. package/workspace/guide/welcome.md +37 -28
  14. package/workspace/lib/bg-queue.js +226 -0
  15. package/workspace/lib/driver-run.js +8 -1
  16. package/workspace/lib/first-reveal.js +311 -0
  17. package/workspace/lib/idle-lab.js +275 -0
  18. package/workspace/lib/moments.js +241 -0
  19. package/workspace/lib/morning-goals.js +191 -0
  20. package/workspace/lib/onboard-fundamentals.js +205 -0
  21. package/workspace/lib/onboarding-progress.js +13 -1
  22. package/workspace/lib/orchestrator-spawn.js +9 -2
  23. package/workspace/lib/project-onboard.js +86 -6
  24. package/workspace/lib/proposals.js +9 -5
  25. package/workspace/lib/route-modules.js +4 -0
  26. package/workspace/lib/routes-lab.js +137 -0
  27. package/workspace/lib/routes-loose.js +1 -0
  28. package/workspace/lib/routes-moments.js +42 -0
  29. package/workspace/lib/routes-morning-goals.js +109 -0
  30. package/workspace/lib/routes-onboard.js +28 -8
  31. package/workspace/lib/routes-proposals.js +12 -2
  32. package/workspace/lib/routes-reveal.js +73 -0
  33. package/workspace/lib/scan-run.js +4 -3
  34. package/workspace/lib/scan.js +5 -3
  35. package/workspace/package-lock.json +2 -2
  36. package/workspace/package.json +1 -1
  37. package/workspace/project-onboard-flow-test.js +70 -57
  38. package/workspace/public/pm/cozy-ev.css +3 -0
  39. package/workspace/public/pm/cozy-lab-ins.js +87 -0
  40. package/workspace/public/pm/cozy-lab.css +86 -0
  41. package/workspace/public/pm/cozy-lab.js +138 -0
  42. package/workspace/public/pm/cozy-nav.js +22 -8
  43. package/workspace/public/pm/cozy-onboard.css +31 -0
  44. package/workspace/public/pm/cozy-onboard.js +217 -111
  45. package/workspace/public/pm/cozy-reveal.css +52 -0
  46. package/workspace/public/pm/cozy-reveal.js +130 -0
  47. package/workspace/public/pm/home-app.js +38 -3
  48. package/workspace/public/pm/home-impact.css +12 -0
  49. package/workspace/public/pm/home-moment.js +41 -0
  50. package/workspace/public/pm/ini-props.js +15 -6
  51. package/workspace/public/pm/premium-board.js +2 -0
  52. package/workspace/public/pm/premium-first.js +1 -1
  53. package/workspace/public/pm/premium-insights.js +6 -1
  54. package/workspace/public/pm/quiet-place.js +31 -0
  55. package/workspace/public/premium-intelligence.html +3 -0
  56. package/workspace/replaced-tests.json +14 -0
  57. package/workspace/server.js +46 -5
  58. package/workspace/test-files.json +2 -0
  59. package/workspace/test-lists/first-reveal.json +9 -0
  60. package/workspace/test-lists/idle-lab.json +9 -0
  61. package/workspace/test-lists/morning-goals.json +9 -0
@@ -2732,6 +2732,8 @@ const orchGate = require('./lib/orchestrator-gate.js').create({ dir: STATE, quot
2732
2732
  const driver = driverRunLib.create({
2733
2733
  mayStart: ({ running }) => orchGate.mayStart({ running: running + orchSpawn.own() + chatWorking() }),
2734
2734
  started: () => orchGate.granted(),
2735
+ // bg-queue: one background run per initiative. The Driver's own runs are left out: lib/driver.js plan never starts two on one target.
2736
+ holder: (ini) => (bgQueue ? bgQueue.holder(ini, 'drive:') : null),
2735
2737
  workspaces: () => [...workspaces.values()],
2736
2738
  isLead: (w) => isPlanNeedsTree(w),
2737
2739
  stateDirFor: (w) => stateDirFor(w),
@@ -2759,7 +2761,9 @@ function chatWorking(now = Date.now()) {
2759
2761
  for (const s of sessions.values()) if (String(s.origin || '').startsWith('chat:') && s.state !== 'exited' && harness.deriveState(s.state, s.lastOutputAt, now).state === 'working') k++;
2760
2762
  return k;
2761
2763
  }
2762
- const orchSpawn = require('./lib/orchestrator-spawn.js').wrap({ gate: orchGate, spawn: (spec) => spawnSession(spec), driverRunning: () => driver.active().length, pmWorking: () => chatWorking() });
2764
+ let bgQueue = null; // lib/bg-queue.js, built below with the job ticks
2765
+ const orchSpawn = require('./lib/orchestrator-spawn.js').wrap({ gate: orchGate, spawn: (spec) => spawnSession(spec), driverRunning: () => driver.active().length, pmWorking: () => chatWorking(),
2766
+ holder: (ini) => (bgQueue ? bgQueue.holder(ini) : null) }); // bg-queue: one background run per initiative
2763
2767
  // agent-orchestrator: the keep rate of the agent's items, read from every registered repository's Driver and core-document ledgers (cached a minute)
2764
2768
  let orchKeepCache = null;
2765
2769
  const orchKeepRate = () => {
@@ -2848,7 +2852,8 @@ const scanner = scanRunLib.create({
2848
2852
  });
2849
2853
  // PMOS_SCAN_NOW (a local date-time such as 2026-10-12T10:00:00) fixes the scan's clock. The suites use it so a scheduled scan does not wait for a weekday.
2850
2854
  const scanClock = () => { const t = process.env.PMOS_SCAN_NOW ? Date.parse(process.env.PMOS_SCAN_NOW) : NaN; return Number.isFinite(t) ? { now: t } : {}; };
2851
- const scanTick = () => { try { scanner.tick(scanClock()); } catch (e) { warnWriteFail('scan tick', e); } };
2855
+ // idle lab (frame I4): the daily scan waits for the queue's idle turn (turn.idle). The suggest run and Scan now do not wait.
2856
+ const scanTick = (turn = {}) => { try { scanner.tick({ ...scanClock(), idle: turn.idle !== false }); } catch (e) { warnWriteFail('scan tick', e); } };
2852
2857
  // report-workspace: the finder is ONE weekly headless run for the machine, on Monday at 09:00 inside the working hours (lib/report-finder.js). The run
2853
2858
  // reads the PM's calendar, chat, mail subjects and drive through the connectors and files proposals with `pmos report propose`; it sets nothing up.
2854
2859
  // PMOS_REPORT_FIND=off switches it off. PMOS_REPORT_FIND_NOW (a local date-time) fixes its clock for the suites.
@@ -3254,7 +3259,43 @@ const gated = (id, fn) => () => { let g = { ok: true }; try { g = refreshRun.job
3254
3259
  // data-refresh-settings: the seed schedules move to Settings › Data refresh (refreshRun.settings(), once) BEFORE checkDueSchedules reads
3255
3260
  // schedules.json, so a schedule that is moving never fires once more from the old list on the first tick after an upgrade.
3256
3261
  const scheduleOwner = require('./lib/schedule-owner.js').create({ port: PORT });
3257
- try { const _tick = setInterval(() => { try { if (!scheduleOwner.mayRun()) return; } catch { /* no lock: run as before */ } try { refreshRun.settings(); } catch { /* the refresh tick tries again */ } checkDueSchedules(); proactiveTick(); try { prepareTick({ manual: false }); } catch { /* the next tick tries again */ } try { dayTick(); } catch (e) { warnWriteFail('day run tick', e); } try { refreshRun.tick(); } catch (e) { warnWriteFail('refresh tick', e); } try { healthTick(); } catch (e) { warnWriteFail('health tick', e); } gated('sync', () => autoSync.tick().catch(() => {}))(); dashboardScheduleTick(); orchTick(); gated('driver', driverTick)(); gated('scan', scanTick)(); gated('finder', reportFinderTick)(); gated('coredocs', coreDocsTick)(); msReviewTick(); gated('propose', proposalTick)(); grillTick(); metricDraftTick(); impactTick(); metricReadTick(); forecastTick(); reportDesignTick(); reportStructureTick(); }, TICK_MS); if (_tick.unref) _tick.unref(); } catch {}
3262
+ // idle lab (frame I4): ONE queue for all background work (lib/bg-queue.js). Each minute the housekeeping runs first (the refresh settings,
3263
+ // health, the orchestrator's health and backup); then every job takes its turn in the queue's order: 2 due at a set time, 3 the Driver,
3264
+ // 4 deep drafts, 5 the idle lab and slow reads. The queue checks the off switch, the idle clock, quiet hours, the spend limit and the
3265
+ // runs-at-once limit once for every job; a job that goes runs its own tick, with its own due rules. A press by the PM never waits here.
3266
+ bgQueue = require('./lib/bg-queue.js').create({
3267
+ stateDir: STATE,
3268
+ idleFor: (now) => pmIdle.idleFor(now), idleLimit: pmIdle.IDLE_MS,
3269
+ quiet: (now) => proactiveLib.inQuietHours(now, (proSettings() || {}).quiet),
3270
+ running: () => orchSpawn.running(),
3271
+ offOf: (id) => require('./lib/ai-guard.js').off(id, { settingsDir: STATE }),
3272
+ spend: (now) => { const G = require('./lib/grill.js'); let cap = 10; try { const c = Number(require('./lib/settings-store.js').get(STATE, 'grill.cap')); if (Number.isFinite(c) && c >= 0) cap = c; } catch { /* the default cap */ }
3273
+ const b = G.budgetFor(G.read(STATE), { cap, now }); return b.ok ? { atCap: false } : { atCap: true, why: `this month's spend is at the $${cap} limit in Settings › Claude's checks` }; },
3274
+ workEnd: () => { const d = (proSettings() || {}).dayCheck; return d && d.end ? d.end : '18:00'; },
3275
+ sessions: () => [...sessions.values()],
3276
+ warn: (what, e) => warnWriteFail(what, e),
3277
+ });
3278
+ bgQueue.register('schedules', () => checkDueSchedules());
3279
+ bgQueue.register('proactive', () => proactiveTick());
3280
+ bgQueue.register('prepare', () => { try { prepareTick({ manual: false }); } catch { /* the next tick tries again */ } });
3281
+ bgQueue.register('day', () => { try { dayTick(); } catch (e) { warnWriteFail('day run tick', e); } });
3282
+ bgQueue.register('refresh', () => { try { refreshRun.tick(); } catch (e) { warnWriteFail('refresh tick', e); } });
3283
+ bgQueue.register('reports', () => dashboardScheduleTick());
3284
+ bgQueue.register('sync', gated('sync', () => autoSync.tick().catch(() => {})));
3285
+ bgQueue.register('driver', gated('driver', driverTick));
3286
+ bgQueue.register('finder', gated('finder', reportFinderTick));
3287
+ bgQueue.register('coredocs', gated('coredocs', coreDocsTick));
3288
+ bgQueue.register('milestones', () => msReviewTick());
3289
+ bgQueue.register('propose', gated('propose', proposalTick));
3290
+ bgQueue.register('grill', () => grillTick());
3291
+ bgQueue.register('metric-drafts', () => metricDraftTick());
3292
+ bgQueue.register('impact', () => impactTick());
3293
+ bgQueue.register('metric-reads', () => metricReadTick());
3294
+ bgQueue.register('forecast', () => forecastTick());
3295
+ bgQueue.register('report-design', () => reportDesignTick());
3296
+ bgQueue.register('report-structure', () => reportStructureTick());
3297
+ bgQueue.register('scan', (turn) => gated('scan', () => scanTick(turn))());
3298
+ try { const _tick = setInterval(() => { try { if (!scheduleOwner.mayRun()) return; } catch { /* no lock: run as before */ } try { refreshRun.settings(); } catch { /* the refresh tick tries again */ } try { healthTick(); } catch (e) { warnWriteFail('health tick', e); } orchTick(); bgQueue.tick(); }, TICK_MS); if (_tick.unref) _tick.unref(); } catch {}
3258
3299
 
3259
3300
  // ── Sessions: real PTYs, owned by the server, with disk-backed scrollback + metadata. ──
3260
3301
  /** @type {Map<string, {id,ws,name,agent,cwd,state,note,created,pty,buf,cols,rows,clients:Set}>} */
@@ -4596,7 +4637,7 @@ function spawnSession(opts) {
4596
4637
  try { if (s && refreshRun) refreshRun.started(s); } catch (e) { warnWriteFail('refresh log (start)', e); }
4597
4638
  return s;
4598
4639
  }
4599
- function noteSessionEnd(s) { try { if (refreshRun) refreshRun.ended(s); } catch (e) { warnWriteFail('refresh log (end)', e); } }
4640
+ function noteSessionEnd(s) { try { if (refreshRun) refreshRun.ended(s); } catch (e) { warnWriteFail('refresh log (end)', e); } try { if (bgQueue) bgQueue.ended(s); } catch (e) { warnWriteFail('background queue (end)', e); } } // bg-queue: the Lab's record of each background run
4600
4641
  function spawnSessionInner({ name, agent, cwd, ws, origin, initialInput, profile, initiative, modelAsk, planItem, workType, autoDelete, launchFlags, addDirs, onDone, scratch, extraEnv, writePaths, chatClaude, byPm, typedByPm, authLogin }) {
4601
4642
  const id = nextSessionId();
4602
4643
  /* pm-os-absorb Run 1 — every AGENT session gets a token, `<id>.<8 hex>`, in its environment as PMOS_SESSION, and
@@ -10583,7 +10624,7 @@ async function handleRequest(req, res) {
10583
10624
  // pm-os-absorb Runs 2–5 — the planning layer's routes, one file per run (lib/route-modules.js). Last, so none shadows a route above.
10584
10625
  // meeting-notes Run 1: the Notes routes keep notes in the per-user runtime directory and start the agent-summary session.
10585
10626
  if (req.method === 'POST' && !(req.headers && req.headers['x-pmos-session'])) orchGate.touch(); // agent-orchestrator: a page press by the PM
10586
- if (await routeModules.dispatch(req, res, url, { orchestrator: { gate: orchGate, running: () => orchSpawn.running(), health: orchHealth, keepRate: orchKeepRate }, proposalRuns, metricDraftRuns, metricReadRuns, metricReadHours, tellGoalAlert: goalAlertTell, json, readBody, getWs, invalidateNeedsAgg, boardCache, consoleState, stateDirFor, sessionList, initiativeIndex,
10627
+ if (await routeModules.dispatch(req, res, url, { bgQueue, orchestrator: { gate: orchGate, running: () => orchSpawn.running(), health: orchHealth, keepRate: orchKeepRate }, proposalRuns, metricDraftRuns, metricReadRuns, metricReadHours, tellGoalAlert: goalAlertTell, json, readBody, getWs, invalidateNeedsAgg, boardCache, consoleState, stateDirFor, sessionList, initiativeIndex,
10587
10628
  runtimeDir: STATE, claudeSetup, registerWorkspace, pickFolder, broadcast, workspaceList: () => [...workspaces.values()], homeRoot: HOME_ENABLED ? SELF_ROOT : null, spawnSession, jevModelOpts, sendToSession, endSupersededRuns, proSettings,
10588
10629
  // premium-chat-session: every premium chat panel is an interactive Claude Code session the PM talks to (text as typed, `/` kept)
10589
10630
  chatSessions,
@@ -89,9 +89,11 @@
89
89
  "schedule-cli.test.js",
90
90
  "initiative-surface.test.js",
91
91
  "guide.test.js",
92
+ "moments.test.js",
92
93
  "driver.test.js",
93
94
  "driver-server.test.js",
94
95
  "scan.test.js",
96
+ "bg-queue.test.js",
95
97
  "scan-server.test.js",
96
98
  "report-setups.test.js",
97
99
  "report-export.test.js",
@@ -0,0 +1,9 @@
1
+ {
2
+ "_comment": "Onboarding build B2, Home right after setup: the search's facts, the reveal model (ticks, portrait, drafted first initiative), ✓ creating the initiative with its outcome and check date, the route (lib/first-reveal.js, lib/routes-reveal.js). A real kit folder, no Claude process.",
3
+ "modules": [
4
+ "first-reveal.test.js"
5
+ ],
6
+ "seconds": {
7
+ "first-reveal.test.js": 3
8
+ }
9
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "_comment": "Idle lab build U (2026-11-04): what the engine files and the screens read — a result needs its proof and sources, specimens stay in their folder, the compare view leaves unproven Production and Design out, the Lab is silent when empty (lib/idle-lab.js, the lab groups in lib/proposals.js). Pure parts.",
3
+ "modules": [
4
+ "idle-lab.test.js"
5
+ ],
6
+ "seconds": {
7
+ "idle-lab.test.js": 1
8
+ }
9
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "_comment": "Build brief Good morning GM1: the quarter strip's one count of goal states, the PM's quarter line ✦, the morning snapshot, goal tags and what Yes does (lib/morning-goals.js, lib/routes-morning-goals.js). Pure, node.",
3
+ "modules": [
4
+ "morning-goals.test.js"
5
+ ],
6
+ "seconds": {
7
+ "morning-goals.test.js": 1
8
+ }
9
+ }