create-pmos 0.522.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.
- package/bin/create-pmos.js +26 -1
- package/package.json +57 -47
- 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/changelog.json +56 -0
- package/workspace/guide/agent-capabilities.md +6 -3
- package/workspace/guide/home.md +1 -1
- package/workspace/guide/horizon-scan.md +2 -2
- package/workspace/guide/idle-lab.md +46 -0
- package/workspace/guide/index.md +2 -0
- package/workspace/guide/moments.md +43 -0
- package/workspace/guide/welcome.md +37 -28
- package/workspace/lib/bg-queue.js +226 -0
- package/workspace/lib/connector-read.js +19 -0
- package/workspace/lib/driver-run.js +8 -1
- package/workspace/lib/first-reveal.js +311 -0
- package/workspace/lib/headless.js +2 -2
- package/workspace/lib/idle-lab.js +275 -0
- package/workspace/lib/moments.js +241 -0
- package/workspace/lib/morning-goals.js +191 -0
- package/workspace/lib/onboard-fundamentals.js +205 -0
- package/workspace/lib/onboarding-progress.js +13 -1
- package/workspace/lib/orchestrator-spawn.js +9 -2
- package/workspace/lib/project-onboard.js +93 -22
- package/workspace/lib/proposals.js +9 -5
- package/workspace/lib/refresh-run.js +2 -1
- package/workspace/lib/route-modules.js +4 -0
- package/workspace/lib/routes-lab.js +137 -0
- package/workspace/lib/routes-loose.js +1 -0
- package/workspace/lib/routes-moments.js +42 -0
- package/workspace/lib/routes-morning-goals.js +109 -0
- package/workspace/lib/routes-onboard.js +45 -8
- package/workspace/lib/routes-proposals.js +12 -2
- package/workspace/lib/routes-reveal.js +73 -0
- package/workspace/lib/scan-run.js +4 -3
- package/workspace/lib/scan.js +5 -3
- package/workspace/package-lock.json +2 -2
- package/workspace/package.json +1 -1
- package/workspace/project-onboard-flow-test.js +70 -57
- package/workspace/public/pm/cozy-ev.css +3 -0
- package/workspace/public/pm/cozy-lab-ins.js +87 -0
- package/workspace/public/pm/cozy-lab.css +86 -0
- package/workspace/public/pm/cozy-lab.js +138 -0
- package/workspace/public/pm/cozy-nav.js +22 -8
- package/workspace/public/pm/cozy-onboard.css +31 -0
- package/workspace/public/pm/cozy-onboard.js +217 -111
- package/workspace/public/pm/cozy-reveal.css +52 -0
- package/workspace/public/pm/cozy-reveal.js +130 -0
- package/workspace/public/pm/home-app.js +38 -3
- package/workspace/public/pm/home-impact.css +12 -0
- package/workspace/public/pm/home-moment.js +41 -0
- package/workspace/public/pm/ini-props.js +15 -6
- package/workspace/public/pm/premium-board.js +2 -0
- package/workspace/public/pm/premium-first.js +1 -1
- package/workspace/public/pm/premium-insights.js +6 -1
- package/workspace/public/pm/quiet-place.js +31 -0
- package/workspace/public/premium-intelligence.html +3 -0
- package/workspace/replaced-tests.json +14 -0
- package/workspace/server.js +46 -5
- package/workspace/test-files.json +2 -0
- package/workspace/test-lists/first-reveal.json +9 -0
- package/workspace/test-lists/idle-lab.json +9 -0
- package/workspace/test-lists/morning-goals.json +9 -0
package/workspace/server.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
}
|