create-pmos 0.128.0 → 0.130.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/state/discoveries.md +1 -1
- package/workspace/c3-one-home-test.js +4 -1
- package/workspace/guide/briefing.md +60 -0
- package/workspace/guide/calendar-popup.md +46 -0
- package/workspace/guide/index.md +3 -0
- package/workspace/guide/layout.md +1 -0
- package/workspace/guide/proactive-engine.md +2 -2
- package/workspace/lib/day-run.js +4 -0
- package/workspace/lib/route-modules.js +1 -0
- package/workspace/lib/routes-brief-page.js +187 -0
- package/workspace/package-lock.json +2 -2
- package/workspace/package.json +1 -1
- package/workspace/public/pm/c3-brief-data.js +11 -0
- package/workspace/public/pm/c3-brief-needs.js +145 -0
- package/workspace/public/pm/c3-brief-pulse.js +70 -0
- package/workspace/public/pm/c3-brief-today.js +44 -0
- package/workspace/public/pm/c3-calpop.js +103 -0
- package/workspace/public/pm/c3-demo-brief-page.js +54 -0
- package/workspace/public/pm/c3-demo.js +1 -1
- package/workspace/public/pm/c3-shell.js +26 -148
- package/workspace/public/pm/calendar-views.js +1 -0
- package/workspace/public/pm/console3.css +43 -0
- package/workspace/server.js +30 -9
- package/workspace/test-files.json +5 -1
- package/workspace/test-lists/calpop.json +4 -0
package/workspace/server.js
CHANGED
|
@@ -2669,10 +2669,14 @@ function adoptOrphanTmuxSessions() {
|
|
|
2669
2669
|
for (const t of tmuxList().sort((a, b) => a.created - b.created)) {
|
|
2670
2670
|
if (!t.name.startsWith('pmos-') || claimed.has(t.name)) continue;
|
|
2671
2671
|
const dir = t.dir && isDir(t.dir) ? path.resolve(t.dir) : null;
|
|
2672
|
-
|
|
2673
|
-
//
|
|
2674
|
-
//
|
|
2675
|
-
|
|
2672
|
+
const start = t.start && isDir(t.start) ? path.resolve(t.start) : null;
|
|
2673
|
+
// Where it belongs: the workspace containing the directory the pane STARTED in, then the one containing where it is
|
|
2674
|
+
// now. Only when neither is registered is a directory registered — the start directory first, because that is a
|
|
2675
|
+
// folder a session was opened in, not wherever the PM last `cd`-ed (registering that made ~ or /tmp a permanent
|
|
2676
|
+
// workspace). The current directory is the last resort, kept because a pane the PM can see must be one they can
|
|
2677
|
+
// reach; the home workspace is assumed only when there is no readable directory at all.
|
|
2678
|
+
const w = workspaceForPath(start) || workspaceForPath(dir) || (start && registerWorkspace(start))
|
|
2679
|
+
|| (dir && registerWorkspace(dir)) || homeWorkspace();
|
|
2676
2680
|
if (!w) continue;
|
|
2677
2681
|
const id = nextSessionId();
|
|
2678
2682
|
// The agent is the pane's own start command, not a guess: tmux spawned it directly (see
|
|
@@ -2680,7 +2684,7 @@ function adoptOrphanTmuxSessions() {
|
|
|
2680
2684
|
const agent = adoptedAgent(t.cmd);
|
|
2681
2685
|
const s = {
|
|
2682
2686
|
id, ws: w.id, root: w.root, name: `recovered ${agent}`, agent,
|
|
2683
|
-
origin: null, cwd: dir && insideRoot(w.root, dir) ? dir : w.root,
|
|
2687
|
+
origin: t.origin || null, cwd: dir && insideRoot(w.root, dir) ? dir : w.root,
|
|
2684
2688
|
state: 'working', pty: null, tmux: t.name, note: '', buf: '',
|
|
2685
2689
|
cols: 80, rows: 24, clients: new Set(), created: nowISO(), recovered: true,
|
|
2686
2690
|
};
|
|
@@ -3115,6 +3119,10 @@ function tmuxList() {
|
|
|
3115
3119
|
.map((name) => ({
|
|
3116
3120
|
name,
|
|
3117
3121
|
dir: tmuxField(name, '#{pane_current_path}'),
|
|
3122
|
+
// Where the pane STARTED (the -c of new-session): the workspace it was opened in. The current path follows every
|
|
3123
|
+
// `cd`, so a pane the PM moved to ~ or /tmp would otherwise file itself under that folder.
|
|
3124
|
+
start: tmuxField(name, '#{pane_start_path}'),
|
|
3125
|
+
origin: tmuxField(name, '#{@pmos_origin}'),
|
|
3118
3126
|
created: Number(tmuxField(name, '#{session_created}')) || 0,
|
|
3119
3127
|
cmd: tmuxField(name, '#{pane_start_command}'),
|
|
3120
3128
|
}));
|
|
@@ -3461,6 +3469,9 @@ function spawnSession({ name, agent, cwd, ws, origin, initialInput, profile, ini
|
|
|
3461
3469
|
s.buf = `\x1b[38;5;203m✗ ${why}\x1b[0m\r\n\x1b[38;5;244mFix the above, then ↻ respawn.\x1b[0m\r\n`;
|
|
3462
3470
|
persist(s); pushSessions(); pushWorkspaces(); return s;
|
|
3463
3471
|
}
|
|
3472
|
+
// The origin rides on the tmux session itself (a user option), so a pane whose record is lost is adopted with it:
|
|
3473
|
+
// a recovered automatic job stays automatic and the sweep can still end it. One cheap call, only when there is one.
|
|
3474
|
+
if (origin) tmuxCtl(['set-option', '-t', tname, '@pmos_origin', String(origin)]);
|
|
3464
3475
|
announceStateHealth(s); // the unmigrated notice comes FIRST — it explains an empty skills list
|
|
3465
3476
|
announceTree(s); // before attach, so the advisory is the first line of the pane's record
|
|
3466
3477
|
announceModel(s);
|
|
@@ -3990,9 +4001,19 @@ function startDayCheck(run, reason, now) {
|
|
|
3990
4001
|
if (run.checks.session_id) run = dayRunLib.sessionEnded(run, run.checks.session_id, now).run;
|
|
3991
4002
|
const sk = daySkillPrompt(run, 'day-check');
|
|
3992
4003
|
if (sk.error) return { ok: false, error: sk.error };
|
|
3993
|
-
const
|
|
3994
|
-
|
|
3995
|
-
|
|
4004
|
+
const line = `This run: /day-check ${reason} — the last check was at ${run.checks.last || 'none yet'}; read what changed since ${run.checks.last || run.started_at}.`;
|
|
4005
|
+
// The last check's session is used again while it is open and quiet: it has the skill in its context, so only this
|
|
4006
|
+
// run's line is typed into it. Before, every check started a new session and the old one sat idle until the sweep
|
|
4007
|
+
// ended it, about one more process per interval (workspace-session-lifecycle).
|
|
4008
|
+
const prev = run.checks.prev_session && sessions.get(run.checks.prev_session);
|
|
4009
|
+
let s = null;
|
|
4010
|
+
if (prev && prev.pty && prev.state !== 'exited' && harness.deriveState(prev.state, prev.lastOutputAt, now).state !== 'working') {
|
|
4011
|
+
try { firstInput.deliver(prev, line + '\r'); s = prev; } catch { s = null; }
|
|
4012
|
+
}
|
|
4013
|
+
if (!s) {
|
|
4014
|
+
s = spawnSession({ name: 'Daytime check', agent: sk.task.agent || 'claude', ws: sk.w ? sk.w.id : run.ws, origin: 'day-check', initialInput: `${sk.prompt}\n\n${line}\r`,
|
|
4015
|
+
modelAsk: { scheduleTier: null, skillTier: sk.task.tier || null, skill: sk.task.skill } });
|
|
4016
|
+
}
|
|
3996
4017
|
if (s.state === 'exited') return { ok: false, error: s.note || 'the check session could not start' };
|
|
3997
4018
|
const c = dayRunLib.checkStarted(run, s.id, reason, now);
|
|
3998
4019
|
return c.ok ? { ok: true, run: c.run, session: s.id } : c;
|
|
@@ -9013,7 +9034,7 @@ if (require.main === module) {
|
|
|
9013
9034
|
});
|
|
9014
9035
|
});
|
|
9015
9036
|
}
|
|
9016
|
-
module.exports = { server, online: { ONLINE, applyOnline, tunnel, publicHost }, spawnSession, removeSession, sweepAutomaticSessions, endSupersededRuns, renameSession, sessions, libraryTree, readTextDoc,
|
|
9037
|
+
module.exports = { server, online: { ONLINE, applyOnline, tunnel, publicHost }, spawnSession, removeSession, sweepAutomaticSessions, endSupersededRuns, adoptOrphanTmuxSessions, renameSession, sessions, libraryTree, readTextDoc,
|
|
9017
9038
|
registerWorkspace, forgetWorkspace, workspaces, library, initiativeIndex, fsList,
|
|
9018
9039
|
// R1 — exported so the suite can assert the CARRY-THROUGH: branchInfo separates an ordinary
|
|
9019
9040
|
// non-repo folder from a real git fault, and the whole legibility defect was that distinction
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"pm-items.test.js",
|
|
26
26
|
"jobs-to-be-done.test.js",
|
|
27
27
|
"pm-items-routes.test.js",
|
|
28
|
+
"brief-page.test.js",
|
|
28
29
|
"item-steps.test.js",
|
|
29
30
|
"status-facts-panel.test.js",
|
|
30
31
|
"jev-claims.test.js",
|
|
@@ -122,7 +123,8 @@
|
|
|
122
123
|
"pm-breakdown-phone-test.js",
|
|
123
124
|
"first-paint-count.test.js",
|
|
124
125
|
"pm-card-layout-test.js",
|
|
125
|
-
"pm-portfolio-inline-test.js"
|
|
126
|
+
"pm-portfolio-inline-test.js",
|
|
127
|
+
"pm-brief-page-test.js"
|
|
126
128
|
],
|
|
127
129
|
"ui": [
|
|
128
130
|
"ui-test.js"
|
|
@@ -145,6 +147,8 @@
|
|
|
145
147
|
"pm-items.test.js": 1,
|
|
146
148
|
"jobs-to-be-done.test.js": 1,
|
|
147
149
|
"pm-items-routes.test.js": 1,
|
|
150
|
+
"brief-page.test.js": 1,
|
|
151
|
+
"pm-brief-page-test.js": 30,
|
|
148
152
|
"item-steps.test.js": 1,
|
|
149
153
|
"status-facts-panel.test.js": 1,
|
|
150
154
|
"jev-claims.test.js": 3,
|