create-pmos 0.67.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-pmos",
|
|
3
|
-
"version": "0.67.
|
|
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-07T02:
|
|
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-07T02:
|
|
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-07T02:
|
|
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