pm-brief 2026.10.21 → 2026.10.24
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/CHANGELOG.md +28 -0
- package/README.md +243 -2
- package/dist/alternatives.d.ts +45 -0
- package/dist/alternatives.d.ts.map +1 -0
- package/dist/alternatives.js +103 -0
- package/dist/alternatives.js.map +1 -0
- package/dist/disclosure.d.ts +70 -0
- package/dist/disclosure.d.ts.map +1 -0
- package/dist/disclosure.js +227 -0
- package/dist/disclosure.js.map +1 -0
- package/dist/handoff.d.ts +102 -0
- package/dist/handoff.d.ts.map +1 -0
- package/dist/handoff.js +352 -0
- package/dist/handoff.js.map +1 -0
- package/dist/index.d.ts +17 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +116 -57
- package/dist/index.js.map +1 -1
- package/docs/examples/alternatives.md +22 -0
- package/docs/examples/disclosure.md +127 -0
- package/docs/examples/handoff.json +6 -0
- package/manifest.json +1 -1
- package/package.json +12 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026.10.24 - 2026-10-24
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Record acknowledged handoff contracts against item revisions ([pm-brief-cjxn](https://github.com/unbraind/pm-brief/blob/main/.agents/pm/features/pm-brief-cjxn.toon))
|
|
8
|
+
- Compare recorded decision alternatives with cited evidence ([pm-brief-ktjl](https://github.com/unbraind/pm-brief/blob/main/.agents/pm/features/pm-brief-ktjl.toon))
|
|
9
|
+
|
|
10
|
+
### Other
|
|
11
|
+
|
|
12
|
+
- Verify evidence for tracker reconciliation review ([pm-brief-review165](https://github.com/unbraind/pm-brief/blob/main/.agents/pm/chores/pm-brief-review165.toon))
|
|
13
|
+
|
|
14
|
+
## 2026.10.23 - 2026-10-23
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Enable the gated GitHub issue sync ([pm-brief-gp5o](https://github.com/unbraind/pm-brief/blob/main/.agents/pm/chores/pm-brief-gp5o.toon))
|
|
19
|
+
- Adopt pm-github 2026.10.16: default-branch-safe gated sync and daily gated closeout PRs ([pm-brief-b7dy](https://github.com/unbraind/pm-brief/blob/main/.agents/pm/chores/pm-brief-b7dy.toon))
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- The publish-attestation gate misses a publish routed through an unquoted shell variable ([pm-brief-tai3](https://github.com/unbraind/pm-brief/blob/main/.agents/pm/issues/pm-brief-tai3.toon))
|
|
24
|
+
- The release job authenticated with a stored npm token that expired, so publishing stopped while every other gate stayed green ([pm-brief-s83v](https://github.com/unbraind/pm-brief/blob/main/.agents/pm/issues/pm-brief-s83v.toon))
|
|
25
|
+
- A release run bumped and committed a new version every night while publishing was impossible, because the only externally-failable step runs last ([pm-brief-4ohy](https://github.com/unbraind/pm-brief/blob/main/.agents/pm/issues/pm-brief-4ohy.toon))
|
|
26
|
+
|
|
27
|
+
### Other
|
|
28
|
+
|
|
29
|
+
- Enable GitHub CodeQL code scanning ([pm-brief-1p5o](https://github.com/unbraind/pm-brief/blob/main/.agents/pm/chores/pm-brief-1p5o.toon))
|
|
30
|
+
|
|
3
31
|
## 2026.10.21 - 2026-10-21
|
|
4
32
|
|
|
5
33
|
### Fixed
|
package/README.md
CHANGED
|
@@ -47,10 +47,11 @@ pm brief since 2026-07-20T00:00:00Z --until 2026-07-22 --author alice
|
|
|
47
47
|
- `pm brief since <checkpoint>` renders a delta brief of what changed since a checkpoint.
|
|
48
48
|
- `pm brief diverge [base]` previews pm item collisions between two branches **before** merging.
|
|
49
49
|
- `pm brief duplicates` sweeps the merged tracker for near-duplicate items the create-time advisory cannot see across branches.
|
|
50
|
+
- `pm brief alternatives <id> <id> [more ids]` compares recorded proposals, outcomes and evidence with exact citations and no recommendation.
|
|
50
51
|
|
|
51
52
|
### Ranking and Budget Flags
|
|
52
53
|
|
|
53
|
-
- `--max-tokens` is an alias for `--token-budget`: a ceiling on the chosen rendered brief, estimated as `ceil(
|
|
54
|
+
- `--max-tokens` is an alias for `--token-budget`: a ceiling on the chosen rendered brief, estimated by the SDK as `ceil(UTF-8 bytes / 4)` (not a model tokenizer).
|
|
54
55
|
- `--dependency-order` prefers prerequisite items before dependent work in next-work ranking.
|
|
55
56
|
- `--focus` highlights specific item ids, or `type:Type` to highlight every item of a type (repeatable or comma-separated).
|
|
56
57
|
- `--include-history` adds a Recent Activity section sourced from `pm activity` to briefs and prompts; `--history-limit` controls the entry count (default 10).
|
|
@@ -87,10 +88,24 @@ const output = renderBrief(brief, "markdown");
|
|
|
87
88
|
`renderMarkdownBrief`, `renderSlackBrief` and `renderAgentPrompt` enforce the
|
|
88
89
|
selected rendering again if callers change format or modify the returned object.
|
|
89
90
|
`budget.estimatedTokens` measures the rendering chosen at build time, including
|
|
90
|
-
its own digit count. An unchanged ordinary tracker that already fits keeps its
|
|
91
|
+
its own digit count and trailing newline, using the SDK UTF-8 byte estimator. An unchanged ordinary tracker that already fits keeps its
|
|
91
92
|
sections and fields; only the estimate disclosure can differ from older versions.
|
|
92
93
|
See [budget evidence and recovery](docs/brief-budget.md) for the regression matrix.
|
|
93
94
|
|
|
95
|
+
Next-work recommendations exclude items with unresolved prerequisites, including
|
|
96
|
+
reverse `blocks` edges and missing targets. Held work remains visible in explicit
|
|
97
|
+
focus, blocker and risk evidence. External targets (`source_kind=global`, its
|
|
98
|
+
`external` alias, or external reference syntax) stay separate from local IDs:
|
|
99
|
+
external reverse edges cannot block local namesakes, and external references
|
|
100
|
+
cannot add local dependent context or ranking credit. Workspace terminal roles govern lifecycle
|
|
101
|
+
filters; library callers can supply `BriefOptions.statusRegistry` from
|
|
102
|
+
`resolveRuntimeStatusRegistry((await readSettings(pmRoot)).schema)`. Omitted
|
|
103
|
+
registries use SDK core defaults plus the legacy terminal `done` spelling, so
|
|
104
|
+
custom terminal names need their registry. An explicitly configured `done` role
|
|
105
|
+
takes precedence over that compatibility fallback. Native disclosure reads the
|
|
106
|
+
workspace registry too. See [relationship readiness](docs/relationship-readiness.md)
|
|
107
|
+
for the graph-shape matrix.
|
|
108
|
+
|
|
94
109
|
## Agent Brief Contents
|
|
95
110
|
|
|
96
111
|
- workspace and item counts
|
|
@@ -410,3 +425,229 @@ compaction. Command-local selection limits and document budgets still apply.
|
|
|
410
425
|
trackers: projection, budget omission, every-row cursor recovery, and writer
|
|
411
426
|
rejection. Remove only the declarations, rebuild, and prove the tests fail.
|
|
412
427
|
5. Run unchanged npm and Bun release gates and document their exact results.
|
|
428
|
+
|
|
429
|
+
## Acknowledged handoff contracts
|
|
430
|
+
|
|
431
|
+
`pm brief handoff` records what each receiving agent understood against exact
|
|
432
|
+
item content revisions. A packet includes explicit questions, unresolved
|
|
433
|
+
assumptions, required evidence and the transitive declared blocker closure.
|
|
434
|
+
A changed blocker, source item or evidence item invalidates its old receipts.
|
|
435
|
+
Two receivers append independent receipts to the same tracker; identical retries
|
|
436
|
+
by the same author add nothing. Claims continue to own work ownership.
|
|
437
|
+
|
|
438
|
+
```sh
|
|
439
|
+
# Set an explicit identity for each sender or receiver.
|
|
440
|
+
export PM_AUTHOR=sender
|
|
441
|
+
# Replace the focus/evidence item ids in docs/examples/handoff.json.
|
|
442
|
+
pm brief handoff preview --input docs/examples/handoff.json --json
|
|
443
|
+
pm brief handoff create --input docs/examples/handoff.json --json
|
|
444
|
+
# Save the returned id and digest. Then write response.json, as shown below.
|
|
445
|
+
PM_AUTHOR=receiver-a pm brief handoff ack <packet-id> --input response.json --json
|
|
446
|
+
pm brief handoff show <packet-id> --receiver receiver-a
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
A receiver supplies every obligation id, including evidence that is still missing:
|
|
450
|
+
|
|
451
|
+
```json
|
|
452
|
+
{
|
|
453
|
+
"digest": "<64-character digest from the packet>",
|
|
454
|
+
"questions": { "fixture": "I will use the public tracker fixture." },
|
|
455
|
+
"assumptions": { "review": "Unresolved; I will verify the blocker before proceeding." },
|
|
456
|
+
"evidence": { "report": "The report link is missing; validation remains outstanding." }
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
Every collection is explicit; use `[]` in contracts and `{}` in responses when
|
|
461
|
+
there are no obligations. Each input collection has at most 32 entries; the
|
|
462
|
+
blocker/evidence closure has at most 64 items. Keys use ASCII letters, digits,
|
|
463
|
+
dots, underscores or hyphens and start with a letter or digit. Obligation and actor
|
|
464
|
+
keys have at most 128 characters; native item identifiers retain their full length. Obligation text and evidence references have at most 2,000 code units.
|
|
465
|
+
Native source titles and blocker references retain their full text under the aggregate budget.
|
|
466
|
+
Native TOON is the default; `--json` uses the host's
|
|
467
|
+
structured JSON output. The default conservative output ceiling is 4,000 tokens,
|
|
468
|
+
measured from UTF-8 bytes with twice pretty-JSON size plus framing headroom.
|
|
469
|
+
`--token-budget` accepts up to 64,000. Oversized output refuses with a remedy;
|
|
470
|
+
it never silently drops questions, assumptions, evidence or receiver receipts.
|
|
471
|
+
A receiver filter reduces the selected receipt set without changing storage.
|
|
472
|
+
Universal host output controls can intentionally project or paginate read commands;
|
|
473
|
+
retain their omission receipts and use normal output for a complete contract.
|
|
474
|
+
|
|
475
|
+
Evidence requirements select exact native `docs`, `files` or `tests` links by
|
|
476
|
+
`item`, `kind` and `ref` (path, or test command). `missingEvidence` remains visible
|
|
477
|
+
in the packet and each receipt. Linkage proves a reference was recorded; it does
|
|
478
|
+
not prove that a file exists, its contents are correct, or a test passed. Receiver
|
|
479
|
+
statements are self-reported understanding, including disagreement or uncertainty.
|
|
480
|
+
`valid` means the source revisions still match; `ready` additionally means all
|
|
481
|
+
required links are present. Neither field grants approval or claims the work.
|
|
482
|
+
|
|
483
|
+
Packets are native Decision items tagged `pm-brief-handoff`; their JSON bodies are
|
|
484
|
+
immutable protocol artifacts. Receipts are append-only native comments protected
|
|
485
|
+
by the host's comment lock and author/text idempotency. Native lock contention
|
|
486
|
+
is retried up to three times for reads and idempotent appends; creates are never
|
|
487
|
+
automatically retried. Persistent contention refuses with a retry remedy. Do not edit contract bodies
|
|
488
|
+
or receipt comments. Create a fresh packet after a revision changes. A receipt
|
|
489
|
+
racing a source edit is reassessed on return and every subsequent read. All source
|
|
490
|
+
metadata, bodies and linked evidence contribute to content revisions, so even an
|
|
491
|
+
unrelated source comment conservatively invalidates old understanding. Reads are
|
|
492
|
+
certified full-corpus snapshots, not a transaction spanning arbitrary source writers.
|
|
493
|
+
|
|
494
|
+
The SDK exports `previewHandoff`, `createHandoff`, `acknowledgeHandoff`,
|
|
495
|
+
`inspectHandoff`, their typed contracts, and `HandoffError` (`code`, `remedy`).
|
|
496
|
+
Pass `{ pmRoot, author, tokenBudget? }`, optionally with the active native `PmClient`.
|
|
497
|
+
CLI expected refusals exit 2 (3 for a stale packet), with a stable `handoff_<code>`
|
|
498
|
+
JSON category and a `required` remedy.
|
|
499
|
+
Categories cover invalid input, identity, missing packets/items, response coverage,
|
|
500
|
+
integrity, budget and tracker reads. Validation and budget checks precede writes.
|
|
501
|
+
The commands never change source items or claims; `preview` and `show` are read-only.
|
|
502
|
+
|
|
503
|
+
This complements [pm-context](https://github.com/unbraind/pm-context)'s
|
|
504
|
+
context delivery/usage receipts and the [since-delta candidate](https://github.com/unbraind/pm-context/pull/164)
|
|
505
|
+
(`feat/since-delta-pack`)
|
|
506
|
+
(`pm context-pack since --from <timestamp>` or `--cursor <cursor>`). That candidate
|
|
507
|
+
owns cursor progress, changed-context selection and omission receipts. Use its delta to
|
|
508
|
+
refresh changed context, then create a new handoff here. No history delta engine
|
|
509
|
+
is duplicated. pm-memory continues to own standing knowledge; `brief prompt`
|
|
510
|
+
continues to generate prose. See the [contract example](docs/examples/handoff.json).
|
|
511
|
+
|
|
512
|
+
## Decision alternatives digest
|
|
513
|
+
|
|
514
|
+
```bash
|
|
515
|
+
pm brief alternatives pm-proposal-a pm-proposal-b --token-budget 4000
|
|
516
|
+
pm brief alternatives pm-proposal-a pm-proposal-b --json
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
Select 2–32 distinct exact item IDs, including terminal items when useful. The
|
|
520
|
+
read-only digest keeps each item separate and follows input order, which conveys
|
|
521
|
+
no preference. It quotes records instead of generating or inferring conclusions.
|
|
522
|
+
Conflicting Plan decisions within one item also remain separate. Core `pm plan`
|
|
523
|
+
owns planning and choices; `pm-review` owns finding verdicts. This command composes
|
|
524
|
+
those records across items without adding a decision engine.
|
|
525
|
+
|
|
526
|
+
Every statement has `source` (`item-id#/field/nested/pointer`), `start` and `end`
|
|
527
|
+
UTF-16 offsets, and exact `text`. Resolve pointers against the certified full item
|
|
528
|
+
row (`listAllComplete({ includeBody: true })`); offsets select the quoted paragraph
|
|
529
|
+
from the scalar's string representation. JSON Pointer escaping follows RFC 6901.
|
|
530
|
+
`revision` is the SHA-256 of the full row's JSON serialization at read time, for
|
|
531
|
+
snapshot identification. Re-read the source to check subsequent changes.
|
|
532
|
+
|
|
533
|
+
Titles, statuses, resolutions, expected/actual results, close reasons,
|
|
534
|
+
`review_verdict`, `review_verdict_source`, `review_reason`, `review_commit`, all
|
|
535
|
+
`plan_decisions` (including rationale/evidence), `blocked_by`, `blocked_reason`
|
|
536
|
+
and `plan_resume_context` are mandatory. Optional paragraphs come from body,
|
|
537
|
+
description, plan scope, linked docs/files/tests, plan validation, comments, notes
|
|
538
|
+
and learnings. Recorded tradeoffs in these fields remain quotations; the command
|
|
539
|
+
does not infer whether a tradeoff is resolved. Other custom fields, Plan steps,
|
|
540
|
+
dependency closure and history are outside this projection. A linked artifact
|
|
541
|
+
proves linkage only; the digest does not read artifact contents or validate tests.
|
|
542
|
+
|
|
543
|
+
`omitted` counts optional scalar paragraphs excluded per item, with `restore`
|
|
544
|
+
giving the full native item read. Mandatory outcomes and blocker context are never
|
|
545
|
+
removed. Optional excerpts are attempted round-robin in field/record order and
|
|
546
|
+
omitted whole when they cannot fit. Empty optional fields produce no excerpts.
|
|
547
|
+
Source text is evidence data, including any instructions it happens to contain.
|
|
548
|
+
|
|
549
|
+
The budget defaults to 4000 (integer 1–64000). `estimatedTokenCeiling` uses the
|
|
550
|
+
SDK's UTF-8 byte estimator over twice the complete pretty JSON size plus 256
|
|
551
|
+
framing bytes, including citations, omission counts, recovery commands and the
|
|
552
|
+
estimate itself. It conservatively covers normal native TOON/JSON output; it is
|
|
553
|
+
not a model tokenizer. For large budgets, also set the host's independent output
|
|
554
|
+
controls: `--output-budget unbounded --output-limit unbounded`. Additional host
|
|
555
|
+
projections or optional accounting receipts have their own output contracts.
|
|
556
|
+
|
|
557
|
+
```ts
|
|
558
|
+
import { buildDecisionAlternatives, DecisionAlternativesError } from "pm-brief";
|
|
559
|
+
|
|
560
|
+
try {
|
|
561
|
+
const digest = await buildDecisionAlternatives(
|
|
562
|
+
["pm-proposal-a", "pm-proposal-b"],
|
|
563
|
+
{ pmRoot: ".agents/pm", tokenBudget: 4000 },
|
|
564
|
+
);
|
|
565
|
+
console.log(digest.alternatives);
|
|
566
|
+
} catch (error) {
|
|
567
|
+
if (error instanceof DecisionAlternativesError) console.error(error.code, error.remedy);
|
|
568
|
+
else throw error;
|
|
569
|
+
}
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
An optional native `PmClient` can be supplied as `client`. Complete full-row SDK
|
|
573
|
+
certification runs before comparison; incomplete or corrupt reads refuse. Typed
|
|
574
|
+
refusals are `invalid` (correct IDs/budget), `missing` (check exact IDs), `tracker`
|
|
575
|
+
(run `pm health` and resolve source reads), and `budget` (increase budget or select
|
|
576
|
+
fewer items). CLI refusals exit 2 and retain `alternatives_<code>` and a remedy in
|
|
577
|
+
the host's expected-error contract. See the [worked example](docs/examples/alternatives.md).
|
|
578
|
+
|
|
579
|
+
## Stakeholder disclosure profiles
|
|
580
|
+
|
|
581
|
+
Render a brief for an explicit audience using native compact TOON (default) or
|
|
582
|
+
JSON. This is a read-only operation and does not require git:
|
|
583
|
+
|
|
584
|
+
```bash
|
|
585
|
+
pm brief disclose --audience public
|
|
586
|
+
pm --json brief disclose --audience external --dry-run
|
|
587
|
+
pm --json brief disclose --policy disclosure.json --token-budget 8000
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
| Audience | Permitted brief fields |
|
|
591
|
+
| --- | --- |
|
|
592
|
+
| `public` | Generation time, item count, and ranked item IDs, titles, types, statuses and priorities |
|
|
593
|
+
| `external` | Public fields plus ranking explanations, tags, dependencies, blockers, risks and staleness |
|
|
594
|
+
| `internal` | External fields plus workspace metadata, assignees, required context, activity, recommendations, insights and source budget metadata |
|
|
595
|
+
|
|
596
|
+
All profiles exclude unmodeled fields, including custom fields, momentum,
|
|
597
|
+
governance and merge receipts. Recognized credential-shaped values are removed
|
|
598
|
+
using the core SDK guard. The tracker path applies this guard before ranking
|
|
599
|
+
and compaction so shortening cannot conceal a recognized secret. This reuses
|
|
600
|
+
core detection; it is not a universal credential scanner or a guarantee that
|
|
601
|
+
arbitrary prose contains no confidential information. Review permitted titles
|
|
602
|
+
and labels before sharing them.
|
|
603
|
+
|
|
604
|
+
Policies can only narrow a profile. For example, `disclosure.json`:
|
|
605
|
+
|
|
606
|
+
```json
|
|
607
|
+
{"profile":"public","exclude":["focus.*.title","next.*.title","decisionsNeeded.*.title"]}
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
Only `profile` and `exclude` are accepted. Unknown keys, audiences or field
|
|
611
|
+
selectors refuse before reading the tracker. `DisclosureField` in the SDK
|
|
612
|
+
enumerates supported selectors; `*` denotes an array index. There is no override
|
|
613
|
+
for adding custom fields or bypassing the credential guard.
|
|
614
|
+
|
|
615
|
+
Every result contains an exclusion manifest grouped by reason (`profile`,
|
|
616
|
+
`policy`, `secret`, `unknown_field`, `invalid_value`). Each entry maps a
|
|
617
|
+
JSON Pointer path to an occurrence count. Profile/policy paths aggregate array
|
|
618
|
+
indices as `*`; secret paths identify individual rendered occurrences. Unknown
|
|
619
|
+
field names are replaced by `@N`, their zero-based position in their parent
|
|
620
|
+
object's property enumeration. Pre-compaction secret exclusions use
|
|
621
|
+
`/source/N/@M` for record/field positions; `/source/N` means a secret-bearing
|
|
622
|
+
identity caused the whole record to be withheld. These paths describe the
|
|
623
|
+
snapshot and never contain field values, item identifiers or unknown key text.
|
|
624
|
+
Dry runs return the same manifest without any brief values.
|
|
625
|
+
|
|
626
|
+
```ts
|
|
627
|
+
import { buildBrief, renderDisclosureBrief, buildDisclosureBrief, DisclosureError } from "pm-brief";
|
|
628
|
+
|
|
629
|
+
const brief = buildBrief(items); // One source; multiple independent renderings.
|
|
630
|
+
const publicView = renderDisclosureBrief(brief, { profile: "public" });
|
|
631
|
+
const reviewPreview = renderDisclosureBrief(brief, { profile: "external" }, { dryRun: true });
|
|
632
|
+
// Or read a complete, certified native snapshot using an optional host PmClient:
|
|
633
|
+
const view = await buildDisclosureBrief({ profile: "public" }, { pmRoot: ".agents/pm" });
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
The native tracker path reuses the existing 4000-token source brief selection;
|
|
637
|
+
`sourceTruncated` discloses source compaction. The default disclosure ceiling is
|
|
638
|
+
8000 estimated tokens, covering native JSON/TOON framing and every exclusion.
|
|
639
|
+
Use `renderDisclosureBrief` with your own `buildBrief` controls for a different
|
|
640
|
+
source selection. Rendering never silently drops manifest entries to fit.
|
|
641
|
+
`DisclosureError` provides `code` and `remedy`: `policy` (correct the policy),
|
|
642
|
+
`invalid` (correct controls/input), `tracker` (resolve the incomplete/unreadable
|
|
643
|
+
source), or `budget` (increase the ceiling or supply a smaller brief). CLI
|
|
644
|
+
refusals exit 2 with `disclosure_<code>` and a remedy, without source text or
|
|
645
|
+
nested error details. See the [worked example and public-tracker replay](docs/examples/disclosure.md).
|
|
646
|
+
|
|
647
|
+
## Without git
|
|
648
|
+
|
|
649
|
+
Briefs, prompts, ranking, history deltas, governance, duplicate checks and all
|
|
650
|
+
handoff, decision alternatives and stakeholder disclosure commands work in plain initialized trackers without a git executable.
|
|
651
|
+
Handoff storage uses the native SDK dispatcher and can reuse a host client.
|
|
652
|
+
`brief diverge` needs a git repository and git refs. Handoff receipts have no
|
|
653
|
+
branch, commit or repository dependency.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { PmClient } from "@unbrained/pm-cli/sdk";
|
|
2
|
+
import type { ExtensionApi } from "@unbrained/pm-cli/sdk/authoring";
|
|
3
|
+
/** Exact recorded text with an item-relative JSON Pointer and UTF-16 range. */
|
|
4
|
+
export interface DecisionExcerpt {
|
|
5
|
+
source: string;
|
|
6
|
+
start: number;
|
|
7
|
+
end: number;
|
|
8
|
+
text: string;
|
|
9
|
+
}
|
|
10
|
+
/** One proposal remains independent, including all recorded outcomes and blockers. */
|
|
11
|
+
export interface DecisionAlternative {
|
|
12
|
+
id: string;
|
|
13
|
+
revision: string;
|
|
14
|
+
statements: DecisionExcerpt[];
|
|
15
|
+
omitted: number;
|
|
16
|
+
restore: string;
|
|
17
|
+
}
|
|
18
|
+
/** Extractive comparison; ordering follows the caller and never implies preference. */
|
|
19
|
+
export interface DecisionAlternativesDigest {
|
|
20
|
+
protocol: "pm-brief.alternatives/v1";
|
|
21
|
+
alternatives: DecisionAlternative[];
|
|
22
|
+
estimatedTokenCeiling: number;
|
|
23
|
+
}
|
|
24
|
+
/** Backend-neutral read context; injected native clients retain the active host dispatcher. */
|
|
25
|
+
export interface DecisionAlternativesOptions {
|
|
26
|
+
pmRoot: string;
|
|
27
|
+
client?: PmClient;
|
|
28
|
+
tokenBudget?: number;
|
|
29
|
+
}
|
|
30
|
+
/** Stable expected failure categories for SDK consumers. */
|
|
31
|
+
export type DecisionAlternativesRefusalCode = "invalid" | "missing" | "tracker" | "budget";
|
|
32
|
+
/** Typed refusal with a recovery action, never an empty successful comparison. */
|
|
33
|
+
export declare class DecisionAlternativesError extends Error {
|
|
34
|
+
/** Machine-readable failure category. */
|
|
35
|
+
readonly code: DecisionAlternativesRefusalCode;
|
|
36
|
+
/** Concrete correction to perform before retrying. */
|
|
37
|
+
readonly remedy: string;
|
|
38
|
+
/** Retain machine and human recovery information independently. */
|
|
39
|
+
constructor(code: DecisionAlternativesRefusalCode, message: string, remedy: string);
|
|
40
|
+
}
|
|
41
|
+
/** Compare explicitly selected native records read-only; never recommend, merge outcomes or invoke git. */
|
|
42
|
+
export declare function buildDecisionAlternatives(ids: string[], options: DecisionAlternativesOptions): Promise<DecisionAlternativesDigest>;
|
|
43
|
+
/** Register a native structured command so host TOON/JSON and error contracts remain authoritative. */
|
|
44
|
+
export declare function registerDecisionAlternativesCommand(api: ExtensionApi): void;
|
|
45
|
+
//# sourceMappingURL=alternatives.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alternatives.d.ts","sourceRoot":"","sources":["../alternatives.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAA+E,MAAM,uBAAuB,CAAC;AAE9H,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAEpE,+EAA+E;AAC/E,MAAM,WAAW,eAAe;IAAG,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AAC7F,sFAAsF;AACtF,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AACD,uFAAuF;AACvF,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,0BAA0B,CAAC;IACrC,YAAY,EAAE,mBAAmB,EAAE,CAAC;IACpC,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AACD,+FAA+F;AAC/F,MAAM,WAAW,2BAA2B;IAAG,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,QAAQ,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE;AACxG,4DAA4D;AAC5D,MAAM,MAAM,+BAA+B,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAC3F,kFAAkF;AAClF,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,+BAA+B,CAAC;IAC/C,sDAAsD;IACtD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,mEAAmE;IACnE,YAAY,IAAI,EAAE,+BAA+B,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAEjF;CACF;AA0BD,2GAA2G;AAC3G,wBAAsB,yBAAyB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,0BAA0B,CAAC,CA4BxI;AAED,uGAAuG;AACvG,wBAAgB,mCAAmC,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CAc3E"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { PmClient, certifyCompleteListResult, createPmCliExpectedError, estimatePmOutputTokens } from "@unbrained/pm-cli/sdk";
|
|
3
|
+
/** Typed refusal with a recovery action, never an empty successful comparison. */
|
|
4
|
+
export class DecisionAlternativesError extends Error {
|
|
5
|
+
/** Machine-readable failure category. */
|
|
6
|
+
code;
|
|
7
|
+
/** Concrete correction to perform before retrying. */
|
|
8
|
+
remedy;
|
|
9
|
+
/** Retain machine and human recovery information independently. */
|
|
10
|
+
constructor(code, message, remedy) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = "DecisionAlternativesError";
|
|
13
|
+
this.code = code;
|
|
14
|
+
this.remedy = remedy;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const REQUIRED = ["title", "status", "resolution", "expected_result", "actual_result", "close_reason", "review_verdict", "review_verdict_source", "review_reason", "review_commit", "plan_decisions", "blocked_by", "blocked_reason", "plan_resume_context"];
|
|
18
|
+
const OPTIONAL = ["body", "description", "plan_scope", "docs", "files", "tests", "plan_validation", "comments", "notes", "learnings"];
|
|
19
|
+
/** Reject malformed agent selection before reading a tracker. */
|
|
20
|
+
function validate(ids, budget) {
|
|
21
|
+
if (!Array.isArray(ids) || ids.length < 2 || ids.length > 32 || new Set(ids).size !== ids.length || ids.some(id => typeof id !== "string" || !/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(id)) || !Number.isSafeInteger(budget) || budget < 1 || budget > 64000) {
|
|
22
|
+
throw new DecisionAlternativesError("invalid", "Invalid alternative selection or token budget", "Supply 2-32 distinct exact item ids and an integer --token-budget from 1 to 64000 (default 4000)");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/** Walk recorded JSON values without inventing summaries or dropping conflicting entries. */
|
|
26
|
+
function excerpts(value, source) {
|
|
27
|
+
if (value === null || value === undefined || value === "")
|
|
28
|
+
return [];
|
|
29
|
+
if (Array.isArray(value))
|
|
30
|
+
return value.flatMap((entry, i) => excerpts(entry, `${source}/${i}`));
|
|
31
|
+
if (typeof value === "object")
|
|
32
|
+
return Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).flatMap(([key, entry]) => excerpts(entry, `${source}/${key.replace(/~/g, "~0").replace(/\//g, "~1")}`));
|
|
33
|
+
const text = String(value);
|
|
34
|
+
// Whole paragraphs preserve complete recorded sentences, including punctuation.
|
|
35
|
+
return [...text.matchAll(/[^\r\n]+(?:\r?\n(?!\s*\r?\n)[^\r\n]+)*/g)].map(match => ({ source, start: match.index, end: match.index + match[0].length, text: match[0] }));
|
|
36
|
+
}
|
|
37
|
+
/** Measure citations, omission counts, recovery commands and framing with the native estimator. */
|
|
38
|
+
function measure(digest) {
|
|
39
|
+
digest.estimatedTokenCeiling = 64000;
|
|
40
|
+
digest.estimatedTokenCeiling = estimatePmOutputTokens(Buffer.byteLength(JSON.stringify(digest, null, 2)) * 2 + 256);
|
|
41
|
+
return digest.estimatedTokenCeiling;
|
|
42
|
+
}
|
|
43
|
+
/** Compare explicitly selected native records read-only; never recommend, merge outcomes or invoke git. */
|
|
44
|
+
export async function buildDecisionAlternatives(ids, options) {
|
|
45
|
+
const budget = options.tokenBudget ?? 4000;
|
|
46
|
+
validate(ids, budget);
|
|
47
|
+
let items;
|
|
48
|
+
try {
|
|
49
|
+
const client = options.client ?? new PmClient({ pmRoot: options.pmRoot, noExtensions: true });
|
|
50
|
+
items = certifyCompleteListResult(await client.listAllComplete({ includeBody: true })).items;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
throw new DecisionAlternativesError("tracker", "Cannot certify the tracker snapshot", "Run pm health and resolve unreadable or incomplete records before retrying");
|
|
54
|
+
}
|
|
55
|
+
const rows = new Map(items.map(item => [item.id, item]));
|
|
56
|
+
if (ids.some(id => !rows.has(id)))
|
|
57
|
+
throw new DecisionAlternativesError("missing", "A selected alternative does not exist", "Check the exact ids with pm list --all --full; no alternative is silently removed");
|
|
58
|
+
const optional = [];
|
|
59
|
+
const alternatives = ids.map(id => {
|
|
60
|
+
const item = rows.get(id);
|
|
61
|
+
const extra = OPTIONAL.flatMap(field => excerpts(item[field], `${id}#/${field}`));
|
|
62
|
+
optional.push(extra);
|
|
63
|
+
return { id, revision: createHash("sha256").update(JSON.stringify(item)).digest("hex"), statements: REQUIRED.flatMap(field => excerpts(item[field], `${id}#/${field}`)), omitted: extra.length, restore: `pm get ${id} --json --output-budget unbounded --output-limit unbounded` };
|
|
64
|
+
});
|
|
65
|
+
const digest = { protocol: "pm-brief.alternatives/v1", alternatives, estimatedTokenCeiling: 0 };
|
|
66
|
+
if (measure(digest) > budget)
|
|
67
|
+
throw new DecisionAlternativesError("budget", "Mandatory alternative context exceeds the token budget", "Increase --token-budget (maximum 64000) or compare fewer items; titles, statuses, outcomes and blocker context are never dropped");
|
|
68
|
+
// Round-robin optional excerpts give each proposal context without ranking it.
|
|
69
|
+
const longest = Math.max(...optional.map(rows => rows.length));
|
|
70
|
+
for (let i = 0; i < longest; i++)
|
|
71
|
+
for (let j = 0; j < alternatives.length; j++) {
|
|
72
|
+
const excerpt = optional[j][i];
|
|
73
|
+
if (!excerpt)
|
|
74
|
+
continue;
|
|
75
|
+
const alternative = alternatives[j];
|
|
76
|
+
alternative.statements.push(excerpt);
|
|
77
|
+
alternative.omitted--;
|
|
78
|
+
if (measure(digest) > budget) {
|
|
79
|
+
alternative.statements.pop();
|
|
80
|
+
alternative.omitted++;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
measure(digest);
|
|
84
|
+
return digest;
|
|
85
|
+
}
|
|
86
|
+
/** Register a native structured command so host TOON/JSON and error contracts remain authoritative. */
|
|
87
|
+
export function registerDecisionAlternativesCommand(api) {
|
|
88
|
+
api.registerCommand({
|
|
89
|
+
name: "brief alternatives",
|
|
90
|
+
description: "Compare recorded proposals and evidence with citations, without picking a winner",
|
|
91
|
+
flags: [{ long: "--token-budget", type: "string", value_name: "n", description: "Conservative TOON/JSON token ceiling including citations and omissions (default 4000, maximum 64000)" }],
|
|
92
|
+
async run(ctx) {
|
|
93
|
+
try {
|
|
94
|
+
return await buildDecisionAlternatives(ctx.args, { pmRoot: ctx.pm_root, client: ctx.sdk?.client, tokenBudget: ctx.options.tokenBudget === undefined ? undefined : Number(ctx.options.tokenBudget) });
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
const refusal = error instanceof DecisionAlternativesError ? error : new DecisionAlternativesError("tracker", "Alternative comparison could not complete", "Run pm health and check tracker permissions before retrying");
|
|
98
|
+
throw createPmCliExpectedError(`alternatives ${refusal.code}: ${refusal.message}. Remedy: ${refusal.remedy}`, { exitCode: 2, context: { code: `alternatives_${refusal.code}`, required: refusal.remedy } });
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=alternatives.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alternatives.js","sourceRoot":"","sources":["../alternatives.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { PmClient } from "@unbrained/pm-cli/sdk";
|
|
2
|
+
import type { ExtensionApi } from "@unbrained/pm-cli/sdk/authoring";
|
|
3
|
+
import type { AgentBrief } from "./index.ts";
|
|
4
|
+
/** Fixed audiences; callers may narrow a profile but cannot widen it. */
|
|
5
|
+
export type DisclosureProfile = "internal" | "external" | "public";
|
|
6
|
+
/** Brief sections containing the same ranked-item shape. */
|
|
7
|
+
type ItemSection = "focus" | "next" | "decisionsNeeded";
|
|
8
|
+
/** Supported scalar fields in ranked items. */
|
|
9
|
+
type ItemField = "id" | "title" | "type" | "status" | "priority" | "assignee" | "whyNow" | "rankingScore" | "confidence" | "tokenCostEstimate" | "mergeCompromised";
|
|
10
|
+
/** Known selectors, using * for array indices; unknown selectors are refused. */
|
|
11
|
+
export type DisclosureField = "generatedAt" | "workspace.root" | "workspace.pmVersion" | "workspace.itemCount" | "budget.requestedTokens" | "budget.estimatedTokens" | "budget.truncated" | `${ItemSection}.*.${ItemField}` | `${ItemSection}.*.${"tags" | "rankingReasons" | "requiredContext" | "dependencyIds" | "dependentIds"}.*` | `blockers.*.${"itemId" | "blockedBy" | "kind" | "title" | "status"}` | `risks.*.${"itemId" | "severity" | "reason"}` | `staleContext.*.${"itemId" | "title" | "updatedAt" | "daysStale"}` | `recentActivity.*.${"timestamp" | "author" | "operation" | "itemId" | "message"}` | `recommendedPmUpdates.*.${"itemId" | "command" | "reason" | "safeToAutoApply"}` | `insights.*.${"level" | "message" | "suggestion"}`;
|
|
12
|
+
/** Explicit audience and optional additional denials. No permissive extension fields. */
|
|
13
|
+
export interface DisclosurePolicy {
|
|
14
|
+
profile: DisclosureProfile;
|
|
15
|
+
exclude?: DisclosureField[];
|
|
16
|
+
}
|
|
17
|
+
/** JSON values retained after validation and disclosure checks. */
|
|
18
|
+
export type DisclosureValue = string | number | boolean | DisclosureValue[] | {
|
|
19
|
+
[key: string]: DisclosureValue;
|
|
20
|
+
};
|
|
21
|
+
/** Value-free reasons; profile/policy paths use * for all matching array indices. */
|
|
22
|
+
export type DisclosureExclusionReason = "profile" | "policy" | "secret" | "unknown_field" | "invalid_value";
|
|
23
|
+
/** Field-level JSON Pointer paths and occurrence counts grouped by exclusion reason. */
|
|
24
|
+
export type DisclosureExclusion = Record<DisclosureExclusionReason, Record<string, number>>;
|
|
25
|
+
/** Agent-sized rendering with a manifest; dry runs contain no brief values. */
|
|
26
|
+
export interface DisclosureResult {
|
|
27
|
+
protocol: "pm-brief.disclosure/v1";
|
|
28
|
+
profile: DisclosureProfile;
|
|
29
|
+
dryRun: boolean;
|
|
30
|
+
sourceTruncated: boolean;
|
|
31
|
+
brief?: {
|
|
32
|
+
[key: string]: DisclosureValue;
|
|
33
|
+
};
|
|
34
|
+
exclusions: DisclosureExclusion;
|
|
35
|
+
estimatedTokenCeiling: number;
|
|
36
|
+
}
|
|
37
|
+
/** Pure rendering controls; the budget includes the full exclusion manifest. */
|
|
38
|
+
export interface DisclosureRenderOptions {
|
|
39
|
+
dryRun?: boolean;
|
|
40
|
+
tokenBudget?: number;
|
|
41
|
+
}
|
|
42
|
+
/** Native, backend-neutral tracker context; never invokes git or writes records. */
|
|
43
|
+
export interface DisclosureOptions extends DisclosureRenderOptions {
|
|
44
|
+
pmRoot: string;
|
|
45
|
+
client?: PmClient;
|
|
46
|
+
generatedAt?: string;
|
|
47
|
+
}
|
|
48
|
+
/** Stable refusal categories shared by the SDK and native CLI. */
|
|
49
|
+
export type DisclosureRefusalCode = "policy" | "invalid" | "tracker" | "budget";
|
|
50
|
+
/** Expected failure containing no source values, paths, policy text or nested causes. */
|
|
51
|
+
export declare class DisclosureError extends Error {
|
|
52
|
+
/** Stable machine category for recovery logic. */
|
|
53
|
+
readonly code: DisclosureRefusalCode;
|
|
54
|
+
/** Safe action to take before retrying. */
|
|
55
|
+
readonly remedy: string;
|
|
56
|
+
/** Preserve recovery information without exposing the failing input. */
|
|
57
|
+
constructor(code: DisclosureRefusalCode, message: string, remedy: string);
|
|
58
|
+
/** Normalize an unexpected failure without retaining potentially forbidden nested text. */
|
|
59
|
+
static from(error: unknown): DisclosureError;
|
|
60
|
+
}
|
|
61
|
+
/** Validate policy keys and every field selector before any tracker read or render. */
|
|
62
|
+
export declare function parseDisclosurePolicy(value: unknown): DisclosurePolicy;
|
|
63
|
+
/** Render the same brief through a closed field vocabulary before native serialization. */
|
|
64
|
+
export declare function renderDisclosureBrief(brief: AgentBrief, input: DisclosurePolicy, options?: DisclosureRenderOptions): DisclosureResult;
|
|
65
|
+
/** Read a certified native snapshot and reuse pm-brief ranking before disclosure. */
|
|
66
|
+
export declare function buildDisclosureBrief(input: DisclosurePolicy, options: DisclosureOptions): Promise<DisclosureResult>;
|
|
67
|
+
/** Register native structured output and sanitized expected errors, with no git dependency. */
|
|
68
|
+
export declare function registerDisclosureCommand(api: ExtensionApi): void;
|
|
69
|
+
export {};
|
|
70
|
+
//# sourceMappingURL=disclosure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disclosure.d.ts","sourceRoot":"","sources":["../disclosure.ts"],"names":[],"mappings":"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"}
|