create-pmos 0.66.0 → 0.67.1
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/guide/layout.md +1 -1
- package/workspace/lib/sync.js +32 -4
- package/workspace/package-lock.json +1 -1
- package/workspace/package.json +1 -1
- package/workspace/run-tests.js +39 -2
- package/workspace/test-timings.json +172 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-pmos",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.67.1",
|
|
4
4
|
"description": "Scaffold the PMOS portable kit — run the PMOS product-management workflow (initiative → lane-fit spec → contract → build → three gates, with work-type lanes for features, research, maintenance, incidents, and content) entirely inside your own repo, with all state as git-versioned files. Includes `workflow-sweep`, which audits the state every board derives from and separates real defects from work you simply have not done. `create-pmos workspace` also installs + launches the local Terminal Workspace GUI. No database, no network, no telemetry.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
package/payload/KIT-VERSION
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
type: Reference
|
|
3
3
|
title: "Eval calibration log"
|
|
4
4
|
description: "Append-only record of every PM override of an evaluator verdict."
|
|
5
|
-
generated: {by: process:create-pmos, at: "2026-10-
|
|
5
|
+
generated: {by: process:create-pmos, at: "2026-10-07T02:28:54Z"}
|
|
6
6
|
status: stable
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
type: Reference
|
|
3
3
|
title: "Health budgets"
|
|
4
4
|
description: "Closed registry of health-budget anchors (D59), edited only by the PM."
|
|
5
|
-
generated: {by: process:create-pmos, at: "2026-10-
|
|
5
|
+
generated: {by: process:create-pmos, at: "2026-10-07T02:28:54Z"}
|
|
6
6
|
status: stable
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
type: Reference
|
|
3
3
|
title: "Discoveries and friction log"
|
|
4
4
|
description: "Append-only record of what runs discovered and where the process rubbed."
|
|
5
|
-
generated: {by: process:create-pmos, at: "2026-10-
|
|
5
|
+
generated: {by: process:create-pmos, at: "2026-10-07T02:28:54Z"}
|
|
6
6
|
status: stable
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -17,7 +17,7 @@ The top bar has these parts, from left to right:
|
|
|
17
17
|
- **Branches and sessions** is in ⌘K. It opens a sheet with every branch of the repository (main first) and how many sessions run in each. Press a branch to see its sessions, open one, end one, or start a session there. **+ branch** makes a branch, and **+ session** starts one with a branch, an agent and a profile. With All repositories, the sheet lists every repository.
|
|
18
18
|
- **Agenda, Initiatives, Board, Reports, Docs and People** are the six places. Press one to show it. The Agenda count shows how many items need you. Docs shows whether each document is the same as its Google Docs and Confluence copy. People shows the people you work with in the repository ([People](people.md)).
|
|
19
19
|
- **Search or capture ⌘K** opens the command palette. Type to find an initiative, a repository, an open tab or a command.
|
|
20
|
-
- **Sync** shows only when the current repository is not in sync with its remote. Press it to fetch, bring in the work of the other machine, record your changes and push. If the repository has not fetched in the last 10 minutes, Sync also shows, because a push from another machine is not visible until a fetch. When the repository fetched recently and is in sync, Sync is not shown. If Sync stops, the message names the step that stopped.
|
|
20
|
+
- **Sync** shows only when the current repository is not in sync with its remote. Press it to fetch, bring in the work of the other machine, record your changes and push. If the repository has not fetched in the last 10 minutes, Sync also shows, because a push from another machine is not visible until a fetch. When the repository fetched recently and is in sync, Sync is not shown. When two machines add lines to the same ledger (a `.jsonl` file under `pmos/` or `planning/`), Sync keeps the lines from both machines. If Sync stops, the message names the step that stopped. If both machines changed the same lines of another file, the message names the file. Keep the version you want in that file on one machine, sync it, then sync the other machine.
|
|
21
21
|
- **Sync on its own.** If you forget to press Sync, the workspace syncs for you. It syncs each repository once when the workspace starts. It also syncs a repository that has records not yet pushed when no record changed for 5 minutes. In a document repository it syncs every changed file on any branch. In a code repository it syncs only on the default branch (for example `main`), and only when every commit not yet pushed changes records and no code. If you close the tab while records are not yet pushed, the browser asks you first. To turn automatic sync off, start the workspace with `PMOS_AUTO_SYNC=0`.
|
|
22
22
|
- **Settings** opens the settings of the workspace.
|
|
23
23
|
|
package/workspace/lib/sync.js
CHANGED
|
@@ -54,6 +54,26 @@ const isRecord = (rel) => RECORD_PATHS.some((p) => rel === p || rel.startsWith(`
|
|
|
54
54
|
// PM repositories append ledgers from several machines; `merge=union` keeps both sides' lines instead
|
|
55
55
|
// of conflicting (D70). Added once, committed with the records. Never touches a product-code repository.
|
|
56
56
|
const UNION_LINE = '*.jsonl merge=union';
|
|
57
|
+
|
|
58
|
+
// The same rule, given to the replay itself rather than read from the repository. A committed `.gitattributes` holds
|
|
59
|
+
// only for a PM-profile repository, and only once it is already on the remote: a rebase reads the attributes of the
|
|
60
|
+
// tree it replays ONTO, so a union line arriving in the very commit being replayed does not apply to it. A code
|
|
61
|
+
// repository never carries the line at all, so two machines appending pmos/state/runs.jsonl stopped Sync at
|
|
62
|
+
// integrate every time. `core.attributesFile` is the lowest-precedence attribute source, so a repository's own
|
|
63
|
+
// `.gitattributes` still wins; it is set for this one rebase and written to no tracked file.
|
|
64
|
+
// A code repository unions its record ledgers only; a document repository every ledger.
|
|
65
|
+
function unionAttributesFor(root) {
|
|
66
|
+
const lines = profileOf(root) === 'pm-artifacts' ? [UNION_LINE]
|
|
67
|
+
: RECORD_PATHS.filter((p) => !p.startsWith('.')).map((p) => `${p}/**/*.jsonl merge=union`);
|
|
68
|
+
const f = path.join(os.tmpdir(), `pmos-sync-attributes-${profileOf(root)}`);
|
|
69
|
+
const text = `${lines.join('\n')}\n`;
|
|
70
|
+
try {
|
|
71
|
+
// written only when it differs, so a second repository's sync never reads it half-written
|
|
72
|
+
if ((fs.existsSync(f) ? fs.readFileSync(f, 'utf8') : '') !== text) fs.writeFileSync(f, text);
|
|
73
|
+
return f;
|
|
74
|
+
} catch { return null; }
|
|
75
|
+
}
|
|
76
|
+
|
|
57
77
|
function ensureUnionAttribute(root) {
|
|
58
78
|
try {
|
|
59
79
|
const prof = fs.readFileSync(path.join(root, '.pmos-profile'), 'utf8').split('\n').map((l) => l.replace(/#.*$/, '').trim()).find(Boolean);
|
|
@@ -136,11 +156,19 @@ async function sync(root, { label } = {}) {
|
|
|
136
156
|
const s2 = await status(root);
|
|
137
157
|
if (s2.behind) {
|
|
138
158
|
// Fast-forward when we have nothing of our own; otherwise replay OUR unpushed commits on top.
|
|
139
|
-
const
|
|
159
|
+
const attrs = s2.ahead ? unionAttributesFor(root) : null;
|
|
160
|
+
const verb = s2.ahead ? [...(attrs ? ['-c', `core.attributesFile=${attrs}`] : []), 'rebase', '--autostash', s2.upstream]
|
|
161
|
+
: ['merge', '--ff-only', s2.upstream];
|
|
140
162
|
const r = await run(root, verb);
|
|
141
163
|
if (!r.ok) {
|
|
142
|
-
if (s2.ahead)
|
|
143
|
-
|
|
164
|
+
if (!s2.ahead) return stop('integrate', `cannot fast-forward — ${r.err.split('\n')[0] || 'see git'}`);
|
|
165
|
+
// Name the files before the abort clears them: the PM has to open these, and "the same lines" alone says not where.
|
|
166
|
+
const u = await run(root, ['diff', '--name-only', '--diff-filter=U']);
|
|
167
|
+
const files = u.ok && u.out ? u.out.split('\n').filter(Boolean) : [];
|
|
168
|
+
await run(root, ['rebase', '--abort']);
|
|
169
|
+
return stop('integrate', files.length
|
|
170
|
+
? `both machines changed ${files.join(', ')} — rebase aborted, nothing changed; keep the version you want in each file on one machine, sync it, then sync the other`
|
|
171
|
+
: `the two machines changed the same lines — rebase aborted, nothing changed — ${r.err.split('\n')[0] || 'see git'}`);
|
|
144
172
|
}
|
|
145
173
|
done('integrate', s2.ahead ? `replayed ${s2.ahead} local commit(s) on the remote` : `fast-forwarded ${s2.behind} commit(s)`);
|
|
146
174
|
} else done('integrate', 'nothing to bring in');
|
|
@@ -183,5 +211,5 @@ async function defaultBranchOf(root, remote) {
|
|
|
183
211
|
return null;
|
|
184
212
|
}
|
|
185
213
|
|
|
186
|
-
module.exports = { status, sync, ensureUnionAttribute, RECORD_PATHS, isRecord, REMOTE_FRESH_MS,
|
|
214
|
+
module.exports = { status, sync, ensureUnionAttribute, unionAttributesFor, RECORD_PATHS, isRecord, REMOTE_FRESH_MS,
|
|
187
215
|
unpushedPaths, newestDirtyRecordMs, defaultBranchOf, profileOf };
|
package/workspace/package.json
CHANGED
package/workspace/run-tests.js
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
/* run-tests.js — run the workspace suites side by side.
|
|
4
4
|
*
|
|
5
|
-
* node run-tests.js <group> [--jobs=N] [--shard=I/N] [--changed[=REF]] [--list] [--verbose]
|
|
5
|
+
* node run-tests.js <group> [--jobs=N] [--shard=I/N] [--changed[=REF]] [--timings-out=FILE] [--list] [--verbose]
|
|
6
6
|
* node run-tests.js --check
|
|
7
|
+
* node run-tests.js --merge-timings=DIR
|
|
7
8
|
*
|
|
8
9
|
* Groups come from test-files.json: unit (test.js + modules), modules, panels, ui, browser
|
|
9
10
|
* (panels + ui), all. The npm scripts call this file, so `npm test` and CI run the same lists.
|
|
@@ -31,6 +32,14 @@
|
|
|
31
32
|
* test-files.json, plus `helpers` (a -test.js file that is a helper, not a suite, with the reason, as
|
|
32
33
|
* in ELSEWHERE). This file merges every fragment into the lists before it does anything else, so
|
|
33
34
|
* --check, --shard and every group see one list. A fragment that is not valid fails every command.
|
|
35
|
+
*
|
|
36
|
+
* Timings. --shard balances the shards by each suite's time, and the shards only finish together when
|
|
37
|
+
* those times are the CI runner's. test-timings.json holds times measured on CI; the `seconds` keys in
|
|
38
|
+
* test-files.json and the fragments are the fallback for a suite it does not name yet, and a suite in
|
|
39
|
+
* neither counts as 10. The `seconds` numbers were measured on a 4-CPU sandbox and were off by up to
|
|
40
|
+
* 4x on the 2-CPU runners, which left one shard running 280s while two others finished in 130s.
|
|
41
|
+
* Every CI job writes its times with --timings-out and uploads them; --merge-timings=DIR folds a
|
|
42
|
+
* downloaded set into test-timings.json. A stale time never skips a suite: it only moves it.
|
|
34
43
|
*/
|
|
35
44
|
const fs = require('fs');
|
|
36
45
|
const os = require('os');
|
|
@@ -98,7 +107,10 @@ const args = process.argv.slice(2);
|
|
|
98
107
|
const flag = (name) => { const a = args.find((x) => x === `--${name}` || x.startsWith(`--${name}=`)); return a === undefined ? undefined : (a.includes('=') ? a.slice(a.indexOf('=') + 1) : true); };
|
|
99
108
|
const group = args.find((a) => !a.startsWith('--'));
|
|
100
109
|
|
|
101
|
-
const
|
|
110
|
+
const TIMINGS_FILE = path.join(DIR, 'test-timings.json');
|
|
111
|
+
let TIMINGS = {};
|
|
112
|
+
try { TIMINGS = JSON.parse(fs.readFileSync(TIMINGS_FILE, 'utf8')).seconds || {}; } catch { /* no CI timings yet: the seconds keys decide */ }
|
|
113
|
+
const secs = (f) => Number(TIMINGS[f]) || Number((FILES.seconds || {})[f]) || 10;
|
|
102
114
|
// Slowest first, so a long suite never starts last and holds the run open on its own.
|
|
103
115
|
const bySlowest = (list) => list.map((f, k) => ({ f, k })).sort((a, b) => secs(b.f) - secs(a.f) || a.k - b.k).map((x) => x.f);
|
|
104
116
|
|
|
@@ -155,6 +167,7 @@ function changedSuites(list, ref) {
|
|
|
155
167
|
for (const f of files) {
|
|
156
168
|
if (source.has(f)) { picked.add(f); continue; }
|
|
157
169
|
if (/^(guide|docs)\/|\.md$/.test(f)) continue; // prose: no suite asserts on it except guide.test.js, a unit suite
|
|
170
|
+
if (f === 'test-timings.json') continue; // run order only: no suite reads it
|
|
158
171
|
const stem = path.basename(f).replace(/\.[^.]+$/, '');
|
|
159
172
|
const key = stem.replace(/^(panel|view|tab)-/, '');
|
|
160
173
|
const hits = list.filter((s) => source.get(s).includes(stem) || s.includes(`-${key}-`) || s.includes(`-${key}.`));
|
|
@@ -207,8 +220,30 @@ function runOne(file, verbose) {
|
|
|
207
220
|
});
|
|
208
221
|
}
|
|
209
222
|
|
|
223
|
+
// Fold the --timings-out files a CI run uploaded (one per job, in DIR) into test-timings.json. A suite
|
|
224
|
+
// the run did not reach keeps its old time; a time under one second is recorded as one.
|
|
225
|
+
function mergeTimings(dir) {
|
|
226
|
+
const old = fs.existsSync(TIMINGS_FILE) ? JSON.parse(fs.readFileSync(TIMINGS_FILE, 'utf8')) : {};
|
|
227
|
+
const seconds = { ...(old.seconds || {}) };
|
|
228
|
+
let n = 0;
|
|
229
|
+
for (const name of fs.readdirSync(dir, { recursive: true }).filter((x) => String(x).endsWith('.json'))) {
|
|
230
|
+
for (const [f, v] of Object.entries(JSON.parse(fs.readFileSync(path.join(dir, String(name)), 'utf8')))) {
|
|
231
|
+
if (typeof v === 'number' && GROUPS.all.includes(f)) { seconds[f] = Math.max(1, Math.round(v)); n++; }
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const sorted = Object.fromEntries(Object.keys(seconds).filter((f) => GROUPS.all.includes(f)).sort().map((f) => [f, seconds[f]]));
|
|
235
|
+
const out = {
|
|
236
|
+
_comment: old._comment || 'Wall time of each suite on the Workspace CI runners, in seconds. run-tests.js --shard balances the shards with these numbers. Refresh: download the timings-* artifacts of a green Workspace CI run into one directory, then run `node run-tests.js --merge-timings=DIR`.',
|
|
237
|
+
measured: new Date().toISOString().slice(0, 10),
|
|
238
|
+
seconds: sorted,
|
|
239
|
+
};
|
|
240
|
+
fs.writeFileSync(TIMINGS_FILE, `${JSON.stringify(out, null, 2)}\n`);
|
|
241
|
+
console.log(`run-tests: ${n} times merged into test-timings.json (${Object.keys(sorted).length} suites).`);
|
|
242
|
+
}
|
|
243
|
+
|
|
210
244
|
async function main() {
|
|
211
245
|
if (flag('check')) return check();
|
|
246
|
+
if (flag('merge-timings')) return mergeTimings(flag('merge-timings'));
|
|
212
247
|
if (fragProblems.length) { for (const p of fragProblems) console.error(`✗ ${p}`); process.exitCode = 2; return; }
|
|
213
248
|
if (!group || !GROUPS[group]) {
|
|
214
249
|
console.error(`usage: node run-tests.js <${Object.keys(GROUPS).join('|')}> [--jobs=N] [--shard=I/N] [--list] [--verbose]\n node run-tests.js --check`);
|
|
@@ -250,6 +285,8 @@ async function main() {
|
|
|
250
285
|
|
|
251
286
|
const failed = results.filter((r) => !r.ok);
|
|
252
287
|
const slowest = [...results].sort((a, b) => b.secs - a.secs).slice(0, 5).map((r) => `${r.file} ${r.secs}s`).join(', ');
|
|
288
|
+
const timingsOut = flag('timings-out');
|
|
289
|
+
if (timingsOut && timingsOut !== true) fs.writeFileSync(timingsOut, JSON.stringify(Object.fromEntries(results.map((r) => [r.file, r.secs])), null, 2));
|
|
253
290
|
console.log(`\nrun-tests: ${results.length - failed.length}/${results.length} suites passed in ${((Date.now() - t0) / 1000).toFixed(1)}s wall. Slowest: ${slowest}.`);
|
|
254
291
|
// exitCode, never process.exit(): stdout to a pipe is asynchronous, and exiting here cut the CI log
|
|
255
292
|
// off mid-suite, before the summary that names what failed.
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "Wall time of each suite on the Workspace CI runners, in seconds. run-tests.js --shard balances the shards with these numbers. Refresh: download the timings-* artifacts of a green Workspace CI run into one directory, then run `node run-tests.js --merge-timings=DIR`.",
|
|
3
|
+
"measured": "2026-10-07",
|
|
4
|
+
"seconds": {
|
|
5
|
+
"agenda.test.js": 1,
|
|
6
|
+
"auto-sync.test.js": 2,
|
|
7
|
+
"board-cli.test.js": 3,
|
|
8
|
+
"capture.test.js": 1,
|
|
9
|
+
"claims.test.js": 2,
|
|
10
|
+
"cuts.test.js": 1,
|
|
11
|
+
"d86-seams.test.js": 1,
|
|
12
|
+
"day-run.test.js": 21,
|
|
13
|
+
"doc-category-corrections.test.js": 1,
|
|
14
|
+
"doc-category.test.js": 1,
|
|
15
|
+
"doc-library.test.js": 1,
|
|
16
|
+
"doc-sync.test.js": 1,
|
|
17
|
+
"docs-cli.test.js": 5,
|
|
18
|
+
"external-linking.test.js": 1,
|
|
19
|
+
"factory-join.test.js": 1,
|
|
20
|
+
"first-paint-board.test.js": 8,
|
|
21
|
+
"first-paint-count.test.js": 23,
|
|
22
|
+
"first-paint-initiatives.test.js": 12,
|
|
23
|
+
"first-paint-reports.test.js": 8,
|
|
24
|
+
"first-paint-today.test.js": 26,
|
|
25
|
+
"fixture-parity.test.mjs": 1,
|
|
26
|
+
"focus.test.js": 1,
|
|
27
|
+
"glossary.test.js": 1,
|
|
28
|
+
"goals.test.js": 1,
|
|
29
|
+
"grant-mint.test.js": 1,
|
|
30
|
+
"guide.test.js": 1,
|
|
31
|
+
"handoff.test.js": 1,
|
|
32
|
+
"health.test.js": 1,
|
|
33
|
+
"initiative-cli.test.js": 8,
|
|
34
|
+
"initiative-needs.test.js": 2,
|
|
35
|
+
"initiative-surface.test.js": 3,
|
|
36
|
+
"initiative-writer.test.js": 1,
|
|
37
|
+
"issues.test.js": 1,
|
|
38
|
+
"item-cli.test.js": 7,
|
|
39
|
+
"item-spans.test.js": 1,
|
|
40
|
+
"jev-categorize.test.js": 1,
|
|
41
|
+
"jev-claims.test.js": 1,
|
|
42
|
+
"jev-route.test.js": 1,
|
|
43
|
+
"jev-status.test.js": 1,
|
|
44
|
+
"jira-wbs.test.js": 1,
|
|
45
|
+
"kg.test.js": 2,
|
|
46
|
+
"kit-update.test.js": 1,
|
|
47
|
+
"launcher.test.js": 1,
|
|
48
|
+
"learn.test.js": 4,
|
|
49
|
+
"live-notes.test.js": 5,
|
|
50
|
+
"markdown.test.mjs": 1,
|
|
51
|
+
"measurements.test.js": 1,
|
|
52
|
+
"next-step-actions.test.js": 11,
|
|
53
|
+
"no-network.test.js": 1,
|
|
54
|
+
"notes-listen.test.js": 2,
|
|
55
|
+
"notes.test.js": 5,
|
|
56
|
+
"online-mode.test.js": 1,
|
|
57
|
+
"people.test.js": 2,
|
|
58
|
+
"phone-access.test.js": 1,
|
|
59
|
+
"phone-command.test.js": 4,
|
|
60
|
+
"placements.test.js": 1,
|
|
61
|
+
"plan-items-stage-parity.test.js": 1,
|
|
62
|
+
"plan-items.test.js": 1,
|
|
63
|
+
"plan-routes.test.js": 11,
|
|
64
|
+
"plan-tree.test.js": 6,
|
|
65
|
+
"pm-board-dest-phone-test.js": 14,
|
|
66
|
+
"pm-board-dest-test.js": 27,
|
|
67
|
+
"pm-breakdown-phone-test.js": 33,
|
|
68
|
+
"pm-breakdown-test.js": 68,
|
|
69
|
+
"pm-breakdown-timeline-test.js": 25,
|
|
70
|
+
"pm-cuts-test.js": 16,
|
|
71
|
+
"pm-detail-test.js": 18,
|
|
72
|
+
"pm-doc-category-test.js": 6,
|
|
73
|
+
"pm-docs-test.js": 37,
|
|
74
|
+
"pm-frame-phone-test.js": 14,
|
|
75
|
+
"pm-frame-test.js": 21,
|
|
76
|
+
"pm-initiatives-dest-phone-test.js": 9,
|
|
77
|
+
"pm-initiatives-dest-test.js": 28,
|
|
78
|
+
"pm-initiatives-test.js": 19,
|
|
79
|
+
"pm-initiatives-timeline-test.js": 39,
|
|
80
|
+
"pm-jira-test.js": 6,
|
|
81
|
+
"pm-lines-needs.test.js": 1,
|
|
82
|
+
"pm-live-notes-test.js": 25,
|
|
83
|
+
"pm-modes-test.js": 11,
|
|
84
|
+
"pm-nonce-test.js": 14,
|
|
85
|
+
"pm-notes-test.js": 40,
|
|
86
|
+
"pm-palette-test.js": 29,
|
|
87
|
+
"pm-people-test.js": 12,
|
|
88
|
+
"pm-r1-test.js": 10,
|
|
89
|
+
"pm-r10-test.js": 1,
|
|
90
|
+
"pm-r11-test.js": 2,
|
|
91
|
+
"pm-r12-test.js": 17,
|
|
92
|
+
"pm-r13-test.js": 12,
|
|
93
|
+
"pm-r14-test.js": 7,
|
|
94
|
+
"pm-r15-test.js": 7,
|
|
95
|
+
"pm-r16-test.js": 16,
|
|
96
|
+
"pm-r17-test.js": 7,
|
|
97
|
+
"pm-r18-test.js": 11,
|
|
98
|
+
"pm-r19-test.js": 20,
|
|
99
|
+
"pm-r2-test.js": 7,
|
|
100
|
+
"pm-r20-test.js": 19,
|
|
101
|
+
"pm-r21-test.js": 29,
|
|
102
|
+
"pm-r22-test.js": 2,
|
|
103
|
+
"pm-r23-test.js": 17,
|
|
104
|
+
"pm-r24-test.js": 15,
|
|
105
|
+
"pm-r25-test.js": 1,
|
|
106
|
+
"pm-r26-test.js": 1,
|
|
107
|
+
"pm-r27-test.js": 26,
|
|
108
|
+
"pm-r28-test.js": 1,
|
|
109
|
+
"pm-r29-filespad-test.js": 1,
|
|
110
|
+
"pm-r29-knowledge-test.js": 1,
|
|
111
|
+
"pm-r29-memory-test.js": 1,
|
|
112
|
+
"pm-r29-newsession-alignment-test.js": 1,
|
|
113
|
+
"pm-r29-portfolio-test.js": 1,
|
|
114
|
+
"pm-r29-reports-addrepo-test.js": 1,
|
|
115
|
+
"pm-r29-skills-scheduled-test.js": 1,
|
|
116
|
+
"pm-r29-today-test.js": 12,
|
|
117
|
+
"pm-r29-validate-guide-test.js": 1,
|
|
118
|
+
"pm-r3-test.js": 11,
|
|
119
|
+
"pm-r30-test.js": 13,
|
|
120
|
+
"pm-r4-test.js": 4,
|
|
121
|
+
"pm-r5-test.js": 6,
|
|
122
|
+
"pm-r6-test.js": 5,
|
|
123
|
+
"pm-r7-test.js": 1,
|
|
124
|
+
"pm-r8-test.js": 1,
|
|
125
|
+
"pm-r9-test.js": 10,
|
|
126
|
+
"pm-report-slides-test.js": 6,
|
|
127
|
+
"pm-reports-phone-test.js": 9,
|
|
128
|
+
"pm-reports-test.js": 20,
|
|
129
|
+
"pm-repos-test.js": 10,
|
|
130
|
+
"pm-seams-test.js": 16,
|
|
131
|
+
"pm-shell-test.js": 6,
|
|
132
|
+
"pm-tabs-test.js": 55,
|
|
133
|
+
"pm-term-test.js": 38,
|
|
134
|
+
"pm-today-goals-test.js": 30,
|
|
135
|
+
"pm-today-phone-test.js": 27,
|
|
136
|
+
"pm-today-test.js": 60,
|
|
137
|
+
"pm-updates-test.js": 16,
|
|
138
|
+
"proactive-prepare.test.js": 12,
|
|
139
|
+
"proactive.test.js": 17,
|
|
140
|
+
"profiles.test.js": 1,
|
|
141
|
+
"public-host.test.js": 1,
|
|
142
|
+
"r25-guards.test.js": 9,
|
|
143
|
+
"r3-display.test.js": 4,
|
|
144
|
+
"replaced-tests.test.js": 17,
|
|
145
|
+
"repo-scan.test.js": 1,
|
|
146
|
+
"repo-watch.test.js": 1,
|
|
147
|
+
"report-cli.test.js": 2,
|
|
148
|
+
"report-draft.test.js": 4,
|
|
149
|
+
"report-needs.test.js": 1,
|
|
150
|
+
"report-slides-data.test.js": 1,
|
|
151
|
+
"routes-board.test.js": 1,
|
|
152
|
+
"routes-capture.test.js": 1,
|
|
153
|
+
"routes-initiatives.test.js": 3,
|
|
154
|
+
"routes-reports.test.js": 1,
|
|
155
|
+
"routes-timeline.test.js": 1,
|
|
156
|
+
"routes-today.test.js": 6,
|
|
157
|
+
"scan-consistency.test.js": 1,
|
|
158
|
+
"schedule-cli.test.js": 3,
|
|
159
|
+
"session-flag.test.js": 1,
|
|
160
|
+
"start-policy.test.js": 1,
|
|
161
|
+
"state-isolation.test.js": 37,
|
|
162
|
+
"status-facts-panel.test.js": 1,
|
|
163
|
+
"story-artifacts.test.js": 1,
|
|
164
|
+
"sync.test.js": 4,
|
|
165
|
+
"test.js": 65,
|
|
166
|
+
"today.test.js": 5,
|
|
167
|
+
"tracker-refresh.test.js": 1,
|
|
168
|
+
"typesafe-validation.test.js": 1,
|
|
169
|
+
"ui-test.js": 43,
|
|
170
|
+
"work-check-needs.test.js": 1
|
|
171
|
+
}
|
|
172
|
+
}
|