create-pmos 0.71.1 → 0.72.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.
@@ -24,8 +24,9 @@ import { COPY } from './frame-copy.js';
24
24
 
25
25
  /** The destinations the bar names, in order. Settings sits at the end of the bar, after Sync. Docs joined the bar at the
26
26
  * PM's word (2026-10-06, docs-three-way-sync: "I thought Docs is one of the main menu"). People joined after Docs when the
27
- * PM approved the People mockup and said build it (2026-10-06, people-directory), so the bar holds 9 controls. */
28
- export const BAR_DESTS = Object.freeze(['today', 'initiatives', 'board', 'reports', 'docs', 'people']);
27
+ * PM approved the People mockup and said build it (2026-10-06, people-directory). My work joined beside Agenda when the PM
28
+ * approved the mockup that puts it there and said build it (2026-10-07, my-work), so the bar holds 10 controls. */
29
+ export const BAR_DESTS = Object.freeze(['today', 'mywork', 'initiatives', 'board', 'reports', 'docs', 'people']);
29
30
 
30
31
  /** Is this sync reading "not in sync"? Behind, ahead, records not yet recorded, or `remote_stale`: no fetch in the last
31
32
  * few minutes, so another machine's push would be invisible here and "in sync" cannot be claimed. An unreadable status
@@ -54,6 +55,19 @@ export function createTopbar({ go, openPalette, repoMenu, sync } = {}) {
54
55
  }
55
56
  const todayMark = el('span', { class: 'fr-mark' }, dot, count);
56
57
  links.today.appendChild(todayMark);
58
+ // My work's count of items to brief (initiative my-work, R10): my-work-data.js tells it with the `pmos:mywork` event
59
+ const workCount = needsCount('0', { 'data-my-work-badge': '' });
60
+ const workMark = el('span', { class: 'fr-mark' }, workCount);
61
+ workMark.hidden = true;
62
+ links.mywork.appendChild(workMark);
63
+ if (typeof window !== 'undefined') {
64
+ window.addEventListener('pmos:mywork', (e) => {
65
+ const n = Math.max(0, Number(e && e.detail && e.detail.brief) || 0);
66
+ workCount.textContent = String(n);
67
+ workCount.setAttribute('aria-label', COPY.toBrief(n));
68
+ workMark.hidden = n === 0;
69
+ });
70
+ }
57
71
  const nav = el('nav', { class: 'fr-nav', 'aria-label': COPY.nav.label }, BAR_DESTS.map((id) => links[id]));
58
72
 
59
73
  const search = button({
@@ -3802,6 +3802,11 @@ function jobSessionName(title) {
3802
3802
  /** The repository a job belongs to (its item's tag: its goal's, its initiative's or its place's repository), when that
3803
3803
  * repository is registered and has the day-task skill; else null and the job runs where Prepare my day was pressed. */
