create-pmos 0.503.0 → 0.504.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-pmos",
3
- "version": "0.503.0",
3
+ "version": "0.504.0",
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": {
@@ -32,6 +32,19 @@
32
32
  "audit"
33
33
  ],
34
34
  "pmosChanges": [
35
+ {
36
+ "v": "0.504.0",
37
+ "at": "2026-11-03T05:59:07.712Z",
38
+ "f": 3,
39
+ "prs": [
40
+ {
41
+ "n": 1189,
42
+ "t": "The Working card ends when Claude's answer ends",
43
+ "s": "The Working card ends when Claude's answer ends",
44
+ "k": "fix"
45
+ }
46
+ ]
47
+ },
35
48
  {
36
49
  "v": "0.503.0",
37
50
  "at": "2026-11-03T05:42:41.752Z",
@@ -422,19 +435,6 @@
422
435
  "k": "fix"
423
436
  }
424
437
  ]
425
- },
426
- {
427
- "v": "0.484.0",
428
- "at": "2026-11-02T02:00:11.221Z",
429
- "f": 3,
430
- "prs": [
431
- {
432
- "n": 1143,
433
- "t": "Program chats get the header pill; a phone shows every PDF page (batch 22 items 17, 18)",
434
- "s": "Program chats get the header pill; a phone shows every PDF page (batch 22 items 17, 18)",
435
- "k": "fix"
436
- }
437
- ]
438
438
  }
439
439
  ]
440
440
  }
@@ -1,3 +1,3 @@
1
- kernel-source: pmos@8b7c5275
1
+ kernel-source: pmos@c0e7ff36
2
2
  assembled: 2026-11-03
3
3
  mode: vendor
@@ -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-11-03T05:42:38Z"}
5
+ generated: {by: process:create-pmos, at: "2026-11-03T05:59:04Z"}
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-11-03T05:42:38Z"}
5
+ generated: {by: process:create-pmos, at: "2026-11-03T05:59:04Z"}
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-11-03T05:42:38Z"}
5
+ generated: {by: process:create-pmos, at: "2026-11-03T05:59:04Z"}
6
6
  status: stable
7
7
  ---
8
8
 
@@ -1,4 +1,17 @@
1
1
  [
2
+ {
3
+ "v": "0.504.0",
4
+ "at": "2026-11-03T05:59:07.712Z",
5
+ "f": 3,
6
+ "prs": [
7
+ {
8
+ "n": 1189,
9
+ "t": "The Working card ends when Claude's answer ends",
10
+ "s": "The Working card ends when Claude's answer ends",
11
+ "k": "fix"
12
+ }
13
+ ]
14
+ },
2
15
  {
3
16
  "v": "0.503.0",
4
17
  "at": "2026-11-03T05:42:41.752Z",
@@ -236,9 +236,20 @@ function newHarnessAcc() {
236
236
  // more. `ai-title` and `attachment` records are CLI bookkeeping and are deliberately not
237
237
  // turn-taking, and neither is a SYNTHETIC assistant record: counting one as "the assistant
238
238
  // finished speaking" is exactly how a false `needs you` would be manufactured.
239
- lastRole: null }; // 'assistant' | 'user' | null
239
+ lastRole: null, // 'assistant' | 'user' | null
240
+ msgId: null, // the newest real model message's id: a new one closes the older messages' calls (feedHarness)
241
+ cmdFrom: undefined }; // the turn before a /command record, given back when the CLI answers the command itself
240
242
  }
241
243
 
