create-pmos 0.123.0 → 0.125.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 +2 -2
- package/payload/planning/evals/eval-calibration.md +1 -1
- package/payload/planning/okrs/health-budgets.md +1 -1
- package/payload/scripts/nine-stages.js +81 -0
- package/payload/scripts/workflow-state.js +2 -0
- package/payload/state/discoveries.md +1 -1
- package/payload/state/log.md +1 -1
- package/workspace/c3-one-home-test.js +131 -0
- package/workspace/fixtures/initiatives-api/list.json +171 -3
- package/workspace/fixtures/initiatives-api/roadmap.json +228 -4
- package/workspace/fixtures/initiatives-api/sheet.json +57 -1
- package/workspace/fixtures/one-home-baseline.json +83 -0
- package/workspace/guide/layout.md +2 -0
- package/workspace/guide/notes.md +1 -0
- package/workspace/lib/engine/nine-stages.js +81 -0
- package/workspace/lib/engine/workflow-state.js +2 -0
- package/workspace/lib/facts-async.js +51 -0
- package/workspace/lib/item-steps.js +52 -0
- package/workspace/lib/jira-status.js +8 -3
- package/workspace/lib/jobs-to-be-done.js +52 -0
- package/workspace/lib/outbox-store.js +87 -0
- package/workspace/lib/pm-items.js +115 -0
- package/workspace/lib/route-modules.js +21 -0
- package/workspace/lib/routes-briefing.js +100 -0
- package/workspace/lib/routes-c3-init.js +53 -0
- package/workspace/lib/routes-c3-life.js +119 -0
- package/workspace/lib/routes-c3-strategy.js +169 -0
- package/workspace/lib/routes-c3-timeline.js +191 -0
- package/workspace/lib/routes-calendar-import.js +60 -0
- package/workspace/lib/routes-calendar-views.js +61 -0
- package/workspace/lib/routes-doc-health.js +79 -0
- package/workspace/lib/routes-doc-sheet.js +169 -0
- package/workspace/lib/routes-forecast.js +85 -0
- package/workspace/lib/routes-hooks.js +121 -0
- package/workspace/lib/routes-initiatives.js +3 -0
- package/workspace/lib/routes-intake.js +24 -0
- package/workspace/lib/routes-outbox.js +97 -0
- package/workspace/lib/routes-pm-items.js +216 -0
- package/workspace/lib/routes-records.js +61 -0
- package/workspace/lib/routes-releases.js +129 -0
- package/workspace/lib/routes-report-facts.js +84 -0
- package/workspace/lib/routes-report-families.js +32 -0
- package/workspace/lib/routes-roadmap-ops.js +141 -0
- package/workspace/lib/routes-runs.js +119 -0
- package/workspace/lib/routes-signals.js +50 -0
- package/workspace/lib/run-answers.js +69 -0
- package/workspace/package-lock.json +2 -2
- package/workspace/package.json +1 -1
- package/workspace/public/c3.html +26 -0
- package/workspace/public/pm/briefing-deck.js +415 -0
- package/workspace/public/pm/briefing-model.js +176 -0
- package/workspace/public/pm/c3-breakdown.js +240 -0
- package/workspace/public/pm/c3-brief.js +278 -0
- package/workspace/public/pm/c3-cal-strategy.js +528 -0
- package/workspace/public/pm/c3-case.js +173 -0
- package/workspace/public/pm/c3-demo-brief-ix.js +350 -0
- package/workspace/public/pm/c3-demo-cal-ix.js +74 -0
- package/workspace/public/pm/c3-demo-cal2.js +66 -0
- package/workspace/public/pm/c3-demo-cal3.js +173 -0
- package/workspace/public/pm/c3-demo-data.js +560 -0
- package/workspace/public/pm/c3-demo-init.js +373 -0
- package/workspace/public/pm/c3-demo-life.js +77 -0
- package/workspace/public/pm/c3-demo-misc2.js +46 -0
- package/workspace/public/pm/c3-demo-plan2.js +30 -0
- package/workspace/public/pm/c3-demo-rep-ix.js +126 -0
- package/workspace/public/pm/c3-demo-rep2.js +92 -0
- package/workspace/public/pm/c3-demo-term.js +153 -0
- package/workspace/public/pm/c3-demo-time.js +49 -0
- package/workspace/public/pm/c3-demo-work-ix.js +80 -0
- package/workspace/public/pm/c3-demo-work2.js +13 -0
- package/workspace/public/pm/c3-demo.js +113 -0
- package/workspace/public/pm/c3-doc-sheet.js +314 -0
- package/workspace/public/pm/c3-dock.js +180 -0
- package/workspace/public/pm/c3-docs.js +290 -0
- package/workspace/public/pm/c3-expand.js +96 -0
- package/workspace/public/pm/c3-init-extras.js +170 -0
- package/workspace/public/pm/c3-lifecycle-panels.js +476 -0
- package/workspace/public/pm/c3-misc-panels.js +89 -0
- package/workspace/public/pm/c3-plan-panels.js +163 -0
- package/workspace/public/pm/c3-plan.js +192 -0
- package/workspace/public/pm/c3-roadmap.js +249 -0
- package/workspace/public/pm/c3-sheet.js +107 -0
- package/workspace/public/pm/c3-shell.js +637 -0
- package/workspace/public/pm/c3-signals.js +196 -0
- package/workspace/public/pm/c3-strategy-panels.js +45 -0
- package/workspace/public/pm/c3-swipe.js +138 -0
- package/workspace/public/pm/c3-terminal-data.js +26 -0
- package/workspace/public/pm/c3-terminal-edge.js +91 -0
- package/workspace/public/pm/c3-terminal-icons.js +41 -0
- package/workspace/public/pm/c3-terminal-results.js +141 -0
- package/workspace/public/pm/c3-terminal.js +52 -0
- package/workspace/public/pm/c3-tickets.js +163 -0
- package/workspace/public/pm/c3-timeline.js +201 -0
- package/workspace/public/pm/c3-toast.js +16 -0
- package/workspace/public/pm/calendar-views.js +1015 -0
- package/workspace/public/pm/console3-lift.md +220 -0
- package/workspace/public/pm/console3.css +1480 -0
- package/workspace/public/pm/dest-initiatives.js +16 -3
- package/workspace/public/pm/dest-mywork.js +8 -1
- package/workspace/public/pm/dest-notes.js +25 -3
- package/workspace/public/pm/dest-reports.js +47 -1
- package/workspace/public/pm/dest-today.js +55 -1
- package/workspace/public/pm/doc-health-panel.js +110 -0
- package/workspace/public/pm/doc-rail.js +9 -3
- package/workspace/public/pm/lifecycle-lens-model.js +228 -0
- package/workspace/public/pm/lifecycle-lens.js +261 -0
- package/workspace/public/pm/new-initiative-sheet.js +116 -21
- package/workspace/public/pm/outbox-panel.js +125 -0
- package/workspace/public/pm/pm-work-view.js +919 -0
- package/workspace/public/pm/releases-view.js +248 -0
- package/workspace/public/pm/report-families-view.js +503 -0
- package/workspace/public/pm/run-card.js +244 -0
- package/workspace/public/pm/sessions-panel.js +149 -0
- package/workspace/public/pm/shell-bell.js +162 -0
- package/workspace/public/pm/shell-model.js +83 -0
- package/workspace/public/pm/shell-phone.js +124 -0
- package/workspace/public/pm/shell-readaloud.js +53 -0
- package/workspace/public/pm/shell-recording.js +110 -0
- package/workspace/public/pm/shell-ticker.js +90 -0
- package/workspace/public/pm/slide-confirm.js +163 -0
- package/workspace/public/pm/timeline-forecast-view.js +164 -0
- package/workspace/public/pm/today-day.js +8 -2
- package/workspace/public/pm/tokens.css +1 -0
- package/workspace/server.js +5 -2
- package/workspace/test-files.json +8 -0
- package/workspace/test-lists/browser-suites-green.json +5 -0
|
@@ -66,7 +66,63 @@
|
|
|
66
66
|
"label": "7 of 12"
|
|
67
67
|
},
|
|
68
68
|
"next_due": "2026-11-14",
|
|
69
|
-
"last_activity": "2026-10-04T09:00:00Z"
|
|
69
|
+
"last_activity": "2026-10-04T09:00:00Z",
|
|
70
|
+
"nine_stages": [
|
|
71
|
+
{
|
|
72
|
+
"key": "discover",
|
|
73
|
+
"label": "Discover",
|
|
74
|
+
"status": "pending",
|
|
75
|
+
"accepted": false
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"key": "ideate",
|
|
79
|
+
"label": "Ideate",
|
|
80
|
+
"status": "pending",
|
|
81
|
+
"accepted": false
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"key": "strategize",
|
|
85
|
+
"label": "Strategize",
|
|
86
|
+
"status": "pending",
|
|
87
|
+
"accepted": false
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"key": "prioritize",
|
|
91
|
+
"label": "Prioritize",
|
|
92
|
+
"status": "pending",
|
|
93
|
+
"accepted": false
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"key": "plan",
|
|
97
|
+
"label": "Plan",
|
|
98
|
+
"status": "pending",
|
|
99
|
+
"accepted": false
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"key": "build",
|
|
103
|
+
"label": "Build",
|
|
104
|
+
"status": "pending",
|
|
105
|
+
"accepted": false
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"key": "deliver",
|
|
109
|
+
"label": "Deliver",
|
|
110
|
+
"status": "pending",
|
|
111
|
+
"accepted": false
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"key": "monitor",
|
|
115
|
+
"label": "Monitor",
|
|
116
|
+
"status": "pending",
|
|
117
|
+
"accepted": false
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"key": "evaluate",
|
|
121
|
+
"label": "Evaluate",
|
|
122
|
+
"status": "pending",
|
|
123
|
+
"accepted": false
|
|
124
|
+
}
|
|
125
|
+
]
|
|
70
126
|
},
|
|
71
127
|
{
|
|
72
128
|
"id": "audit-log",
|
|
@@ -108,7 +164,63 @@
|
|
|
108
164
|
"label": "3 of 5"
|
|
109
165
|
},
|
|
110
166
|
"next_due": "2026-10-20",
|
|
111
|
-
"last_activity": "2026-09-29T15:00:00Z"
|
|
167
|
+
"last_activity": "2026-09-29T15:00:00Z",
|
|
168
|
+
"nine_stages": [
|
|
169
|
+
{
|
|
170
|
+
"key": "discover",
|
|
171
|
+
"label": "Discover",
|
|
172
|
+
"status": "pending",
|
|
173
|
+
"accepted": false
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"key": "ideate",
|
|
177
|
+
"label": "Ideate",
|
|
178
|
+
"status": "pending",
|
|
179
|
+
"accepted": false
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"key": "strategize",
|
|
183
|
+
"label": "Strategize",
|
|
184
|
+
"status": "pending",
|
|
185
|
+
"accepted": false
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"key": "prioritize",
|
|
189
|
+
"label": "Prioritize",
|
|
190
|
+
"status": "pending",
|
|
191
|
+
"accepted": false
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"key": "plan",
|
|
195
|
+
"label": "Plan",
|
|
196
|
+
"status": "pending",
|
|
197
|
+
"accepted": false
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
"key": "build",
|
|
201
|
+
"label": "Build",
|
|
202
|
+
"status": "pending",
|
|
203
|
+
"accepted": false
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"key": "deliver",
|
|
207
|
+
"label": "Deliver",
|
|
208
|
+
"status": "pending",
|
|
209
|
+
"accepted": false
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"key": "monitor",
|
|
213
|
+
"label": "Monitor",
|
|
214
|
+
"status": "pending",
|
|
215
|
+
"accepted": false
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
"key": "evaluate",
|
|
219
|
+
"label": "Evaluate",
|
|
220
|
+
"status": "pending",
|
|
221
|
+
"accepted": false
|
|
222
|
+
}
|
|
223
|
+
]
|
|
112
224
|
}
|
|
113
225
|
],
|
|
114
226
|
"next": [
|
|
@@ -145,7 +257,63 @@
|
|
|
145
257
|
"label": "no breakdown"
|
|
146
258
|
},
|
|
147
259
|
"next_due": null,
|
|
148
|
-
"last_activity": "2026-09-20T10:00:00Z"
|
|
260
|
+
"last_activity": "2026-09-20T10:00:00Z",
|
|
261
|
+
"nine_stages": [
|
|
262
|
+
{
|
|
263
|
+
"key": "discover",
|
|
264
|
+
"label": "Discover",
|
|
265
|
+
"status": "pending",
|
|
266
|
+
"accepted": false
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
"key": "ideate",
|
|
270
|
+
"label": "Ideate",
|
|
271
|
+
"status": "pending",
|
|
272
|
+
"accepted": false
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
"key": "strategize",
|
|
276
|
+
"label": "Strategize",
|
|
277
|
+
"status": "pending",
|
|
278
|
+
"accepted": false
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
"key": "prioritize",
|
|
282
|
+
"label": "Prioritize",
|
|
283
|
+
"status": "pending",
|
|
284
|
+
"accepted": false
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
"key": "plan",
|
|
288
|
+
"label": "Plan",
|
|
289
|
+
"status": "pending",
|
|
290
|
+
"accepted": false
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
"key": "build",
|
|
294
|
+
"label": "Build",
|
|
295
|
+
"status": "pending",
|
|
296
|
+
"accepted": false
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
"key": "deliver",
|
|
300
|
+
"label": "Deliver",
|
|
301
|
+
"status": "pending",
|
|
302
|
+
"accepted": false
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
"key": "monitor",
|
|
306
|
+
"label": "Monitor",
|
|
307
|
+
"status": "pending",
|
|
308
|
+
"accepted": false
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
"key": "evaluate",
|
|
312
|
+
"label": "Evaluate",
|
|
313
|
+
"status": "pending",
|
|
314
|
+
"accepted": false
|
|
315
|
+
}
|
|
316
|
+
]
|
|
149
317
|
}
|
|
150
318
|
],
|
|
151
319
|
"later": []
|
|
@@ -191,7 +359,63 @@
|
|
|
191
359
|
"label": "no breakdown"
|
|
192
360
|
},
|
|
193
361
|
"next_due": null,
|
|
194
|
-
"last_activity": "2026-07-01T10:00:00Z"
|
|
362
|
+
"last_activity": "2026-07-01T10:00:00Z",
|
|
363
|
+
"nine_stages": [
|
|
364
|
+
{
|
|
365
|
+
"key": "discover",
|
|
366
|
+
"label": "Discover",
|
|
367
|
+
"status": "pending",
|
|
368
|
+
"accepted": false
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
"key": "ideate",
|
|
372
|
+
"label": "Ideate",
|
|
373
|
+
"status": "pending",
|
|
374
|
+
"accepted": false
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
"key": "strategize",
|
|
378
|
+
"label": "Strategize",
|
|
379
|
+
"status": "pending",
|
|
380
|
+
"accepted": false
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
"key": "prioritize",
|
|
384
|
+
"label": "Prioritize",
|
|
385
|
+
"status": "pending",
|
|
386
|
+
"accepted": false
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
"key": "plan",
|
|
390
|
+
"label": "Plan",
|
|
391
|
+
"status": "pending",
|
|
392
|
+
"accepted": false
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
"key": "build",
|
|
396
|
+
"label": "Build",
|
|
397
|
+
"status": "pending",
|
|
398
|
+
"accepted": false
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
"key": "deliver",
|
|
402
|
+
"label": "Deliver",
|
|
403
|
+
"status": "pending",
|
|
404
|
+
"accepted": false
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
"key": "monitor",
|
|
408
|
+
"label": "Monitor",
|
|
409
|
+
"status": "pending",
|
|
410
|
+
"accepted": false
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
"key": "evaluate",
|
|
414
|
+
"label": "Evaluate",
|
|
415
|
+
"status": "pending",
|
|
416
|
+
"accepted": false
|
|
417
|
+
}
|
|
418
|
+
]
|
|
195
419
|
}
|
|
196
420
|
],
|
|
197
421
|
"proposals": [
|
|
@@ -48,7 +48,63 @@
|
|
|
48
48
|
"label": "7 of 12"
|
|
49
49
|
},
|
|
50
50
|
"next_due": "2026-11-14",
|
|
51
|
-
"last_activity": "2026-10-04T09:00:00Z"
|
|
51
|
+
"last_activity": "2026-10-04T09:00:00Z",
|
|
52
|
+
"nine_stages": [
|
|
53
|
+
{
|
|
54
|
+
"key": "discover",
|
|
55
|
+
"label": "Discover",
|
|
56
|
+
"status": "pending",
|
|
57
|
+
"accepted": false
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"key": "ideate",
|
|
61
|
+
"label": "Ideate",
|
|
62
|
+
"status": "pending",
|
|
63
|
+
"accepted": false
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"key": "strategize",
|
|
67
|
+
"label": "Strategize",
|
|
68
|
+
"status": "pending",
|
|
69
|
+
"accepted": false
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"key": "prioritize",
|
|
73
|
+
"label": "Prioritize",
|
|
74
|
+
"status": "pending",
|
|
75
|
+
"accepted": false
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"key": "plan",
|
|
79
|
+
"label": "Plan",
|
|
80
|
+
"status": "pending",
|
|
81
|
+
"accepted": false
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"key": "build",
|
|
85
|
+
"label": "Build",
|
|
86
|
+
"status": "pending",
|
|
87
|
+
"accepted": false
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"key": "deliver",
|
|
91
|
+
"label": "Deliver",
|
|
92
|
+
"status": "pending",
|
|
93
|
+
"accepted": false
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"key": "monitor",
|
|
97
|
+
"label": "Monitor",
|
|
98
|
+
"status": "pending",
|
|
99
|
+
"accepted": false
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"key": "evaluate",
|
|
103
|
+
"label": "Evaluate",
|
|
104
|
+
"status": "pending",
|
|
105
|
+
"accepted": false
|
|
106
|
+
}
|
|
107
|
+
]
|
|
52
108
|
},
|
|
53
109
|
"stepper": [
|
|
54
110
|
{
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "Items the console3 page makes actionable on more than one tab today (c3-one-home-test.js). Known-failing until the Phase 2 restructure of the console3 feedback plan; the suite fails only on a duplicate that is not listed here. Remove an entry when its duplicate is gone.",
|
|
3
|
+
"duplicates": [
|
|
4
|
+
{
|
|
5
|
+
"title": "accept the 15 oct interview invite",
|
|
6
|
+
"tabs": [
|
|
7
|
+
"brief",
|
|
8
|
+
"work"
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"title": "approve pricing-page copy before handoff",
|
|
13
|
+
"tabs": [
|
|
14
|
+
"brief",
|
|
15
|
+
"work"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"title": "assign owners to 2 unowned workshop actions",
|
|
20
|
+
"tabs": [
|
|
21
|
+
"brief",
|
|
22
|
+
"work"
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"title": "confirm the 1 oct numbers before the 10:30 update",
|
|
27
|
+
"tabs": [
|
|
28
|
+
"brief",
|
|
29
|
+
"work"
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"title": "confirm the growth assumption in the q4 forecast",
|
|
34
|
+
"tabs": [
|
|
35
|
+
"brief",
|
|
36
|
+
"work"
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"title": "pick interview slots with 3 customers",
|
|
41
|
+
"tabs": [
|
|
42
|
+
"brief",
|
|
43
|
+
"work"
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"title": "review the 13:00 interview guide",
|
|
48
|
+
"tabs": [
|
|
49
|
+
"brief",
|
|
50
|
+
"work"
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"title": "say yes to sam: ship the logging change",
|
|
55
|
+
"tabs": [
|
|
56
|
+
"brief",
|
|
57
|
+
"work"
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"title": "self-serve onboarding: continue or park?",
|
|
62
|
+
"tabs": [
|
|
63
|
+
"brief",
|
|
64
|
+
"work"
|
|
65
|
+
]
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"title": "sso is live with 3 customers",
|
|
69
|
+
"tabs": [
|
|
70
|
+
"brief",
|
|
71
|
+
"init",
|
|
72
|
+
"rep"
|
|
73
|
+
]
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"title": "the board update is 70% ready",
|
|
77
|
+
"tabs": [
|
|
78
|
+
"init",
|
|
79
|
+
"rep"
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
}
|
|
@@ -102,6 +102,8 @@ When the workspace needs an answer from you, for example the name for a rename o
|
|
|
102
102
|
|
|
103
103
|
The workspace is neutral. A primary button is the text colour on the page colour, in both themes. The one brand colour marks the Agenda dot and the Agenda count, and nothing else. The bar, the dock and the bottom bar follow the theme; only a terminal stays dark. Corners are square. Controls are icons from one set, not text symbols. On a touch screen every field is 16 pixels, so the phone does not zoom when you tap it, and every control is at least 44 pixels high.
|
|
104
104
|
|
|
105
|
+
On the console page (`/c3.html`), text on the blue accent and on a red badge is white in both themes. The page takes this colour from one token, so the colours stay the same when the theme changes.
|
|
106
|
+
|
|
105
107
|
## Keys
|
|
106
108
|
|
|
107
109
|
| Key | What it does |
|
package/workspace/guide/notes.md
CHANGED
|
@@ -63,6 +63,7 @@ The Notes view shows one meeting, top to bottom. A bar at the top shows whether
|
|
|
63
63
|
1. Press **Listen**. Select what to listen to:
|
|
64
64
|
- **My microphone**: what you say.
|
|
65
65
|
- **The meeting**: the other people in an online meeting. The meeting can be in any app, such as Zoom, or in any browser tab. In the sharing window, choose **Entire screen** and tick **Also share system audio**, so that the sound of every app is recorded. To record one browser tab, choose that tab and tick **Share tab audio**. Chrome offers system audio on Windows and ChromeOS; on macOS use a tab.
|
|
66
|
+
- **Skipping the sharing window.** A browser always asks before a page records the screen, and a page cannot turn that off. To pick **Entire screen** without being asked, start Chrome with the switch `--auto-select-desktop-capture-source="Entire screen"` (a Chrome on your own machine, for example from a shortcut). System audio is then shared when the browser and the system offer it (see above). This is a Chrome setting on your machine, not a PMOS setting.
|
|
66
67
|
2. Press **Start**. The header shows a red dot, the time, and the sources. Tell people that you are taking notes. If the meeting stays completely silent for 20 seconds while your microphone works, a red message says that the other people are not being recorded. Most often the sharing window had the wrong source. Press **Stop**, press **Listen** again, choose **Entire screen** (or the meeting's tab), and tick **Also share system audio** (or **Share tab audio**). The message goes away when sound arrives or when you press **Stop**.
|
|
67
68
|
3. Each line shows in the transcript a few seconds after it is said, with who said it, the time and its label. Your lines are **You**. The meeting's lines are **Meeting**: click the name to change it. The transcript cannot tell the people in the meeting apart.
|
|
68
69
|
4. Press **Stop** to end. The summary shows at the top of your notes. To carry on, press **Listen again**: the clock carries on from where it stopped, and the time between does not count. Line times and the kept audio use the same clock.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/*
|
|
3
|
+
* The nine stage names as a label layer over the workflow engine's derived stage (run 3).
|
|
4
|
+
*
|
|
5
|
+
* The engine derives one of six rungs (intake, spec, contract, build, eval, accepted) from the steps
|
|
6
|
+
* it found. This file names the nine stages the PM sees and says which of them each lane uses. It
|
|
7
|
+
* never decides a stage itself: a stage is `done` only when a derived signal shows it, and a stage
|
|
8
|
+
* no record can yet show is `no-signal`, not guessed.
|
|
9
|
+
*
|
|
10
|
+
* The lane sets below are a proposal for the PM to correct (see the run 3 contract in the PRD).
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const STAGES = ['discover', 'ideate', 'strategize', 'prioritize', 'plan', 'build', 'deliver', 'monitor', 'evaluate'];
|
|
14
|
+
|
|
15
|
+
const LABELS = {
|
|
16
|
+
discover: 'Discover', ideate: 'Ideate', strategize: 'Strategize', prioritize: 'Prioritize', plan: 'Plan',
|
|
17
|
+
build: 'Build', deliver: 'Deliver', monitor: 'Monitor', evaluate: 'Evaluate',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// Which stages each product-code lane uses. Stages not listed read `skipped`.
|
|
21
|
+
const LANE_STAGES = {
|
|
22
|
+
feature: STAGES,
|
|
23
|
+
discovery: ['discover', 'ideate', 'strategize', 'prioritize', 'evaluate'],
|
|
24
|
+
chore: ['plan', 'build', 'evaluate'],
|
|
25
|
+
incident: ['build', 'deliver', 'monitor', 'evaluate'],
|
|
26
|
+
content: ['ideate', 'plan', 'build', 'deliver'],
|
|
27
|
+
prototype: ['discover', 'ideate', 'evaluate'],
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Stages that have a derived signal today. Every other stage reads `no-signal` until its record exists.
|
|
31
|
+
const SIGNALLED = new Set(['discover', 'plan', 'build', 'evaluate']);
|
|
32
|
+
|
|
33
|
+
const RANK = { intake: 0, spec: 1, contract: 2, build: 3, eval: 4, accepted: 5 };
|
|
34
|
+
|
|
35
|
+
// Stages that gain a signal only when the caller passes the records (scripts/records readAll plus optional `releases`).
|
|
36
|
+
// With no records the output is exactly the older output, so the lifecycle-lens mirror stays equal.
|
|
37
|
+
const RECORD_SIGNALLED = new Set(['ideate', 'strategize', 'prioritize', 'monitor', 'deliver']);
|
|
38
|
+
|
|
39
|
+
// records: { initiative?, anchor?, ideas, hypotheses, decisions, bets, 'kr-metrics', releases } (every list optional).
|
|
40
|
+
// The initiative id and anchor come from `derived` (id, anchor) or from records.initiative / records.anchor.
|
|
41
|
+
function recordSignals(derived, records, buildDone) {
|
|
42
|
+
const id = (derived && derived.id) || records.initiative || null;
|
|
43
|
+
const anchor = (derived && derived.anchor) || records.anchor || null;
|
|
44
|
+
const mine = (list) => (list || []).filter((r) => id && r.initiative === id);
|
|
45
|
+
const kr = (records['kr-metrics'] || []).filter((m) => anchor && (m.rid === anchor || m.parent_kr === anchor || 'kr:' + m.rid === anchor));
|
|
46
|
+
return {
|
|
47
|
+
ideate: mine(records.ideas).length + mine(records.hypotheses).length > 0,
|
|
48
|
+
strategize: mine(records.decisions).length + mine(records.bets).length > 0,
|
|
49
|
+
prioritize: mine(records.bets).some((b) => ['now', 'next', 'later'].includes(b.horizon) && Number.isInteger(b.rank)),
|
|
50
|
+
monitor: !!buildDone && kr.some((m) => (m.readings || []).length > 0),
|
|
51
|
+
deliver: mine(records.releases).length > 0,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function nineStages(lane, derived, records) {
|
|
56
|
+
const laneSet = new Set(LANE_STAGES[lane] || STAGES);
|
|
57
|
+
const rank = RANK[derived && derived.stage] ?? 0;
|
|
58
|
+
const step = (key) => (derived && derived.steps || []).find((s) => s.key === key);
|
|
59
|
+
const done = {
|
|
60
|
+
discover: rank >= 1,
|
|
61
|
+
plan: rank >= 2,
|
|
62
|
+
build: rank >= 3 || (step('build') && step('build').status === 'done'),
|
|
63
|
+
evaluate: rank >= 4,
|
|
64
|
+
};
|
|
65
|
+
const accepted = rank >= 5;
|
|
66
|
+
const fromRecords = records && typeof records === 'object' ? recordSignals(derived, records, done.build) : null;
|
|
67
|
+
const out = [];
|
|
68
|
+
let currentSet = false;
|
|
69
|
+
for (const key of STAGES) {
|
|
70
|
+
let status;
|
|
71
|
+
if (!laneSet.has(key)) status = 'skipped';
|
|
72
|
+
else if (!SIGNALLED.has(key) && !(fromRecords && RECORD_SIGNALLED.has(key) && (key !== 'deliver' || fromRecords.deliver))) status = 'no-signal';
|
|
73
|
+
else if (done[key] || (fromRecords && fromRecords[key])) status = 'done';
|
|
74
|
+
else status = 'pending';
|
|
75
|
+
if (status === 'pending' && !currentSet) { status = 'current'; currentSet = true; }
|
|
76
|
+
out.push({ key, label: LABELS[key], status, accepted: key === 'evaluate' ? accepted : undefined });
|
|
77
|
+
}
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports = { STAGES, LABELS, LANE_STAGES, nineStages };
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
* Zero dependencies, stock Node. It runs in CI, in a terminal, and inside the workspace server.
|
|
37
37
|
*/
|
|
38
38
|
|
|
39
|
+
const { nineStages } = require('./nine-stages');
|
|
39
40
|
const fs = require('fs');
|
|
40
41
|
const path = require('path');
|
|
41
42
|
const { execFileSync } = require('child_process');
|
|
@@ -1178,6 +1179,7 @@ function computeWorkflowDerived(id, opts) {
|
|
|
1178
1179
|
ok: true, id, lane, laneKnown: knownLane, legacy, in_change: inChange,
|
|
1179
1180
|
last_activity: lastActivity, accepted: accepted.length > 0, stage, record: recRel,
|
|
1180
1181
|
title: fm.title || id, anchor: fm.parent_kr || null, profile: 'product-code',
|
|
1182
|
+
nine_stages: nineStages(effLane, { stage, steps }),
|
|
1181
1183
|
...facts,
|
|
1182
1184
|
steps, blockers: blockers.map((s) => s.key), gate_failures: gateFailures.map((s) => s.rule || s.key),
|
|
1183
1185
|
next: next ? { step: next.key, why: next.evidence, action: next.next || next.evidence } : null,
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/* facts-async.js — the repo's initiative facts (scripts/signals/facts.js readRepoFacts) WITHOUT blocking the server.
|
|
3
|
+
*
|
|
4
|
+
* readRepoFacts derives every initiative's stage from git, once per initiative: minutes for ~300 records, and synchronous.
|
|
5
|
+
* Called inside the server process it stops every other request (the page sat "just loading"). This runs it in a child
|
|
6
|
+
* process (scripts/signals/facts-cli.js), keeps one result per root and day for five minutes, and shares one read in
|
|
7
|
+
* flight between callers, so a burst of requests starts one child, not one each. Once a result is older than five minutes it
|
|
8
|
+
* is still returned at once while a new read runs in the background (stale while revalidate), so only the first read waits.
|
|
9
|
+
*/
|
|
10
|
+
const { execFile } = require('child_process');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
|
|
13
|
+
const CLI = path.resolve(__dirname, '..', '..', 'scripts', 'signals', 'facts-cli.js');
|
|
14
|
+
const TTL_MS = 5 * 60 * 1000;
|
|
15
|
+
const memo = new Map(); // root|today -> { at, facts }
|
|
16
|
+
const inflight = new Map(); // root|today -> Promise
|
|
17
|
+
|
|
18
|
+
function readFactsAsync(root, opts = {}) {
|
|
19
|
+
const today = opts.today || '';
|
|
20
|
+
const resolved = path.resolve(root || process.cwd());
|
|
21
|
+
const key = resolved + '|' + today;
|
|
22
|
+
const clock = opts.clock || Date.now;
|
|
23
|
+
const hit = memo.get(key);
|
|
24
|
+
const fresh = hit && clock() - hit.at < (opts.ttlMs == null ? TTL_MS : opts.ttlMs);
|
|
25
|
+
if (fresh) return Promise.resolve(hit.facts);
|
|
26
|
+
|
|
27
|
+
const start = () => {
|
|
28
|
+
if (inflight.has(key)) return inflight.get(key);
|
|
29
|
+
const run = opts.run || ((r, t) => new Promise((resolve, reject) => {
|
|
30
|
+
execFile(process.execPath, [CLI, r, t], { maxBuffer: 512 * 1024 * 1024, timeout: 15 * 60 * 1000 }, (err, out) => {
|
|
31
|
+
if (err) return reject(err);
|
|
32
|
+
try { resolve(JSON.parse(out)); } catch (e) { reject(e); }
|
|
33
|
+
});
|
|
34
|
+
}));
|
|
35
|
+
const p = Promise.resolve(run(resolved, today)).then((facts) => {
|
|
36
|
+
memo.set(key, { at: clock(), facts });
|
|
37
|
+
return facts;
|
|
38
|
+
}).finally(() => { inflight.delete(key); });
|
|
39
|
+
inflight.set(key, p);
|
|
40
|
+
return p;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Stale while revalidate: an expired result is still the best answer for now. Return it at once and refresh in the
|
|
44
|
+
// background, so only the very first read of a repository ever waits (opts.stale === false turns this off).
|
|
45
|
+
if (hit && opts.stale !== false) { start().catch(() => {}); return Promise.resolve(hit.facts); }
|
|
46
|
+
return start();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function resetFactsCache() { memo.clear(); inflight.clear(); }
|
|
50
|
+
|
|
51
|
+
module.exports = { readFactsAsync, resetFactsCache, TTL_MS };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/* item-steps.js — per-item steps for the PM's work items (console3 wave A1). Append-only JSONL, like pm-items.js.
|
|
3
|
+
*
|
|
4
|
+
* A step is { id, text, who }, who = 'you' | 'agent-drafts' | 'agent-does'. Events: step_added, who_set, step_removed.
|
|
5
|
+
* OUTWARD RULE: a step that sends something to a person (send, email, message, tell, post, reply to) is never
|
|
6
|
+
* 'agent-does'. It is forced to 'agent-drafts': the agent drafts and the PM's slide releases it. The outbox is
|
|
7
|
+
* scripts/outbox.js; it is deliberately not wired here.
|
|
8
|
+
* The writer is pm-items.appendEvent (same single-writer rule).
|
|
9
|
+
*/
|
|
10
|
+
const WHO = ['you', 'agent-drafts', 'agent-does'];
|
|
11
|
+
const OUTWARD = /\b(send|sends|sending|email|emails|message|messages|tell|post|reply to)\b/i;
|
|
12
|
+
|
|
13
|
+
const isOutward = (text) => OUTWARD.test(String(text || ''));
|
|
14
|
+
|
|
15
|
+
// The who a step may hold: outward steps never go beyond 'agent-drafts'.
|
|
16
|
+
function clampWho(text, who) {
|
|
17
|
+
if (!WHO.includes(who)) return null;
|
|
18
|
+
return who === 'agent-does' && isOutward(text) ? 'agent-drafts' : who;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function addStep(itemId, text, who, id) {
|
|
22
|
+
const t = String(text || '').trim();
|
|
23
|
+
if (!t) return { ok: false, error: 'the step needs text' };
|
|
24
|
+
const w = clampWho(t, who === undefined ? 'you' : who);
|
|
25
|
+
if (!w) return { ok: false, error: 'who must be you, agent-drafts or agent-does' };
|
|
26
|
+
return { ok: true, forced: w !== (who === undefined ? 'you' : who), event: { event: 'step_added', item_id: itemId, id, text: t, who: w } };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function setWho(lines, stepId, who) {
|
|
30
|
+
const step = foldSteps(lines).all.find((s) => s.id === stepId);
|
|
31
|
+
if (!step) return { ok: false, error: 'no such step' };
|
|
32
|
+
const w = clampWho(step.text, who);
|
|
33
|
+
if (!w) return { ok: false, error: 'who must be you, agent-drafts or agent-does' };
|
|
34
|
+
return { ok: true, who: w, forced: w !== who, event: { event: 'who_set', id: stepId, who: w } };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Fold the lines into { byItem: { itemId: [step] }, all: [step] }, in the order added.
|
|
38
|
+
function foldSteps(lines) {
|
|
39
|
+
const steps = new Map();
|
|
40
|
+
for (const ev of lines || []) {
|
|
41
|
+
if (!ev || !ev.id) continue;
|
|
42
|
+
if (ev.event === 'step_added') steps.set(ev.id, { id: ev.id, item_id: ev.item_id, text: ev.text, who: clampWho(ev.text, ev.who) || 'you' });
|
|
43
|
+
else if (ev.event === 'who_set' && steps.has(ev.id)) { const s = steps.get(ev.id); s.who = clampWho(s.text, ev.who) || s.who; }
|
|
44
|
+
else if (ev.event === 'step_removed') steps.delete(ev.id);
|
|
45
|
+
}
|
|
46
|
+
const all = [...steps.values()];
|
|
47
|
+
const byItem = {};
|
|
48
|
+
for (const s of all) (byItem[s.item_id] = byItem[s.item_id] || []).push({ id: s.id, text: s.text, who: s.who });
|
|
49
|
+
return { byItem, all };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = { WHO, isOutward, clampWho, addStep, setWho, foldSteps };
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* which(root, key) → the initiative and ticket a key belongs to
|
|
15
15
|
*
|
|
16
16
|
* A READING is { key, summary, status, category: todo|doing|done, sprint: { name, state: active|future|closed } | null,
|
|
17
|
-
* subtasks: { done, total }, flagged, reason, url }. A ticket the search did not return keeps its last reading, marked
|
|
17
|
+
* subtasks: { done, total }, fixVersion: [names], flagged, reason, url }. A ticket the search did not return keeps its last reading, marked
|
|
18
18
|
* stale. Titles and statuses only: never a description, a comment or a person.
|
|
19
19
|
*
|
|
20
20
|
* BOUNDARY (J15). No network module, no child process. The only write is the snapshot file.
|
|
@@ -69,6 +69,11 @@ function flaggedIn(fields) {
|
|
|
69
69
|
}
|
|
70
70
|
return false;
|
|
71
71
|
}
|
|
72
|
+
/** fixVersions (Jira's release tags) as a list of names; the flat shape may say fixVersion or fixVersions, a name or a list. */
|
|
73
|
+
function fixVersionsOf(v) {
|
|
74
|
+
const list = Array.isArray(v) ? v : v == null || v === '' ? [] : [v];
|
|
75
|
+
return [...new Set(list.map((x) => clip(nameOf(x), 80)).filter(Boolean))];
|
|
76
|
+
}
|
|
72
77
|
const SPRINT_STATES = ['active', 'future', 'closed'];
|
|
73
78
|
/** One sprint, from an object { name, state } or a bare name. */
|
|
74
79
|
function sprintOne(v) {
|
|
@@ -128,7 +133,7 @@ function normalizeIssue(x) {
|
|
|
128
133
|
const st = f.status || {};
|
|
129
134
|
const status = nameOf(st) || 'Unknown';
|
|
130
135
|
const flagged = flaggedIn(f) || /block|impediment|on hold/i.test(status);
|
|
131
|
-
return { key, summary, status, category: categoryOf(status, st.statusCategory), sprint: sprintIn(f), subtasks: subtasksOf(f.subtasks),
|
|
136
|
+
return { key, summary, status, category: categoryOf(status, st.statusCategory), sprint: sprintIn(f), subtasks: subtasksOf(f.subtasks), fixVersion: fixVersionsOf(f.fixVersions),
|
|
132
137
|
flagged, reason: flagged ? (flaggedIn(f) ? 'Flagged in Jira' : `Status: ${status}`) : null, url: urlOf(x, key) };
|
|
133
138
|
}
|
|
134
139
|
// The flat shape: what the skill tells the agent to write when it is unsure of the connector's shape.
|
|
@@ -136,7 +141,7 @@ function normalizeIssue(x) {
|
|
|
136
141
|
if (!summary) return null;
|
|
137
142
|
const status = oneLine(x.status) || 'Unknown';
|
|
138
143
|
const flagged = x.flagged === true || /block|impediment|on hold/i.test(status);
|
|
139
|
-
return { key, summary, status, category: categoryOf(status, x.category), sprint: sprintOf(x.sprint), subtasks: subtasksOf(x.subtasks),
|
|
144
|
+
return { key, summary, status, category: categoryOf(status, x.category), sprint: sprintOf(x.sprint), subtasks: subtasksOf(x.subtasks), fixVersion: fixVersionsOf(x.fixVersions != null ? x.fixVersions : x.fixVersion),
|
|
140
145
|
flagged, reason: flagged ? clip(oneLine(x.reason || x.flag_reason || (x.flagged === true ? 'Flagged in Jira' : `Status: ${status}`)), 160) : null,
|
|
141
146
|
url: urlOf(x, key) };
|
|
142
147
|
}
|