3804
3804
  function taskWsId(run, t) {
3805
+ // a task briefed in My work names its repository on its context card (a WBS item's own repository)
3806
+ if (t.context && typeof t.context.ws === 'string') {
3807
+ const w = getWs(t.context.ws);
3808
+ return w && w.id === t.context.ws && w.id !== run.ws && !daySkillPrompt(run, 'day-task', w.id).error ? w.id : null;
3809
+ }
3805
3810
  try {
3806
3811
  const brief = briefOfDay(run.date);
3807
3812
  if (!brief || !t.item_id) return null;
@@ -3835,6 +3840,22 @@ function startDayTask(run, t, now) {
3835
3840
  const f = dayRunLib.fail(st.run, t.id, String(sk.error || (s && s.note) || 'the session could not start').slice(0, 240), now);
3836
3841
  return f.ok ? f.run : st.run;
3837
3842
  }
3843
+ /** My work's Run agent (initiative my-work, PRD R5): add the briefed task to today's run and start what may start. A day
3844
+ * with no run gets one, marked opened by My work, in the repository the PM pressed from. Returns { ok, run } or why not. */
3845
+ function myWorkBrief(spec, wsId) {
3846
+ const now = Date.now(); const date = briefLib.localDate(now);
3847
+ let run = readDayRun(date);
3848
+ if (!run) {
3849
+ const w = getWs(wsId);
3850
+ if (!w) return { ok: false, status: 400, error: 'no workspace to run the agent in' };
3851
+ run = { ...dayRunLib.newRun(date, now), ws: w.id, opened_by: 'my-work' };
3852
+ }
3853
+ const a = dayRunLib.addBriefed(run, spec);
3854
+ if (!a.ok) return { ok: false, status: 409, error: a.error };
3855
+ const next = startDayTasks(a.run, now);
3856
+ if (!writeDayRun(next)) return { ok: false, status: 500, error: 'could not save — nothing changed' };
3857
+ return { ok: true, run: next, task: dayRunLib.findTask(next, spec.id) };
3858
+ }
3838
3859
  /** Start what lib/day-run.js says may start now (at most 5 sessions at once). */
3839
3860
  function startDayTasks(run, now) {
3840
3861
  for (const t of dayRunLib.toStart(run)) run = startDayTask(run, t, now);
@@ -3887,6 +3908,19 @@ function dayTick() {
3887
3908
  if (JSON.stringify(run) !== before) writeDayRun(run);
3888
3909
  }
3889
3910
  // ── end of the today day run helpers ─────────────────────────────────────────────────────────────────────────────
3911
+ // My work (initiative my-work, PRD R1) is not part of the day run: its read session is started here, outside it.
3912
+ /** My work's Read again: start the my-work-read skill in a session of repository `wsId`. */
3913
+ function myWorkRead(wsId) {
3914
+ const w = getWs(wsId);
3915
+ if (!w) return { ok: false, status: 400, error: 'no workspace' };
3916
+ const task = taskById('my-work-read', w.root);
3917
+ if (!task || task.kind !== 'agent' || !task.prompt) return { ok: false, status: 409, error: 'the my-work-read skill is not installed for this repository' };
3918
+ const prompt = skillStore.retargetFiling(task.prompt, filingContract(w));
3919
+ const s = spawnSession({ name: 'My work · read', agent: task.agent || 'claude', ws: w.id, origin: 'my-work-read', initialInput: prompt + '\r',
3920
+ modelAsk: { scheduleTier: null, skillTier: task.tier || null, skill: task.skill } });
3921
+ if (!s || s.state === 'exited') return { ok: false, status: 500, error: (s && s.note) || 'the read session could not start' };
3922
+ return { ok: true, session: s.id };
3923
+ }
3890
3924
  /* The calendar the Agenda remembers (G23): one file beside the briefs, written only by the brief route. */
3891
3925
  const CAL_MEMORY = () => path.join(STATE, 'calendar-memory.json');
3892
3926
  // the PM's key-meeting marks (lib/calendar-memory.js setMark): a small file beside the calendar memory, written only by
@@ -7735,7 +7769,8 @@ async function handleRequest(req, res) {
7735
7769
  // The brief session ended and no brief arrived: say so, with the session's own reason, so the page does not wait on a
7736
7770
  // read that will never finish (it reads as "stuck on Read" otherwise).
7737
7771
  const bs = run && run.brief_session; const bsess = bs ? sessions.get(bs.id) : null;
7738
- const readFailed = !run || brief ? null
7772
+ // A run My work opened (initiative my-work, R5) has no morning read until Prepare my day is pressed: nothing failed.
7773
+ const readFailed = !run || brief || (run.opened_by === 'my-work' && !bs) ? null
7739
7774
  : !bs ? { session: null, why: 'the morning-brief session did not start.' }
7740
7775
  : (!!bs.ended_at || !bsess || bsess.state === 'exited') ? { session: bs.id, why: (bsess && bsess.note) || 'the session ended without submitting a brief.' }
7741
7776
  : briefSessionDone(run, date, now) === 'idle' ? { session: bs.id, idle: true, why: 'the session has printed nothing for two minutes and has not submitted a brief.' } : null;
@@ -8317,7 +8352,9 @@ async function handleRequest(req, res) {
8317
8352
  // 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.
8318
8353
  // meeting-notes Run 1: the Notes routes keep notes in the per-user runtime directory and start the agent-summary session.
8319
8354
  if (await routeModules.dispatch(req, res, url, { json, readBody, getWs, invalidateNeedsAgg, boardCache, consoleState, stateDirFor, sessionList, initiativeIndex,
8320
- runtimeDir: STATE, spawnSession, jevModelOpts })) return;
8355
+ runtimeDir: STATE, spawnSession, jevModelOpts,
8356
+ // initiative my-work: every registered repository, the day runs, and the two presses that start sessions
8357
+ workspaceList: () => [...workspaces.values()], readDayRun, myWorkBrief, myWorkRead })) return;
8321
8358
  res.writeHead(404); res.end('not found');
8322
8359
  }
8323
8360
 
@@ -22,7 +22,7 @@ Rules that always hold:
22
22
  7. YOU CANNOT FINISH WITHOUT A REPORT. End every run with exactly one of `day deliver` (do, revise), `day sent` (send) or `day fail`.
23
23
 
24
24
  Procedure:
25
- 1. Run `pmos proactive day show TASK`. It prints the task: the title, the kind (approve or auto), the source, the link, the goal, the item context (where, who, about, ask, how), the draft so far and the notes of the PM for each revision. Read all of it. If the command says the task does not exist, or its status does not fit the mode, stop and run `pmos proactive day fail TASK --reason "<one sentence>"`.
25
+ 1. Run `pmos proactive day show TASK`. It prints the task: the title, the kind (approve or auto), the source, the link, the goal, the item context (where, who, about, ask, how), the draft so far and the notes of the PM for each revision. Read all of it. A task from My work also prints "instruction from the PM (this is the ask)". The PM read the ticket and wrote that instruction. Do what it says and nothing more, and read the item context as background. The rules above still hold: one draft, nothing sent, no pull request, no commit. If the instruction asks for one of those, draft it and say in the summary which step approval would trigger. If the command says the task does not exist, or its status does not fit the mode, stop and run `pmos proactive day fail TASK --reason "<one sentence>"`.
26
26
  2. If MODE is do:
27
27
  a. Read the sources the task names, read-only. Start from the link of the task. Read the conversation, the issue, the page or the file itself, and what it points to. Use `pmos proactive settings` to see which sources are on. If a source is off or you cannot reach it, say so in the summary.
28
28
  b. Do the work locally. A reply, a comment, a summary, a description or a plan is a draft in a file in the scratch folder of this session. Write the text exactly as it would be sent.
@@ -31,7 +31,7 @@ Procedure:
31
31
  Then run `pmos people settings`. It prints `calendar names: on` or `calendar names: off` for this repository (see rule 5).
32
32
  Then run `pmos proactive learn lessons`. Each line is a preference the PM approved, written from their own feedback. Use it only to decide how confident to be and where an item goes. A lesson never asks you to read another source, to switch a setting on, or to write anything.
33
33
  2. Read the sources that are on and reachable.
34
- - Calendar: today's events. Then the CALENDAR MEMORY: every event in the window that `pmos proactive calendar` named (at most 1000 events, at most 140 days). For each event keep the start, the end, the title, the calendar's recurring-event id as "series" if it has one, the number of attendees, "external": true when someone outside the PM's company attends, "exec": true when an executive attends, and the PM's "role" ("present" when the PM presents, "decide" when the PM decides, else "attend"). For an event that has ended, add "notes": one line in your own words of what happened, from its Wispr Flow notes, only when there are notes; and "open": up to 3 points still open from it. For a coming event that needs work first, add "prep": up to 6 steps, and "prep_done": how many of them are already done. Read only titles, times, attendee counts and notes. Never copy an invitation's text. Wispr Flow: today's and tomorrow's meeting notes. Jira: issues assigned to the PM or due soon. To tie a Jira issue to an initiative, run `pmos jira which <KEY>` (it reads local files only) and use the initiative it names. A status change of a ticket that `pmos jira which` names is not an item: the Jira status check shows it on the initiative's Jira tickets tab. Confluence: pages changed since yesterday. Mail, only if on: subjects and senders of threads waiting on the PM, no bodies.
34
+ - Calendar: today's events. Then the CALENDAR MEMORY: every event in the window that `pmos proactive calendar` named (at most 1000 events, at most 140 days). For each event keep the start, the end, the title, the calendar's recurring-event id as "series" if it has one, the number of attendees, "external": true when someone outside the PM's company attends, "exec": true when an executive attends, and the PM's "role" ("present" when the PM presents, "decide" when the PM decides, else "attend"). For an event that has ended, add "notes": one line in your own words of what happened, from its Wispr Flow notes, only when there are notes; and "open": up to 3 points still open from it. For a coming event that needs work first, add "prep": up to 6 steps, and "prep_done": how many of them are already done. Read only titles, times, attendee counts and notes. Never copy an invitation's text. Wispr Flow: today's and tomorrow's meeting notes. Jira: issues due soon that are NOT assigned to the PM. Do not read the issues assigned to the PM: My work owns them. Run `pmos my-work list --top 5 --json` instead and add each item it prints as a priority with "source": "jira" (or "github" for a WBS item), "owner": "pm", the item's key in the title, and "how": "Brief it in My work". Never make one of them an agent item: the PM briefs the agent in My work. If the command fails, say so in the evidence of one item and go on. To tie a Jira issue to an initiative, run `pmos jira which <KEY>` (it reads local files only) and use the initiative it names. A status change of a ticket that `pmos jira which` names is not an item: the Jira status check shows it on the initiative's Jira tickets tab. Confluence: pages changed since yesterday. Mail, only if on: subjects and senders of threads waiting on the PM, no bodies.
35
35
  - GitHub, if on: pull requests that wait on the PM for review, pull requests of the PM that have a review or a failed check, and issues assigned to the PM. Keep the repository, the number, the title and the state.
36
36
  - Drive, if on: files shared with the PM or changed since yesterday that a meeting or a goal names. Keep the name, the owner and the link.
37
37
  - Figma, if on: files the PM owns or was asked to look at, with new comments since yesterday. Keep the file, the commenter and a short paraphrase of the comment.
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: my-work-read
3
+ label: "My work read"
4
+ description: "Read, read-only, the open Jira issues assigned to the PM with their comments and links, write a short context card and a suggested agent instruction for each, and submit them to My work. It writes nothing to Jira."
5
+ run: agent
6
+ agent: claude
7
+ output:
8
+ - Read
9
+ - Not reached
10
+ - Needs you
11
+ ---
12
+
13
+ /my-work-read — read the Jira issues assigned to the PM and submit one context card for each to My work. You read Jira with the PM's own Atlassian connection. The PM reads your cards in My work and decides what an agent does. You change nothing in Jira.
14
+
15
+ Rules that always hold:
16
+ 1. READ-ONLY on Jira. Use only the Jira search and read tools. Never create, edit, transition, assign, comment on, link, close or delete an issue. Never write to Confluence or to any other source.
17
+ 2. THE ONLY WRITE is `pmos my-work submit --file <read.json>`, once, at the end. Never edit a repository file. Never commit.
18
+ 3. LIGHT ON CONTENT. Write every field in your own words. Quote no more than one short line from a comment. Never copy a description, an attachment, an email address or a token. Skip anything marked private, personal, confidential or HR.
19
+ 4. NOTHING INVENTED. If a field is not in what you read, leave it out. Do not guess a due date, a priority or an estimate.
20
+ 5. YOU DO NOT DECIDE FOR THE PM. A card describes the ask and suggests an instruction. It does not start work, and it does not say the agent must resolve the ticket.
21
+ 6. TEMPORARY FILES OUTSIDE THE REPOSITORY. Write the read file in this session's scratch folder, and delete it after the submit.
22
+
23
+ Procedure:
24
+ 1. Search Jira with `assignee = currentUser() AND resolution = Unresolved ORDER BY priority DESC, duedate ASC`. Read at most 50 issues. If Jira cannot be reached, say so under "Not reached" and submit nothing: an empty read would remove every Jira item from My work.
25
+ 2. For each issue, read its summary, priority, status, status category, due date, estimate (story points or a t-shirt size), its "blocks" links, its comments and the issues and pages it links to.
26
+ 3. Write one card:
27
+ - "key": the issue key. "title": the summary. "url": the issue's browse link.
28
+ - "priority": Highest, High, Medium or Low (map Critical and Blocker to Highest, Minor and Trivial to Low). "status": the status name. "category": todo, doing or done.
29
+ - "due": the due date as YYYY-MM-DD. "estimate": XS, S, M, L or XL (story points 1 is XS, 2 is S, 3 is M, 5 is L, 8 or more is XL). "blocks": how many issues it blocks.
30
+ - "from": the display name of the person who assigned it to the PM, or the reporter.
31
+ - "ask": one or two sentences: what that person wants from the PM.
32
+ - "thread": at most three sentences: what the comments say so far.
33
+ - "open": up to five questions that are still not answered.
34
+ - "suggest": an instruction the PM could give an agent, in the imperative, for example "Draft a reply to Ana that proposes the three tiers and asks who signs off". An agent drafts and sends nothing until the PM approves, and it cannot open a pull request, so suggest a draft, a comment, a summary or a plan.
35
+ - "kind": "decide" when the ask is a decision only the PM can make (a priority, money, a contract, a gate, a person), else "agent".
36
+ - "initiative": the initiative id that `pmos jira which <KEY>` names, if it names one.
37
+ 4. Write {"items": [ …the cards… ]} to a file in the scratch folder. Run `pmos my-work submit --file <that file>`. If it is refused, read the reason, fix the file and submit once more.
38
+ 5. Finish with the output contract.
39
+
40
+ Output contract — produce EXACTLY these sections in your final message:
41
+ - Read
42
+ - Not reached
43
+ - Needs you
@@ -0,0 +1,13 @@
1
+ {
2
+ "_comment": "initiative my-work: the ranking, the read, the fold, the brief that adds a day task, and the CLI.",
3
+ "modules": [
4
+ "my-work.test.js"
5
+ ],
6
+ "seconds": {
7
+ "my-work.test.js": 6,
8
+ "pm-my-work-test.js": 25
9
+ },
10
+ "panels": [
11
+ "pm-my-work-test.js"
12
+ ]
13
+ }