create-pmos 0.515.0 → 0.517.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 (79) hide show
  1. package/package.json +41 -71
  2. package/payload/KIT-VERSION +2 -2
  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/payload/state/log.md +1 -1
  7. package/workspace/briefing-premium-calendar-test.js +6 -3
  8. package/workspace/briefing-premium-insights-test.js +2 -2
  9. package/workspace/changelog.json +40 -0
  10. package/workspace/ev-everywhere-test.js +3 -3
  11. package/workspace/fixtures/premium-viewer-fixtures.js +4 -2
  12. package/workspace/guide/agent-capabilities.md +73 -0
  13. package/workspace/guide/board.md +7 -63
  14. package/workspace/guide/breakdown.md +8 -108
  15. package/workspace/guide/briefing-premium.md +5 -526
  16. package/workspace/guide/console-calendar.md +7 -206
  17. package/workspace/guide/docs.md +10 -125
  18. package/workspace/guide/home.md +8 -5
  19. package/workspace/guide/index.md +79 -78
  20. package/workspace/guide/initiatives-and-next-steps.md +6 -19
  21. package/workspace/guide/layout.md +23 -230
  22. package/workspace/guide/live-notes.md +5 -7
  23. package/workspace/guide/my-work.md +8 -172
  24. package/workspace/guide/notes.md +14 -21
  25. package/workspace/guide/people.md +6 -39
  26. package/workspace/guide/report-design.md +2 -2
  27. package/workspace/guide/report-structure.md +1 -1
  28. package/workspace/guide/reports-needs-you.md +34 -0
  29. package/workspace/guide/reports-set-up.md +9 -10
  30. package/workspace/guide/reports.md +17 -1
  31. package/workspace/guide/settings.md +16 -69
  32. package/workspace/guide/today.md +12 -188
  33. package/workspace/lib/report-acts.js +189 -0
  34. package/workspace/lib/report-checks.js +3 -0
  35. package/workspace/lib/report-cli.js +112 -3
  36. package/workspace/lib/report-engine.js +779 -0
  37. package/workspace/lib/report-export.js +36 -1
  38. package/workspace/lib/report-pyramid.js +20 -0
  39. package/workspace/lib/routes-insights-premium.js +17 -3
  40. package/workspace/lib/routes-ready-reports.js +11 -2
  41. package/workspace/lib/routes-report-design.js +7 -2
  42. package/workspace/lib/routes-report-setups.js +38 -3
  43. package/workspace/package-lock.json +2 -2
  44. package/workspace/package.json +1 -1
  45. package/workspace/premium-vw-meet-test.js +9 -5
  46. package/workspace/public/pm/cozy-evui.js +1 -0
  47. package/workspace/public/pm/cozy-insights.css +34 -0
  48. package/workspace/public/pm/cozy-nav.js +4 -1
  49. package/workspace/public/pm/home-app.js +3 -1
  50. package/workspace/public/pm/premium-insights.js +112 -14
  51. package/workspace/public/pm/premium-vw-guide.css +36 -0
  52. package/workspace/public/pm/premium-vw-guide.js +137 -0
  53. package/workspace/public/pm/premium-vw-open.js +4 -1
  54. package/workspace/public/pm/premium-vw-page.js +2 -1
  55. package/workspace/public/premium-intelligence.html +1 -1
  56. package/workspace/run-tests.js +6 -0
  57. package/workspace/skills/report-biweekly.skill +7 -0
  58. package/workspace/skills/report-daily.skill +7 -0
  59. package/workspace/skills/report-monthly.skill +7 -0
  60. package/workspace/skills/report-special.skill +2 -0
  61. package/workspace/skills/report-template.skill +8 -1
  62. package/workspace/skills/report-weekly.skill +7 -0
  63. package/workspace/skills/report-write.skill +44 -0
  64. package/workspace/test-lists/report-engine.json +5 -0
  65. package/workspace/test-lists/reports-needs-you.json +5 -0
  66. package/workspace/guide/ask-the-agent.md +0 -46
  67. package/workspace/guide/briefing-cards.md +0 -52
  68. package/workspace/guide/briefing.md +0 -159
  69. package/workspace/guide/calendar-popup.md +0 -46
  70. package/workspace/guide/command-palette.md +0 -77
  71. package/workspace/guide/console3-sessions.md +0 -147
  72. package/workspace/guide/document-sheet.md +0 -89
  73. package/workspace/guide/initiative-boards.md +0 -123
  74. package/workspace/guide/initiatives-screen.md +0 -179
  75. package/workspace/guide/initiatives-timeline.md +0 -55
  76. package/workspace/guide/phone-companion.md +0 -89
  77. package/workspace/guide/reports-dashboards.md +0 -70
  78. package/workspace/guide/reports-page.md +0 -87
  79. package/workspace/guide/timeline.md +0 -70
