create-pmos 0.134.0 → 0.135.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/bin/notes-replay.js +235 -0
- package/workspace/c3-briefing-test.js +130 -0
- package/workspace/c3-foundation-test.js +159 -0
- package/workspace/c3-ib-items-test.js +105 -0
- package/workspace/c3-ib-more-test.js +120 -0
- package/workspace/c3-ib-triage-backlog-test.js +119 -0
- package/workspace/c3-ini-harness.js +66 -0
- package/workspace/c3-initiatives-test.js +140 -0
- package/workspace/c3-one-home-test.js +14 -1
- package/workspace/c3-reports-test.js +57 -18
- package/workspace/c3-settings-test.js +139 -0
- package/workspace/c3-work-test.js +42 -10
- package/workspace/fixtures/one-home-baseline.json +1 -9
- package/workspace/guide/briefing-cards.md +15 -3
- package/workspace/guide/briefing.md +12 -8
- package/workspace/guide/calendar-popup.md +2 -2
- package/workspace/guide/console-calendar.md +39 -10
- package/workspace/guide/index.md +1 -0
- package/workspace/guide/initiative-boards.md +65 -0
- package/workspace/guide/jira.md +3 -1
- package/workspace/guide/layout.md +2 -0
- package/workspace/guide/my-work.md +5 -3
- package/workspace/guide/notes.md +16 -1
- package/workspace/guide/reports-dashboards.md +29 -5
- package/workspace/guide/settings.md +68 -0
- package/workspace/guide/welcome.md +10 -10
- package/workspace/lib/calendar-cli.js +3 -2
- package/workspace/lib/calendar-layers.js +21 -10
- package/workspace/lib/calendar-tidy.js +230 -0
- package/workspace/lib/engine/boards.js +542 -0
- package/workspace/lib/engine/breakdown-ops.js +180 -0
- package/workspace/lib/engine/calendar-import.js +84 -0
- package/workspace/lib/engine/calendar-model.js +185 -0
- package/workspace/lib/engine/card-state.js +92 -0
- package/workspace/lib/engine/derived/derive.js +92 -0
- package/workspace/lib/engine/derived/plan.js +3 -0
- package/workspace/lib/engine/derived/trust.js +3 -0
- package/workspace/lib/engine/doc-health.js +142 -0
- package/workspace/lib/engine/doc-sheet.js +75 -0
- package/workspace/lib/engine/intake.js +78 -0
- package/workspace/lib/engine/outbox.js +86 -0
- package/workspace/lib/engine/plan-forecast.js +342 -0
- package/workspace/lib/engine/promises.js +29 -0
- package/workspace/lib/engine/records/index.js +114 -0
- package/workspace/lib/engine/releases.js +96 -0
- package/workspace/lib/engine/replies.js +99 -0
- package/workspace/lib/engine/reply-contract/reply-contract.js +372 -0
- package/workspace/lib/engine/report-families.js +175 -0
- package/workspace/lib/engine/roadmap-ops.js +150 -0
- package/workspace/lib/engine/sessions-list.js +27 -0
- package/workspace/lib/engine/signal-rules.js +95 -0
- package/workspace/lib/engine/signals/cards.js +57 -0
- package/workspace/lib/engine/signals/detectors.js +370 -0
- package/workspace/lib/engine/signals/facts-cli.js +8 -0
- package/workspace/lib/engine/signals/facts.js +197 -0
- package/workspace/lib/engine/signals/index.js +33 -0
- package/workspace/lib/engine/signals/kinds.js +110 -0
- package/workspace/lib/engine/signals/layout-paths.js +44 -0
- package/workspace/lib/engine/signals/options.js +24 -0
- package/workspace/lib/engine/signals/score.js +72 -0
- package/workspace/lib/engine/signals/select.js +47 -0
- package/workspace/lib/engine/step-planner.js +65 -0
- package/workspace/lib/engine/trust/claim-rules.json +93 -0
- package/workspace/lib/engine/trust/import-calendar.js +21 -0
- package/workspace/lib/engine/trust/import-guard.js +36 -0
- package/workspace/lib/engine/trust/ledger.js +53 -0
- package/workspace/lib/engine/trust/outbox.js +45 -0
- package/workspace/lib/engine/trust/plan.js +5 -0
- package/workspace/lib/engine/trust/trust.js +21 -0
- package/workspace/lib/engine/truth-table.js +57 -0
- package/workspace/lib/engine/workspace-lib.js +24 -0
- package/workspace/lib/factory-join.js +1 -1
- package/workspace/lib/facts-async.js +4 -4
- package/workspace/lib/headless.js +95 -0
- package/workspace/lib/import-overlay.js +2 -1
- package/workspace/lib/jira-status.js +30 -3
- package/workspace/lib/notes-capture.js +9 -1
- package/workspace/lib/notes-final.js +38 -13
- package/workspace/lib/notes-replay.js +125 -0
- package/workspace/lib/notes-screen.js +180 -0
- package/workspace/lib/notes-whisper.js +10 -3
- package/workspace/lib/outbox-store.js +10 -6
- package/workspace/lib/pmos-verbs.js +3 -1
- package/workspace/lib/proactive-cli.js +7 -0
- package/workspace/lib/proactive.js +15 -2
- package/workspace/lib/repo-script.js +36 -0
- package/workspace/lib/report-dashboards.js +5 -2
- package/workspace/lib/report-frame.js +122 -0
- package/workspace/lib/report-schedules.js +113 -0
- package/workspace/lib/route-modules.js +9 -2
- package/workspace/lib/routes-boards.js +734 -0
- package/workspace/lib/routes-brief-page.js +13 -4
- package/workspace/lib/routes-briefing.js +22 -11
- package/workspace/lib/routes-c3-init.js +4 -3
- package/workspace/lib/routes-c3-life.js +2 -1
- package/workspace/lib/routes-c3-reports.js +96 -13
- package/workspace/lib/routes-c3-strategy.js +4 -3
- package/workspace/lib/routes-c3-timeline.js +3 -2
- package/workspace/lib/routes-calendar-import.js +3 -2
- package/workspace/lib/routes-calendar-views.js +9 -4
- package/workspace/lib/routes-doc-health.js +2 -1
- package/workspace/lib/routes-doc-sheet.js +2 -1
- package/workspace/lib/routes-forecast.js +2 -1
- package/workspace/lib/routes-hooks.js +3 -2
- package/workspace/lib/routes-initiatives.js +2 -1
- package/workspace/lib/routes-intake.js +2 -1
- package/workspace/lib/routes-notes.js +55 -9
- package/workspace/lib/routes-outbox.js +23 -3
- package/workspace/lib/routes-pm-items.js +19 -6
- package/workspace/lib/routes-records.js +3 -2
- package/workspace/lib/routes-releases.js +2 -1
- package/workspace/lib/routes-report-facts.js +4 -3
- package/workspace/lib/routes-report-families.js +2 -1
- package/workspace/lib/routes-roadmap-ops.js +5 -4
- package/workspace/lib/routes-runs.js +6 -5
- package/workspace/lib/routes-settings.js +51 -0
- package/workspace/lib/routes-signals.js +3 -2
- package/workspace/lib/routes-stage-tools.js +220 -0
- package/workspace/lib/run-answers.js +2 -1
- package/workspace/lib/settings-store.js +226 -0
- package/workspace/lib/stage-tools.js +208 -0
- package/workspace/lib/vendor/scripts/signals/layout-paths.js +2 -1
- package/workspace/lib/vendor/scripts/workspace-lib.js +24 -0
- package/workspace/lib/work-evidence.js +73 -0
- package/workspace/package-lock.json +2 -2
- package/workspace/package.json +1 -1
- package/workspace/public/pm/briefing-deck.js +63 -17
- package/workspace/public/pm/briefing-model.js +36 -7
- package/workspace/public/pm/c3-ambient.js +100 -0
- package/workspace/public/pm/c3-brief-needs.js +26 -6
- package/workspace/public/pm/c3-brief-pulse.js +12 -4
- package/workspace/public/pm/c3-brief-today.js +56 -21
- package/workspace/public/pm/c3-brief.js +2 -1
- package/workspace/public/pm/c3-calendar.js +161 -42
- package/workspace/public/pm/c3-calpop.js +5 -5
- package/workspace/public/pm/c3-demo-boards.js +649 -0
- package/workspace/public/pm/c3-demo-brief-page.js +1 -1
- package/workspace/public/pm/c3-demo-cal4.js +3 -2
- package/workspace/public/pm/c3-demo-cal5.js +52 -0
- package/workspace/public/pm/c3-demo-data.js +17 -27
- package/workspace/public/pm/c3-demo-rep3.js +46 -5
- package/workspace/public/pm/c3-demo.js +2 -1
- package/workspace/public/pm/c3-dock.js +1 -1
- package/workspace/public/pm/c3-ib-docs.js +80 -0
- package/workspace/public/pm/c3-ib-initiatives.js +134 -0
- package/workspace/public/pm/c3-ib-items.js +201 -0
- package/workspace/public/pm/c3-ib-releases.js +51 -0
- package/workspace/public/pm/c3-ib-sprints.js +55 -0
- package/workspace/public/pm/c3-ib-triage.js +178 -0
- package/workspace/public/pm/c3-ii-tabs.js +240 -0
- package/workspace/public/pm/c3-ini-records.js +197 -0
- package/workspace/public/pm/c3-ini-timeline.js +278 -0
- package/workspace/public/pm/c3-ini-ui.js +229 -0
- package/workspace/public/pm/c3-ini-work.js +139 -0
- package/workspace/public/pm/c3-initiatives.css +218 -0
- package/workspace/public/pm/c3-initiatives.js +741 -0
- package/workspace/public/pm/c3-plan.js +2 -2
- package/workspace/public/pm/c3-reports.css +47 -47
- package/workspace/public/pm/c3-reports.js +223 -185
- package/workspace/public/pm/c3-settings.css +74 -0
- package/workspace/public/pm/c3-settings.js +703 -0
- package/workspace/public/pm/c3-shell.js +102 -36
- package/workspace/public/pm/c3-terminal-icons.js +2 -2
- package/workspace/public/pm/c3-terminal.js +2 -2
- package/workspace/public/pm/calendar-views.js +1 -1
- package/workspace/public/pm/components.css +319 -213
- package/workspace/public/pm/console3.css +99 -23
- package/workspace/public/pm/dest-notes.js +26 -4
- package/workspace/public/pm/notes-screen-capture.js +165 -0
- package/workspace/public/pm/notes-screen-view.js +98 -0
- package/workspace/public/pm/panel-trees.js +5 -2
- package/workspace/public/pm/pm-work-view.js +233 -146
- package/workspace/public/pm/shell-bell.js +3 -2
- package/workspace/public/pm/shell-recording.js +29 -8
- package/workspace/public/pm/tokens.css +2 -2
- package/workspace/public/pm/view-notes.js +46 -9
- package/workspace/public/pm/welcome.js +197 -89
- package/workspace/public/welcome.html +6 -4
- package/workspace/server.js +105 -6
- package/workspace/skills/day-check.skill +1 -1
- package/workspace/skills/jira-sync.skill +6 -4
- package/workspace/skills/morning-brief.skill +1 -1
- package/workspace/test-files.json +12 -3
- package/workspace/test-lists/c3-ib-items.json +9 -0
- package/workspace/test-lists/c3-ib-more.json +9 -0
- package/workspace/test-lists/c3-ib-triage-backlog.json +9 -0
- package/workspace/test-lists/c3-initiative-boards.json +6 -0
- package/workspace/test-lists/calendar-tidy-up.json +6 -0
- package/workspace/test-lists/console3-briefing.json +9 -0
- package/workspace/test-lists/console3-foundation.json +9 -0
- package/workspace/test-lists/console3-reports.json +3 -3
- package/workspace/test-lists/meeting-notes.json +10 -4
- package/workspace/test-lists/workspace-headless-jobs.json +5 -0
- package/workspace/test-lists/workspace-package-script-closure.json +6 -0
- package/workspace/lib/vendor/workspace/lib/actor.js +0 -91
- package/workspace/lib/vendor/workspace/lib/board-cache.js +0 -156
- package/workspace/lib/vendor/workspace/lib/console-state.js +0 -295
- package/workspace/lib/vendor/workspace/lib/factory-join.js +0 -158
- package/workspace/lib/vendor/workspace/lib/git-info.js +0 -306
- package/workspace/lib/vendor/workspace/lib/plan-items.js +0 -922
- package/workspace/lib/vendor/workspace/lib/plan-tree.js +0 -419
- package/workspace/lib/vendor/workspace/lib/review-gate.js +0 -39
- package/workspace/lib/vendor/workspace/lib/sink.js +0 -321
- package/workspace/lib/vendor/workspace/lib/state-root.js +0 -587
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
/* routes-brief-page.js — GET /api/brief-page[?ws=<id>&now=ISO] (console3 Briefing as the brief, PRD briefing-brief R2, R3, R8).
|
|
3
3
|
*
|
|
4
|
-
* → { ok, date, today: [meeting], needs: [row], decisions_error? }
|
|
4
|
+
* → { ok, date, me?, today: [meeting], needs: [row], decisions_error? } me: the PM's first name from git config user.name, or null
|
|
5
5
|
*
|
|
6
6
|
* READ ONLY, and built only from what PMOS already holds. Nothing is invented.
|
|
7
7
|
* today one row per meeting of the local day, in time order, from the cached calendar events (routes-calendar-import.js readEvents,
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
* has it. A deferred item ('Not yet') is left out until its defer date or time. Writes go through the existing pm-items routes. */
|
|
22
22
|
const path = require('path');
|
|
23
23
|
const pmItems = require('./pm-items.js');
|
|
24
|
+
const { repoScript } = require('./repo-script.js');
|
|
24
25
|
|
|
25
26
|
const pad = (n) => String(n).padStart(2, '0');
|
|
26
27
|
const localDate = (d) => `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
@@ -153,9 +154,17 @@ function notesAdapter(runtimeDir) {
|
|
|
153
154
|
};
|
|
154
155
|
}
|
|
155
156
|
|
|
157
|
+
/** The PM's first name for the greeting: the first word of `git config user.name` where PMOS runs. null when git holds none (the page then greets without a name). */
|
|
158
|
+
function firstName(cwd) {
|
|
159
|
+
try {
|
|
160
|
+
const n = String(require('child_process').execFileSync('git', ['config', 'user.name'], { cwd, encoding: 'utf8', timeout: 2000, stdio: ['ignore', 'pipe', 'ignore'] })).trim().split(/\s+/)[0];
|
|
161
|
+
return n && n.length <= 40 ? n : null;
|
|
162
|
+
} catch { return null; }
|
|
163
|
+
}
|
|
164
|
+
|
|
156
165
|
module.exports = {
|
|
157
166
|
prefixes: ['/api/brief-page'],
|
|
158
|
-
build, todayAgenda, needsOf, evidenceFor, deferred,
|
|
167
|
+
build, todayAgenda, needsOf, evidenceFor, deferred, firstName,
|
|
159
168
|
handle: async (req, res, url, ctx) => {
|
|
160
169
|
if (url.pathname !== '/api/brief-page') return false;
|
|
161
170
|
if (req.method !== 'GET') { ctx.json(res, { ok: false, error: 'GET only' }, 405); return true; }
|
|
@@ -174,10 +183,10 @@ module.exports = {
|
|
|
174
183
|
const root = (w && w.root) || path.resolve(__dirname, '..', '..');
|
|
175
184
|
const iso = localDate(now);
|
|
176
185
|
const facts = await require('./facts-async.js').readFactsAsync(root, { today: iso });
|
|
177
|
-
|
|
178
|
-
cards = require(path.join(sig, 'index.js')).present(facts, { lens: 'Unblock', zoom: 'week', today: iso }).cards || [];
|
|
186
|
+
cards = require(repoScript('signals/index.js')).present(facts, { lens: 'Unblock', zoom: 'week', today: iso }).cards || [];
|
|
179
187
|
} catch (e) { decisionsError = 'the decisions could not be read: ' + (e && e.message ? e.message : String(e)); }
|
|
180
188
|
const out = build({ now: now.toISOString() }, { events, items, cards, decisionsError, notes: dir ? notesAdapter(dir) : {} });
|
|
189
|
+
if (out.body && out.body.ok) out.body.me = firstName(path.resolve(__dirname, '..', '..'));
|
|
181
190
|
ctx.json(res, out.body, out.status);
|
|
182
191
|
} catch (e) {
|
|
183
192
|
ctx.json(res, { ok: false, error: 'the brief page could not be built: ' + (e && e.message ? e.message : String(e)) }, 500);
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
/* routes-briefing.js — GET /api/briefing?lens=Plan|Unblock|Close|Reflect&zoom=day|week|month[&now=ISO] (console3 wave C1).
|
|
2
|
+
/* routes-briefing.js — GET /api/briefing?lens=Plan|Unblock|Close|Reflect&zoom=day|week|month[&scope=brief|rep][&now=ISO] (console3 wave C1).
|
|
3
3
|
*
|
|
4
|
-
* { ok, lens, zoom, cards, ticker, banner, own_needs }
|
|
5
|
-
*
|
|
4
|
+
* { ok, scope, lens, zoom, cards, ticker, banner, own_needs }
|
|
5
|
+
* scope: whose deck asks. brief (or none) runs the engine's briefing detectors, rep its reports detectors (console3-deck-flow-fixes).
|
|
6
|
+
* Any other scope answers no cards, so a page never shows another page's cards.
|
|
7
|
+
* own_needs: the PM's own items overdue or due today, as needs rows (lib/needs-overdue.js), overdue first. Briefing scope only; the page shows them above the cards.
|
|
8
|
+
* notices: the drafts a dashboard schedule made in the last 7 days that are still in the outbox (lib/report-schedules.js noticesOf).
|
|
9
|
+
* Additive; the bell lists them after the cards, and each opens Reports > Drafts.
|
|
6
10
|
*
|
|
7
11
|
* `cards` are the engine's selected cards (scripts/signals present() over readRepoFacts of the repo root), with the card
|
|
8
12
|
* anatomy untouched. `ticker` is one line per top card, built from the card's own headline and deadline. `banner` is the
|
|
@@ -10,9 +14,12 @@
|
|
|
10
14
|
* { ok:false, error } with 500 and never throws out of the handler.
|
|
11
15
|
*/
|
|
12
16
|
const path = require('path');
|
|
17
|
+
const { repoScript } = require('./repo-script.js');
|
|
13
18
|
|
|
14
19
|
const LENSES = ['Plan', 'Unblock', 'Close', 'Reflect'];
|
|
15
20
|
const ZOOMS = ['day', 'week', 'month'];
|
|
21
|
+
// the engine's detector pages for each deck that asks (scripts/signals/detectors.js `page`)
|
|
22
|
+
const SCOPE_PAGES = { brief: ['briefing'], rep: ['reports'] };
|
|
16
23
|
|
|
17
24
|
function lensFor(date) {
|
|
18
25
|
const h = date.getHours();
|
|
@@ -38,9 +45,8 @@ function factsOnce(eng, root, iso) {
|
|
|
38
45
|
|
|
39
46
|
function loadEngine() {
|
|
40
47
|
// the engine is this repo's; `root` only says which repo's initiatives it reads
|
|
41
|
-
const
|
|
42
|
-
const {
|
|
43
|
-
const { readRepoFacts } = require(path.join(sig, 'facts.js'));
|
|
48
|
+
const { present } = require(repoScript('signals/index.js'));
|
|
49
|
+
const { readRepoFacts } = require(repoScript('signals/facts.js'));
|
|
44
50
|
return { present, readRepoFacts };
|
|
45
51
|
}
|
|
46
52
|
|
|
@@ -52,12 +58,15 @@ function briefing(query, opts = {}) {
|
|
|
52
58
|
if (isNaN(now.getTime())) now = new Date();
|
|
53
59
|
const lens = LENSES.includes(q.lens) ? q.lens : lensFor(now);
|
|
54
60
|
const zoom = ZOOMS.includes(q.zoom) ? q.zoom : 'week';
|
|
61
|
+
const scope = q.scope ? String(q.scope) : 'brief';
|
|
62
|
+
const pages = SCOPE_PAGES[scope];
|
|
63
|
+
if (!pages) return { code: 200, body: { ok: true, scope, lens, zoom, cards: [], ticker: [], banner: null } };
|
|
55
64
|
try {
|
|
56
65
|
const eng = (opts.load || loadEngine)(root);
|
|
57
66
|
const iso = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0') + '-' + String(now.getDate()).padStart(2, '0');
|
|
58
67
|
const facts = opts.load ? eng.readRepoFacts(root, { today: iso }) : factsOnce(eng, root, iso);
|
|
59
68
|
let useLens = lens;
|
|
60
|
-
let cards = eng.present(facts, { lens, zoom, today: iso }).cards || [];
|
|
69
|
+
let cards = eng.present(facts, { lens, zoom, today: iso, pages }).cards || [];
|
|
61
70
|
// When the clock's lens has no card, show the lens that has the most (ties keep the clock's lens). On the real repo
|
|
62
71
|
// this is usually all four empty: the briefing detectors read promised dates, forecasts, holders and the like, and no
|
|
63
72
|
// initiative record carries them yet. The answer then stays empty and says so by fallback_lens being absent.
|
|
@@ -65,12 +74,12 @@ function briefing(query, opts = {}) {
|
|
|
65
74
|
if (!cards.length && !q.lens) {
|
|
66
75
|
for (const l of LENSES) {
|
|
67
76
|
if (l === lens) continue;
|
|
68
|
-
const c = eng.present(facts, { lens: l, zoom, today: iso }).cards || [];
|
|
77
|
+
const c = eng.present(facts, { lens: l, zoom, today: iso, pages }).cards || [];
|
|
69
78
|
if (c.length > cards.length) { cards = c; useLens = l; fallback = true; }
|
|
70
79
|
}
|
|
71
80
|
}
|
|
72
81
|
const banner = cards.find((c) => c.pinned && c.tag === 'Critical') || null;
|
|
73
|
-
return { code: 200, body: { ok: true, lens: useLens, zoom, cards, ticker: tickerOf(cards), banner, ...(fallback ? { fallback_lens: true } : {}) } };
|
|
82
|
+
return { code: 200, body: { ok: true, scope, lens: useLens, zoom, cards, ticker: tickerOf(cards), banner, ...(fallback ? { fallback_lens: true } : {}) } };
|
|
74
83
|
} catch (e) {
|
|
75
84
|
return { code: 500, body: { ok: false, error: 'the signal engine failed: ' + (e && e.message ? e.message : String(e)) } };
|
|
76
85
|
}
|
|
@@ -78,7 +87,7 @@ function briefing(query, opts = {}) {
|
|
|
78
87
|
|
|
79
88
|
module.exports = {
|
|
80
89
|
prefixes: ['/api/briefing'],
|
|
81
|
-
briefing, lensFor, tickerOf,
|
|
90
|
+
briefing, lensFor, tickerOf, SCOPE_PAGES,
|
|
82
91
|
handle: async (req, res, url, ctx) => {
|
|
83
92
|
if (url.pathname !== '/api/briefing') return false;
|
|
84
93
|
if (req.method !== 'GET') { ctx.json(res, { ok: false, error: 'GET only' }, 405); return true; }
|
|
@@ -96,12 +105,14 @@ module.exports = {
|
|
|
96
105
|
const eng = loadEngine();
|
|
97
106
|
const out = briefing(q, { root: useRoot, load: () => ({ present: eng.present, readRepoFacts: () => facts }) });
|
|
98
107
|
// additive: the PM's own overdue and due-today items, as needs rows beside the engine's cards (lib/needs-overdue.js); a read failure leaves the list empty
|
|
99
|
-
if (out.code === 200) {
|
|
108
|
+
if (out.code === 200 && out.body.scope === 'brief') {
|
|
100
109
|
try {
|
|
101
110
|
const pmItems = require('./pm-items.js');
|
|
102
111
|
const file = path.join(ctx.runtimeDir, 'pm-items', 'items.jsonl');
|
|
103
112
|
out.body.own_needs = require('./needs-overdue.js').overdueNeeds(pmItems.fold(pmItems.readLines(file)), iso);
|
|
104
113
|
} catch { out.body.own_needs = []; }
|
|
114
|
+
// additive: a draft a dashboard schedule made in the last 7 days, still in the outbox, is a notice on the bell (lib/report-schedules.js). Nothing was sent.
|
|
115
|
+
try { out.body.notices = require('./report-schedules.js').noticesOf(require('./outbox-store.js').readOutbox(ctx.runtimeDir)); } catch { out.body.notices = []; }
|
|
105
116
|
}
|
|
106
117
|
ctx.json(res, out.body, out.code);
|
|
107
118
|
return true;
|
|
@@ -10,9 +10,10 @@
|
|
|
10
10
|
const fs = require('fs');
|
|
11
11
|
const path = require('path');
|
|
12
12
|
const roadmapOps = require('./routes-roadmap-ops.js');
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const
|
|
13
|
+
const { repoScript } = require('./repo-script.js');
|
|
14
|
+
const records = require(repoScript('records/index.js'));
|
|
15
|
+
const roadmap = require(repoScript('roadmap-ops.js'));
|
|
16
|
+
const breakdown = require(repoScript('breakdown-ops.js'));
|
|
16
17
|
|
|
17
18
|
function readPeople(runtimeDir) {
|
|
18
19
|
try {
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
* Repo facts are not read here (readRepoFacts is synchronous and slow); only two small JSONL files and the existence of named files are. */
|
|
14
14
|
const fs = require('fs');
|
|
15
15
|
const path = require('path');
|
|
16
|
-
const
|
|
16
|
+
const { repoScript } = require('./repo-script.js');
|
|
17
|
+
const records = require(repoScript('records/index.js'));
|
|
17
18
|
|
|
18
19
|
const REPO = path.join(__dirname, '..', '..');
|
|
19
20
|
const DAY = 86400000;
|
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
* and scope, id, today echoed. 400 on a bad scope or a missing id; 404 for an id nothing holds.
|
|
7
7
|
* POST /api/report-dashboards/layout { key, reports } → { ok, key, reports, layouts } reports: null resets the key to its default.
|
|
8
8
|
* 400 on an unknown key or report id; 403 without a page press.
|
|
9
|
+
* POST /api/report-dashboards/schedule { key, plan, audience } → { ok, key, schedule, schedules } plan: none|weekly|monthly; none removes it.
|
|
10
|
+
* 400 on a bad key, plan or audience; 403 without a page press. (lib/report-schedules.js)
|
|
11
|
+
* runDue(ctx, now) the server tick: each due schedule appends ONE draft to the outbox. Nothing is sent.
|
|
9
12
|
*
|
|
10
13
|
* Initiatives come from the workspace's facts (lib/facts-async.js), like routes-calendar-views.js. Key results, bets and hypotheses
|
|
11
14
|
* come from the same records as routes-c3-strategy.js. The handlers are pure over their inputs so a test needs no server.
|
|
@@ -14,24 +17,32 @@ const path = require('path');
|
|
|
14
17
|
const guard = require('./pm-guard.js');
|
|
15
18
|
const strategy = require('./routes-c3-strategy.js');
|
|
16
19
|
const rd = require('./report-dashboards.js');
|
|
20
|
+
const rs = require('./report-schedules.js');
|
|
21
|
+
const RF = require('./report-frame.js');
|
|
22
|
+
const { repoScript } = require('./repo-script.js');
|
|
17
23
|
|
|
18
24
|
const fail = (status, error, extra) => ({ status, body: { ok: false, error, ...(extra || {}) } });
|
|
19
25
|
const pad = (n) => String(n).padStart(2, '0');
|
|
20
26
|
const todayStr = () => { const d = new Date(); return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate()); };
|
|
21
27
|
const cap = (s) => (s ? s.charAt(0).toUpperCase() + s.slice(1) : s);
|
|
22
28
|
|
|
23
|
-
/** boards and initiatives from the facts.
|
|
24
|
-
|
|
29
|
+
/** boards and initiatives from the facts. With `index` (the Initiatives board model, routes-boards.js boardIndex) an
|
|
30
|
+
* initiative sits on the board the Initiatives page shows it on, and a board keeps its name there. Without it a board is
|
|
31
|
+
* boardOf(ini, slug) and its title is its id, capitalised. */
|
|
32
|
+
function catalogue(facts, slug, index) {
|
|
25
33
|
const inis = ((facts && facts.inis) || []).filter((i) => i && i.id);
|
|
26
|
-
const
|
|
34
|
+
const boardOf = (i) => (index ? index.of(String(i.id)) : rd.boardOf(i, slug));
|
|
35
|
+
const initiatives = inis.map((i) => ({ id: String(i.id), title: String(i.title || i.id), board: boardOf(i) }));
|
|
36
|
+
const names = new Map(index ? index.boards.map((b) => [b.id, b.title]) : []);
|
|
27
37
|
const seen = new Map();
|
|
28
|
-
initiatives.forEach((i) => { if (i.board && !seen.has(i.board)) seen.set(i.board, { id: i.board, title: cap(i.board) }); });
|
|
38
|
+
initiatives.forEach((i) => { if (i.board && !seen.has(i.board)) seen.set(i.board, { id: i.board, title: names.get(i.board) || cap(i.board) }); });
|
|
29
39
|
return { boards: [...seen.values()], initiatives };
|
|
30
40
|
}
|
|
31
41
|
|
|
32
|
-
function list({ facts, runtimeDir, slug }) {
|
|
33
|
-
const c = catalogue(facts, slug);
|
|
34
|
-
return { status: 200, body: { ok: true, library: rd.LIBRARY, layouts: rd.readLayouts(runtimeDir), defaults: rd.DEFAULTS, boards: c.boards, initiatives: c.initiatives
|
|
42
|
+
function list({ facts, runtimeDir, slug, index, now }) {
|
|
43
|
+
const c = catalogue(facts, slug, index);
|
|
44
|
+
return { status: 200, body: { ok: true, library: rd.LIBRARY, layouts: rd.readLayouts(runtimeDir), defaults: rd.DEFAULTS, boards: c.boards, initiatives: c.initiatives,
|
|
45
|
+
schedules: rs.viewOf(rs.readSchedules(runtimeDir), now || new Date()), plans: rs.PLANS } };
|
|
35
46
|
}
|
|
36
47
|
|
|
37
48
|
/** query { scope, id }; deps { facts, build() → the c3-strategy body, today, slug, hypotheses }. */
|
|
@@ -41,14 +52,14 @@ function data(query, deps) {
|
|
|
41
52
|
if (scope !== 'portfolio') {
|
|
42
53
|
if (typeof id !== 'string' || !id) return fail(400, 'id is required for the ' + scope + ' scope');
|
|
43
54
|
if (!rd.validId(id)) return fail(400, 'id is not a valid id');
|
|
44
|
-
const c = catalogue(deps.facts, deps.slug);
|
|
55
|
+
const c = catalogue(deps.facts, deps.slug, deps.index);
|
|
45
56
|
const found = scope === 'board' ? c.boards.some((b) => b.id === id) : c.initiatives.some((i) => i.id === id);
|
|
46
57
|
if (!found) return fail(404, 'no ' + scope + ' has the id ' + id);
|
|
47
58
|
}
|
|
48
59
|
const today = deps.today || todayStr();
|
|
49
60
|
try {
|
|
50
61
|
const body = deps.build(today);
|
|
51
|
-
return { status: 200, body: rd.scopeFilter(body, deps.facts, scope, id || null, today, { slug: deps.slug, hypotheses: deps.hypotheses }) };
|
|
62
|
+
return { status: 200, body: rd.scopeFilter(body, deps.facts, scope, id || null, today, { slug: deps.slug, hypotheses: deps.hypotheses, boardOf: deps.index ? (i) => deps.index.of(String(i.id)) : undefined }) };
|
|
52
63
|
} catch (e) { return fail(500, String((e && e.message) || e)); }
|
|
53
64
|
}
|
|
54
65
|
|
|
@@ -62,6 +73,70 @@ function layout(req, body, runtimeDir) {
|
|
|
62
73
|
return { status: 200, body: { ok: true, key: body.key, reports: r.layouts[body.key] || null, layouts: r.layouts } };
|
|
63
74
|
}
|
|
64
75
|
|
|
76
|
+
function schedule(req, body, runtimeDir, now = new Date()) {
|
|
77
|
+
const g = guard.requirePagePress(req, body);
|
|
78
|
+
if (!g.ok) return fail(g.status, g.error);
|
|
79
|
+
const r = rs.saveSchedule(runtimeDir, { key: body.key, plan: body.plan, audience: body.audience, ws: body.ws == null || body.ws === '' ? null : body.ws }, now);
|
|
80
|
+
if (!r.ok) return fail(/could not be saved|no runtime/.test(r.error) ? 500 : 400, r.error);
|
|
81
|
+
const view = rs.viewOf(r.schedules, now);
|
|
82
|
+
return { status: 200, body: { ok: true, key: body.key, schedule: view[body.key] || null, schedules: view } };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* The dashboard's title as the page names it (c3-reports.js dashTitle): Portfolio, Board: <title>, Initiative: <title>. */
|
|
86
|
+
function titleOf(key, c) {
|
|
87
|
+
if (key === 'portfolio') return 'Portfolio';
|
|
88
|
+
const i = key.indexOf(':'); const scope = key.slice(0, i); const id = key.slice(i + 1);
|
|
89
|
+
const x = (scope === 'board' ? c.boards : c.initiatives).find((b) => b.id === id);
|
|
90
|
+
return (scope === 'board' ? 'Board: ' : 'Initiative: ') + (x ? x.title || x.id : id);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Run one schedule: the dashboard's data for its scope, its current layout (or the scope's default), the frame and text the Share sheet
|
|
95
|
+
* makes, then ONE outbox draft. deps { facts, slug, build(today), hypotheses, runtimeDir, today }. Returns { ok, entry } | { ok:false, error }.
|
|
96
|
+
*/
|
|
97
|
+
function runOne(sched, deps, now = new Date()) {
|
|
98
|
+
const key = sched.key;
|
|
99
|
+
const scope = key === 'portfolio' ? 'portfolio' : key.slice(0, key.indexOf(':'));
|
|
100
|
+
const id = scope === 'portfolio' ? null : key.slice(key.indexOf(':') + 1);
|
|
101
|
+
const r = data({ scope, id }, deps);
|
|
102
|
+
if (r.status !== 200) return { ok: false, error: r.body.error || 'the dashboard could not be read' };
|
|
103
|
+
const layouts = rd.readLayouts(deps.runtimeDir);
|
|
104
|
+
const ids = Object.prototype.hasOwnProperty.call(layouts, key) ? layouts[key] : rd.DEFAULTS[scope];
|
|
105
|
+
const reports = ids.map((x) => rd.LIBRARY.find((l) => l.id === x)).filter(Boolean);
|
|
106
|
+
const c = catalogue(deps.facts, deps.slug, deps.index);
|
|
107
|
+
const F = RF.frameOf({ title: titleOf(key, c), reports, raw: r.body, audience: sched.audience, today: r.body.today });
|
|
108
|
+
try { return { ok: true, entry: rs.makeDraft(deps.runtimeDir, sched, F, RF.draftBody(F), now) }; }
|
|
109
|
+
catch (e) { return { ok: false, error: 'the draft could not be saved: ' + String((e && e.message) || e) }; }
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** The tick. lastRun moves first, so a slow read never runs the same slot twice; the outcome is written after. */
|
|
113
|
+
let running = false;
|
|
114
|
+
async function runDue(ctx, now = new Date()) {
|
|
115
|
+
if (running || !ctx || !ctx.runtimeDir) return [];
|
|
116
|
+
running = true;
|
|
117
|
+
const done = [];
|
|
118
|
+
try {
|
|
119
|
+
for (const s of rs.dueOf(rs.readSchedules(ctx.runtimeDir), now)) {
|
|
120
|
+
rs.markRun(ctx.runtimeDir, s.key, { lastRun: now.toISOString() });
|
|
121
|
+
let out;
|
|
122
|
+
try {
|
|
123
|
+
const w = ctx.getWs(s.ws || null);
|
|
124
|
+
if (!w) throw new Error('no workspace is registered');
|
|
125
|
+
const slug = w.id || (w.root ? path.basename(path.resolve(w.root)) : null);
|
|
126
|
+
const facts = await (ctx.readFacts || readFacts)(w);
|
|
127
|
+
const root = rootOf(ctx);
|
|
128
|
+
let hypotheses = [];
|
|
129
|
+
try { hypotheses = require(repoScript('records/index.js')).list(root, 'hypotheses'); } catch { hypotheses = []; }
|
|
130
|
+
out = runOne(s, { facts, slug, hypotheses, runtimeDir: ctx.runtimeDir, today: ctx.today,
|
|
131
|
+
build: ctx.build || ((today) => strategy.build(root, path.join(ctx.runtimeDir, 'signals', 'signals.jsonl'), today)) }, now);
|
|
132
|
+
} catch (e) { out = { ok: false, error: String((e && e.message) || e) }; }
|
|
133
|
+
rs.markRun(ctx.runtimeDir, s.key, out.ok ? { last_status: 'ok', last_error: null, last_draft: out.entry.id } : { last_status: 'failed', last_error: out.error });
|
|
134
|
+
done.push({ key: s.key, ...out });
|
|
135
|
+
}
|
|
136
|
+
} finally { running = false; }
|
|
137
|
+
return done;
|
|
138
|
+
}
|
|
139
|
+
|
|
65
140
|
const rootOf = (ctx) => (ctx && ctx.recordsDir) || path.join((ctx && ctx.repoRoot) || path.join(__dirname, '..', '..'), 'planning', 'records');
|
|
66
141
|
|
|
67
142
|
async function readFacts(w) {
|
|
@@ -70,7 +145,7 @@ async function readFacts(w) {
|
|
|
70
145
|
|
|
71
146
|
module.exports = {
|
|
72
147
|
prefixes: ['/api/report-dashboards'],
|
|
73
|
-
catalogue, list, data, layout,
|
|
148
|
+
catalogue, list, data, layout, schedule, runOne, runDue,
|
|
74
149
|
handle: async (req, res, url, ctx) => {
|
|
75
150
|
const p = url.pathname;
|
|
76
151
|
const send = (r) => { ctx.json(res, r.body, r.status); return true; };
|
|
@@ -88,12 +163,14 @@ module.exports = {
|
|
|
88
163
|
let facts;
|
|
89
164
|
try { facts = await readFacts(w); }
|
|
90
165
|
catch (e) { return send(fail(500, 'the dashboards could not read the repository: ' + (e && e.message ? e.message : String(e)))); }
|
|
91
|
-
|
|
166
|
+
let index = null; // the Initiatives board model; without it (no module, or a read error) boardOf decides
|
|
167
|
+
try { index = require('./routes-boards.js').boardIndex(ctx, w); } catch { index = null; }
|
|
168
|
+
if (p === '/api/report-dashboards') return send(list({ facts, runtimeDir: ctx.runtimeDir, slug, index }));
|
|
92
169
|
const root = rootOf(ctx);
|
|
93
170
|
let hypotheses = [];
|
|
94
|
-
try { hypotheses = require('
|
|
171
|
+
try { hypotheses = require(repoScript('records/index.js')).list(root, 'hypotheses'); } catch { hypotheses = []; }
|
|
95
172
|
return send(data({ scope: url.searchParams.get('scope'), id: url.searchParams.get('id') }, {
|
|
96
|
-
facts, slug, hypotheses,
|
|
173
|
+
facts, slug, hypotheses, index,
|
|
97
174
|
build: (today) => strategy.build(root, path.join(ctx.runtimeDir || '.', 'signals', 'signals.jsonl'), today),
|
|
98
175
|
}));
|
|
99
176
|
}
|
|
@@ -103,6 +180,12 @@ module.exports = {
|
|
|
103
180
|
if (!got.ok) return send(fail(400, 'invalid JSON body'));
|
|
104
181
|
return send(layout(req, got.body || {}, ctx.runtimeDir));
|
|
105
182
|
}
|
|
183
|
+
if (p === '/api/report-dashboards/schedule') {
|
|
184
|
+
if (req.method !== 'POST') return send(fail(405, 'POST only'));
|
|
185
|
+
const got = await ctx.readJson(req);
|
|
186
|
+
if (!got.ok) return send(fail(400, 'invalid JSON body'));
|
|
187
|
+
return send(schedule(req, got.body || {}, ctx.runtimeDir));
|
|
188
|
+
}
|
|
106
189
|
return false;
|
|
107
190
|
},
|
|
108
191
|
};
|
|
@@ -17,9 +17,10 @@
|
|
|
17
17
|
* reader is used, so the route never starts a cold repository read. A number that no record holds is null, never invented. */
|
|
18
18
|
const path = require('path');
|
|
19
19
|
const fs = require('fs');
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
20
|
+
const { repoScript } = require('./repo-script.js');
|
|
21
|
+
const records = require(repoScript('records/index.js'));
|
|
22
|
+
const sigRules = require(repoScript('signal-rules.js'));
|
|
23
|
+
const ledger = require(repoScript('trust/ledger.js'));
|
|
23
24
|
|
|
24
25
|
const EARLY = 0.10; // the repository's early-warning share (scripts/calendar-model.js EARLY_WARNING)
|
|
25
26
|
const OFF = 0.50; // behind the line by half the span or more reads as off course
|
|
@@ -23,9 +23,10 @@
|
|
|
23
23
|
*/
|
|
24
24
|
const path = require('path');
|
|
25
25
|
const planItems = require('./plan-items.js');
|
|
26
|
-
const
|
|
26
|
+
const { repoScript } = require('./repo-script.js');
|
|
27
|
+
const F = require(repoScript('plan-forecast.js'));
|
|
27
28
|
const roadmapOps = require('./routes-roadmap-ops.js');
|
|
28
|
-
const breakdown = require(
|
|
29
|
+
const breakdown = require(repoScript('breakdown-ops.js'));
|
|
29
30
|
|
|
30
31
|
const localYmd = (d) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
|
31
32
|
const DAY = 86400000;
|
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
* File: <runtime>/calendar-import/events.jsonl (append only, scripts/trust/ledger.js). */
|
|
12
12
|
const path = require('path');
|
|
13
13
|
const guard = require('./pm-guard.js');
|
|
14
|
-
const
|
|
15
|
-
const
|
|
14
|
+
const { repoScript } = require('./repo-script.js');
|
|
15
|
+
const CI = require(repoScript('calendar-import.js'));
|
|
16
|
+
const L = require(repoScript('trust/ledger.js'));
|
|
16
17
|
|
|
17
18
|
const fileOf = (runtimeDir) => path.join(runtimeDir, 'calendar-import', 'events.jsonl');
|
|
18
19
|
const fail = (status, error) => ({ status, body: { ok: false, error } });
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
/* routes-calendar-views.js — GET /api/calendar-views?view=day|week|month|quarter|year&date=YYYY-MM-DD&ws=<id> (console3 wave C2).
|
|
3
3
|
*
|
|
4
4
|
* → { ok, view, range, cells, unit, gantt, strategy, events_source, today,
|
|
5
|
-
* layers, layers_total, layers_note, free, context, context_total
|
|
5
|
+
* layers, layers_total, layers_note, free, context, context_total, (lib/calendar-layers.js)
|
|
6
|
+
* tidy, tidy_total, tidy_note } (lib/calendar-tidy.js: suggestions in words, no write)
|
|
6
7
|
*
|
|
7
8
|
* READ ONLY. Initiatives come from the signal engine's repo reader (scripts/signals/facts.js readRepoFacts), required inside
|
|
8
9
|
* the handler so a failure answers 500 { ok:false } and never reaches the server. The date and the plan come from the records:
|
|
@@ -13,8 +14,10 @@
|
|
|
13
14
|
* Until one is, events = [] and events_source is 'none'. KRS: no KR metric series is stored in the repo, so the strategy lens
|
|
14
15
|
* gets none and says so. */
|
|
15
16
|
const path = require('path');
|
|
16
|
-
const
|
|
17
|
+
const { repoScript } = require('./repo-script.js');
|
|
18
|
+
const model = require(repoScript('calendar-model.js'));
|
|
17
19
|
const layersLib = require('./calendar-layers.js');
|
|
20
|
+
const tidyLib = require('./calendar-tidy.js');
|
|
18
21
|
|
|
19
22
|
const today = () => { const d = new Date(); const p = (n) => String(n).padStart(2, '0'); return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`; };
|
|
20
23
|
|
|
@@ -44,7 +47,9 @@ function handle(query, deps = {}) {
|
|
|
44
47
|
const src = typeof deps.readContextSources === 'function' ? (deps.readContextSources() || {}) : {};
|
|
45
48
|
const nowMs = Number.isFinite(deps.nowMs) ? deps.nowMs : (deps.today ? undefined : Date.now());
|
|
46
49
|
const extra = layersLib.build({ range, today: nowDay, nowMs, events, dated, src, own: items.own, planItemsDue: items.planItems });
|
|
47
|
-
|
|
50
|
+
const tidy = tidyLib.tidyFrom({ range, today: nowDay, nowMs, events, eventsSource: source, inis, gantt,
|
|
51
|
+
planItems: dated.planItems || items.planItems || [] });
|
|
52
|
+
return { status: 200, body: { ok: true, view, range, unit: b.unit, cells: b.cells, gantt, strategy, events_source: source, today: nowDay, ...extra, ...tidy } };
|
|
48
53
|
} catch (e) {
|
|
49
54
|
return { status: 500, body: { ok: false, error: String(e && e.message || e) } };
|
|
50
55
|
}
|
|
@@ -70,7 +75,7 @@ function readers(root, runtimeDir) {
|
|
|
70
75
|
const out = { unavailable };
|
|
71
76
|
try { out.planItems = planRows().map(planItem); } catch (e) { unavailable.plan_items = 'the plan ledger could not be read: ' + reason(e); }
|
|
72
77
|
try {
|
|
73
|
-
const R = require('
|
|
78
|
+
const R = require(repoScript('releases.js'));
|
|
74
79
|
const f = path.join(runtimeDir, 'releases', 'releases.jsonl');
|
|
75
80
|
let lines = []; try { lines = require('fs').readFileSync(f, 'utf8').split('\n').filter(Boolean); } catch { lines = []; }
|
|
76
81
|
out.releases = R.foldReleases(lines);
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
const fs = require('fs');
|
|
13
13
|
const path = require('path');
|
|
14
14
|
const { spawnSync } = require('child_process');
|
|
15
|
-
const
|
|
15
|
+
const { repoScript } = require('./repo-script.js');
|
|
16
|
+
const H = require(repoScript('doc-health.js'));
|
|
16
17
|
|
|
17
18
|
const ROOT = path.resolve(__dirname, '..', '..');
|
|
18
19
|
const bad = (error, status = 400) => ({ status, body: { ok: false, error } });
|
|
@@ -19,7 +19,8 @@ const fs = require('fs');
|
|
|
19
19
|
const path = require('path');
|
|
20
20
|
const guard = require('./pm-guard.js');
|
|
21
21
|
const applyChange = require('./apply-change.js');
|
|
22
|
-
const
|
|
22
|
+
const { repoScript } = require('./repo-script.js');
|
|
23
|
+
const S = require(repoScript('doc-sheet.js'));
|
|
23
24
|
|
|
24
25
|
const ROOT = path.resolve(__dirname, '..', '..');
|
|
25
26
|
const fail = (status, error, extra) => ({ status, body: { ok: false, error, ...(extra || {}) } });
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
const fs = require('fs');
|
|
16
16
|
const path = require('path');
|
|
17
17
|
const planItems = require('./plan-items.js');
|
|
18
|
-
const
|
|
18
|
+
const { repoScript } = require('./repo-script.js');
|
|
19
|
+
const F = require(repoScript('plan-forecast.js'));
|
|
19
20
|
|
|
20
21
|
const DEFAULT_PPW = 5;
|
|
21
22
|
const localYmd = (d) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
|
@@ -14,8 +14,9 @@ const fs = require('fs');
|
|
|
14
14
|
const path = require('path');
|
|
15
15
|
const actor = require('./actor.js');
|
|
16
16
|
const runAnswers = require('./run-answers.js');
|
|
17
|
-
const
|
|
18
|
-
const
|
|
17
|
+
const { repoScript } = require('./repo-script.js');
|
|
18
|
+
const C = require(repoScript('reply-contract/reply-contract.js'));
|
|
19
|
+
const R = require(repoScript('replies.js'));
|
|
19
20
|
|
|
20
21
|
const EVENTS = ['SessionStart', 'PreToolUse', 'PermissionRequest', 'Stop', 'Notification', 'SessionEnd'];
|
|
21
22
|
const ALIASES = { 'session-start': 'SessionStart', 'pre-tool': 'PreToolUse', 'permission-request': 'PermissionRequest', stop: 'Stop', notification: 'Notification', 'session-end': 'SessionEnd' };
|
|
@@ -57,7 +57,8 @@ const tidy = require('./tidy-documents.js');
|
|
|
57
57
|
const jevDocs = require('./jev-documents.js');
|
|
58
58
|
const tsSettings = require('./typesafe-settings');
|
|
59
59
|
const docCatCorrections = require('./doc-category-corrections');
|
|
60
|
-
const {
|
|
60
|
+
const { repoScript } = require('./repo-script.js');
|
|
61
|
+
const { nineStages } = require(repoScript('nine-stages.js')); // pure label layer; never workflow-state.js (it runs its CLI on require)
|
|
61
62
|
|
|
62
63
|
const HORIZON_RANK = { now: 0, next: 1, later: 2 };
|
|
63
64
|
const FILE_KEYS = [['brief_path', 'brief', 'Brief'], ['prd_path', 'prd', 'PRD'], ['rubric_path', 'rubric', 'Rubric'], ['doc_path', 'doc', 'Document']];
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* Drafts only. Creating the initiative stays with createInitiative, which refuses an unanchored create. */
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const guard = require('./pm-guard.js');
|
|
7
|
-
const
|
|
7
|
+
const { repoScript } = require('./repo-script.js');
|
|
8
|
+
const intake = require(repoScript('intake.js'));
|
|
8
9
|
|
|
9
10
|
const ROOT = path.resolve(__dirname, '..', '..');
|
|
10
11
|
|