244
+ // The text of a user record, for the turn rules below: string content, or its text blocks joined.
245
+ function userRecordText(um) {
246
+ if (typeof um.content === 'string') return um.content;
247
+ return (Array.isArray(um.content) ? um.content : []).filter((c) => c && c.type === 'text' && typeof c.text === 'string').map((c) => c.text).join('\n');
248
+ }
249
+ const INTERRUPTED = /^\s*\[Request interrupted by user/;
250
+ const LOCAL_OUT = /^\s*<(local-command-stdout|local-command-stderr)>/;
251
+ const LOCAL_IN = /^\s*<(bash-input|bash-stdout|bash-stderr)>|^\s*Caveat: The messages below/;
252
+
242
253
  function feedHarness(acc, raw, clean) {
243
254
  for (const line of raw.split('\n')) {
244
255
  if (!line) continue;
@@ -253,13 +264,27 @@ function feedHarness(acc, raw, clean) {
253
264
  }
254
265
  // tool_result blocks live inside `user` records; harvest the ids they resolve.
255
266
  if (r.type === 'user') {
267
+ if (r.isSidechain) continue; // a subagent's own records: its calls and results never hold the main session's turn
256
268
  const um = r.message || {};
269
+ let result = false;
257
270
  for (const c of (Array.isArray(um.content) ? um.content : [])) {
258
271
  if (c && c.type === 'tool_result' && c.tool_use_id) {
272
+ result = true;
259
273
  if (!acc.openUse.delete(c.tool_use_id)) acc.resolved.add(c.tool_use_id);
260
274
  }
261
275
  }
262
- acc.lastRole = 'user'; // a prompt was submitted, or a tool result landed
276
+ const said = result ? '' : userRecordText(um);
277
+ // batch 25 item 15: only a prompt or a tool result gives the model the turn. The CLI's own records after a finished
278
+ // answer (a meta note, a compact summary, a local command such as /model and its output, a `!` shell line) start no
279
+ // model turn, so counting them left the chat on "Working" for hours after Claude had answered.
280
+ if (result) acc.lastRole = 'user';
281
+ else if (INTERRUPTED.test(said)) { acc.lastRole = 'assistant'; acc.openUse.clear(); } // Esc / Stop: the model stopped, the PM is up
282
+ else if (LOCAL_OUT.test(said)) { if (acc.cmdFrom !== undefined) acc.lastRole = acc.cmdFrom; acc.cmdFrom = undefined; } // a local command answered itself
283
+ else if (r.isMeta || r.isCompactSummary || r.isVisibleInTranscriptOnly || LOCAL_IN.test(said)) { /* bookkeeping: not turn-taking */ }
284
+ else {
285
+ if (/<command-name>/.test(said)) acc.cmdFrom = acc.lastRole; // /name: a prompt command takes the turn; a local one gives it back above
286
+ acc.lastRole = 'user'; // a prompt was submitted
287
+ }
263
288
  continue;
264
289
  }
265
290
  if (r.type === 'attachment') {
@@ -274,6 +299,13 @@ function feedHarness(acc, raw, clean) {
274
299
  }
275
300
  if (r.type !== 'assistant') continue;
276
301
  const m = r.message || {};
302
+ if (m.model && m.model !== SYNTHETIC && !r.isSidechain && m.id && m.id !== acc.msgId) {
303
+ // A new model message starts only once every call of the one before it has its result: the model cannot go on without
304
+ // them. So a call of an older message that is still unresolved is a phantom (a crash, a killed pane, a resumed chat), never
305
+ // a call in flight, and it must not hold the turn (batch 25 item 15: a chat showed "Working · 169:28" under its answer).
306
+ for (const [id, info] of acc.openUse) if (info.msg !== m.id) acc.openUse.delete(id);
307
+ acc.msgId = m.id;
308
+ }
277
309
  if (m.model && m.model !== SYNTHETIC) {
278
310
  acc.model = clean(m.model);
279
311
  acc.turns++; // only real model turns count
@@ -298,7 +330,7 @@ function feedHarness(acc, raw, clean) {
298
330
  const name = clean(prettyTool(c.name));
299
331
  acc.toolCounts[name] = (acc.toolCounts[name] || 0) + 1;
300
332
  acc.toolTotal++;
301
- if (c.id && !acc.resolved.delete(c.id)) acc.openUse.set(c.id, { verb: name, ts: r.timestamp || null });
333
+ if (c.id && !r.isSidechain && !acc.resolved.delete(c.id)) acc.openUse.set(c.id, { verb: name, ts: r.timestamp || null, msg: m.id || null });
302
334
  }
303
335
  }
304
336
  }
@@ -320,6 +352,9 @@ function harnessOf(acc) {
320
352
  // the strong `needs you` claim can be built) is UNREACHABLE for it. Not a guard that rejects
321
353
  // the phantom: a value it cannot construct. Reordering these branches silently converts a
322
354
  // corpse into "waiting on you", which is the one lie this surface must not tell.
355
+ // A phantom stays only while nothing came after it: once a NEWER model message exists, the session demonstrably went
356
+ // on past that call, so feedHarness drops it (batch 25 item 15). A crash with the call as its newest record still lands
357
+ // on `tool`, exactly as above.
323
358
  if (out.openCall) out.turn = 'tool'; // awaiting a tool — OR the PM's approval of one
324
359
  else if (acc.lastRole === 'assistant') out.turn = 'user'; // the model stopped; the human is up
325
360
  else if (acc.lastRole === 'user') out.turn = 'agent'; // a prompt/result landed; the model is up
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pmos-workspace",
3
- "version": "0.503.0",
3
+ "version": "0.504.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pmos-workspace",
9
- "version": "0.503.0",
9
+ "version": "0.504.0",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@anthropic-ai/sdk": "^1.3.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmos-workspace",
3
- "version": "0.503.0",
3
+ "version": "0.504.0",
4
4
  "private": true,
5
5
  "description": "PMOS Terminal Workspace — local companion hosting real PTYs beside the library and gates (D62)",
6
6
  "license": "MIT",