@@ -37,8 +37,23 @@ const actorLib = require('./actor.js');
37
37
  const RS = require('./report-setups.js');
38
38
  const { parseArgs } = require('./schedule-cli');
39
39
 
40
- const COMMANDS = { report: ['draft', 'issue', 'list', 'propose', 'definitions', 'setups', 'finder'] };
40
+ const COMMANDS = { report: ['make', 'read', 'find', 'write', 'check', 'rule', 'draft', 'issue', 'list', 'propose', 'definitions', 'setups', 'finder'] };
41
41
  const USAGE = [
42
+ 'usage: pmos report make|read|find|write|check|rule — the report engine: brief, read, find, answer, render (any report, any shape)',
43
+ ' pmos report make <id> [--ask "<the question>"] [--readers "<who>"] [--source <kind:ref>,…] [--slot <date>]',
44
+ ' Steps 1 to 3: derive the brief (readers, question, window, sources; no section list), read every source PMOS reaches,',
45
+ ' and find what changed. An ad hoc report needs --ask. Sources: pmos · pack:<state file of readings> · connector:<name> · document:<path>.',
46
+ ' pmos report read <id> [--slot <date>] --from <file|->',
47
+ ' File the readings you read through a connector or a document: {"readings":[{id,value,unit,at,source,how,label,n,of,target}],',
48
+ ' "gaps":[{source,reason}]}. Every reading has a source of the brief, a date and how it was read.',
49
+ ' pmos report find <id> [--slot <date>] --from <file|->',
50
+ ' File the findings that answer the question: {"findings":[{text,readings:[ids],kind,question}]}. Each cites readings.',
51
+ ' pmos report write <id> [--slot <date>] --from <file|->',
52
+ ' Step 4 to 6: check the report.json you wrote (the outline is yours), render the document and the deck, write the checks.',
53
+ ' Refused when there is no answer with a reading, or when a figure is not a reading {{r:<id>}}.',
54
+ ' pmos report check <id> [--slot <date>] the checks of the last write: substance first, then form',
55
+ ' pmos report rule <id> list | add <voice|wording|off|keep> "<text or part>" | remove <n>',
56
+ ' What the readers taught this report: a voice or wording rule, or a part beyond the ask turned off or kept.',
42
57
  'usage: pmos report draft|issue|list — cadence reports (for example the biweekly)',
43
58
  ' pmos report draft <cadence> [<slot>] [--now <time>] [--redraft]',
44
59
  ' Write the draft for a slot (default: today) with every number. Refuses a slot that has a draft;',
@@ -59,8 +74,9 @@ const USAGE = [
59
74
  ' every command: [--json] [--root <dir>]. The cadence is the report skill id without "report-", for example biweekly.',
60
75
  ];
61
76
  const BOOL = new Set(['json', 'redraft', 'help']);
62
- const VALUE = new Set(['now', 'root']);
63
- const ALLOWED = { draft: ['json', 'redraft', 'now', 'root'], issue: ['root'], list: ['json', 'root'], propose: ['json', 'root'], definitions: ['json', 'root'], setups: ['json', 'root'], finder: ['json', 'root'] };
77
+ const VALUE = new Set(['now', 'root', 'ask', 'readers', 'source', 'slot', 'from']);
78
+ const ALLOWED = { make: ['json', 'now', 'root', 'ask', 'readers', 'source', 'slot'], read: ['json', 'now', 'root', 'slot', 'from', 'source'], find: ['json', 'now', 'root', 'slot', 'from'],
79
+ write: ['json', 'now', 'root', 'slot', 'from'], check: ['json', 'root', 'slot'], rule: ['json', 'root'], draft: ['json', 'redraft', 'now', 'root'], issue: ['root'], list: ['json', 'root'], propose: ['json', 'root'], definitions: ['json', 'root'], setups: ['json', 'root'], finder: ['json', 'root'] };
64
80
  const CADENCE_RE = /^[a-z][a-z0-9-]{0,39}$/;
65
81
  const DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
66
82
 
@@ -129,6 +145,7 @@ async function run(argv, { say = (s) => console.log(s), cwd = process.cwd(), isT
129
145
  return 0;
130
146
  }
131
147
 
148
+ if (['make', 'read', 'find', 'write', 'check', 'rule'].includes(verb)) return engineVerb(verb, { pos, flags, root, json, say, fail, isTTY, env, stdin, now });
132
149
  if (verb === 'definitions' || verb === 'setups' || verb === 'propose' || verb === 'finder') return reportWorkspace(verb, { pos, flags, root, json, say, fail, cwd, isTTY, env, stdin, now });
133
150
 
134
151
  const [cadence, slot] = pos;
@@ -170,6 +187,98 @@ async function run(argv, { say = (s) => console.log(s), cwd = process.cwd(), isT
170
187
  return 0;
171
188
  }
172
189
 
190
+ /** The report engine's verbs (lib/report-engine.js). An agent session and the PM may run them; issuing stays the PM's (`pmos report issue`). */
191
+ function engineVerb(verb, { pos, flags, root, json, say, fail, isTTY, env, stdin, now }) {
192
+ const RE = require('./report-engine.js');
193
+ const id = pos[0];
194
+ if (!id || !RE.ID_RE.test(id)) { say(`usage: pmos report ${verb} <id> … (the id is lower case letters, digits and dashes, for example scarlet-assessment)`); return 2; }
195
+ let clock = now == null ? Date.now() : now;
196
+ if (flags.now !== undefined) { clock = Date.parse(flags.now); if (!Number.isFinite(clock)) return fail('--now must be a time, for example 2026-10-16T09:00:00Z', 2); }
197
+ const slot = flags.slot !== undefined ? flags.slot : undefined;
198
+ if (slot !== undefined && !isDate(slot)) return fail('--slot must be a date, YYYY-MM-DD', 2);
199
+ const day = slot || new Date(clock).toISOString().slice(0, 10);
200
+ const who = actorLib.fromCli({ ...(isTTY === undefined ? {} : { isTTY }), ...(env === undefined ? {} : { env }) });
201
+ const readFrom = () => {
202
+ const src = flags.from;
203
+ if (!src) return { error: `--from <file|-> is required: the JSON to file` };
204
+ let text;
205
+ try { text = src === '-' ? (typeof stdin === 'string' ? stdin : fs.readFileSync(0, 'utf8')) : fs.readFileSync(path.resolve(src), 'utf8'); } catch { return { error: `could not read ${src === '-' ? 'standard input' : src}` }; }
206
+ try { const o = JSON.parse(text); return o && typeof o === 'object' ? { body: o } : { error: 'the JSON is an object' }; } catch { return { error: 'that is not JSON' }; }
207
+ };
208
+ const sources = flags.source ? String(flags.source).split(',').map((x) => x.trim()).filter(Boolean) : [];
209
+ const bad = sources.find((x) => !RE.parseSource(x));
210
+ if (bad) return fail(`--source ${bad}: write pmos, pack:<file>, connector:<name> or document:<path>`, 2);
211
+ const summary = (m) => {
212
+ const f = m.findings; const g = m.readings.gaps;
213
+ if (json) { say(JSON.stringify({ ok: true, brief: m.brief, readings: m.readings.readings.length, gaps: g, findings: f.findings, none: f.none, paths: m.paths })); return 0; }
214
+ say(`✓ Brief ${m.paths.brief}: for ${m.brief.readers}. Question: ${m.brief.question}`);
215
+ say(` ${m.readings.readings.length} reading(s); ${g.length ? `${g.length} gap(s): ${g.map((x) => `${x.source} (${x.reason})`).join('; ')}` : 'no gap'}.`);
216
+ say(f.none ? ' No finding, so no draft: nothing to report yet. Read the sources the gaps name and file the readings: pmos report read ' + id + ' --from <file>'
217
+ : ` ${f.findings.length} finding(s): ${f.findings.slice(0, 3).map((x) => x.text).join(' · ')}`);
218
+ if (!f.none) say(` Next: write ${m.paths.report} (the outline is yours) and run: pmos report write ${id}${slot ? ' --slot ' + slot : ''} --from <file>`);
219
+ return 0;
220
+ };
221
+ if (verb === 'make') {
222
+ const m = RE.make(root, id, { slot: day, ask: flags.ask, readers: flags.readers, sources, now: clock });
223
+ if (!m.ok) return fail(m.error);
224
+ return summary(m);
225
+ }
226
+ if (verb === 'read' || verb === 'find') {
227
+ const r = readFrom(); if (r.error) return fail(r.error, 2);
228
+ const add = verb === 'read' ? { add: r.body.readings || [], gaps: r.body.gaps || [] } : { addFindings: r.body.findings || [] };
229
+ const m = RE.make(root, id, { slot: day, sources, ...add, now: clock });
230
+ if (!m.ok) return fail(m.error);
231
+ return summary(m);
232
+ }
233
+ if (verb === 'write') {
234
+ const r = readFrom(); if (r.error) return fail(r.error, 2);
235
+ const w = RE.write(root, id, day, r.body, { actor: who, now: clock });
236
+ if (!w.ok) {
237
+ if (json) { say(JSON.stringify({ ok: false, error: w.error, checks: w.checks || null, none: !!w.none })); return 1; }
238
+ say(`✗ ${w.error}`);
239
+ return 1;
240
+ }
241
+ if (json) { say(JSON.stringify({ ok: true, path: w.path, report: w.report, checks: w.checks })); return 0; }
242
+ say(`✓ Wrote ${w.path} from ${w.report}. The deck is drawn from the same model.`);
243
+ for (const c of w.checks) say(` ${c.pass ? '✓' : '✗'} ${c.id}: ${c.reason}`);
244
+ return 0;
245
+ }
246
+ if (verb === 'check') {
247
+ let P; try { P = RE.paths(root, id, day); } catch (e) { return fail(e.message, 2); }
248
+ let c; try { c = JSON.parse(fs.readFileSync(P.checks.abs, 'utf8')); } catch { return fail(`${id} ${day} has no checks yet: pmos report write ${id} --from <file>`); }
249
+ if (json) { say(JSON.stringify({ ok: true, ...c })); return 0; }
250
+ for (const x of c.checks) say(`${x.pass ? '✓' : '✗'} ${x.id}: ${x.reason}`);
251
+ return 0;
252
+ }
253
+ // rule
254
+ const act = pos[1] || 'list';
255
+ if (act === 'list') {
256
+ const rules = RE.rulesOf(root, id);
257
+ if (json) { say(JSON.stringify({ ok: true, rules })); return 0; }
258
+ if (!rules.length) say(`${id} has no rule yet; the default voice applies.`);
259
+ for (const x of rules) say(`${x.n} ${x.kind} ${x.text || x.part}${x.from ? ` (from ${x.from})` : ''}`);
260
+ return 0;
261
+ }
262
+ if (!actorLib.isPm(who) && !actorLib.isAgent(who)) return fail('only the PM or an agent session can change a report\'s rules');
263
+ if (act === 'add') {
264
+ const kind = pos[2]; const text = pos.slice(3).join(' ');
265
+ const r = RE.addRule(root, id, { kind, text: kind === 'off' || kind === 'keep' ? null : text, part: kind === 'off' || kind === 'keep' ? text : null, from: actorLib.isPm(who) ? 'the PM' : 'the writer', by: who.by, now: clock });
266
+ if (!r.ok) return fail(r.error);
267
+ if (json) { say(JSON.stringify({ ok: true, rule: r.rule })); return 0; }
268
+ say(`✓ Rule ${r.rule.n} kept for ${id}: ${r.rule.text || `${r.rule.kind} ${r.rule.part}`}`);
269
+ return 0;
270
+ }
271
+ if (act === 'remove') {
272
+ const r = RE.removeRule(root, id, Number(pos[2]), { by: who.by, now: clock });
273
+ if (!r.ok) return fail(r.error);
274
+ if (json) { say(JSON.stringify({ ok: true })); return 0; }
275
+ say(`✓ Rule ${pos[2]} removed.`);
276
+ return 0;
277
+ }
278
+ say('usage: pmos report rule <id> list | add <kind> "<text>" | remove <n>');
279
+ return 2;
280
+ }
281
+
173
282
  /** The report workspace's verbs. `propose` is the one an agent run may call; `finder` is the PM's. */
174
283
  function reportWorkspace(verb, { pos, flags, root, json, say, fail, isTTY, env, stdin, now }) {
175
284
  const E = env === undefined ? process.env : env;