pm-brief 2026.10.23 → 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 CHANGED
@@ -1,5 +1,16 @@
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
+
3
14
  ## 2026.10.23 - 2026-10-23
4
15
 
5
16
  ### Changed
package/README.md CHANGED
@@ -51,7 +51,7 @@ pm brief since 2026-07-20T00:00:00Z --until 2026-07-22 --author alice
51
51
 
52
52
  ### Ranking and Budget Flags
53
53
 
54
- - `--max-tokens` is an alias for `--token-budget`: a ceiling on the chosen rendered brief, estimated as `ceil(characters / 4)` (not a model tokenizer).
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).
55
55
  - `--dependency-order` prefers prerequisite items before dependent work in next-work ranking.
56
56
  - `--focus` highlights specific item ids, or `type:Type` to highlight every item of a type (repeatable or comma-separated).
57
57
  - `--include-history` adds a Recent Activity section sourced from `pm activity` to briefs and prompts; `--history-limit` controls the entry count (default 10).
@@ -88,10 +88,24 @@ const output = renderBrief(brief, "markdown");
88
88
  `renderMarkdownBrief`, `renderSlackBrief` and `renderAgentPrompt` enforce the
89
89
  selected rendering again if callers change format or modify the returned object.
90
90
  `budget.estimatedTokens` measures the rendering chosen at build time, including
91
- 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
92
92
  sections and fields; only the estimate disclosure can differ from older versions.
93
93
  See [budget evidence and recovery](docs/brief-budget.md) for the regression matrix.
94
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
+
95
109
  ## Agent Brief Contents
96
110
 
97
111
  - workspace and item counts
@@ -562,10 +576,78 @@ refusals are `invalid` (correct IDs/budget), `missing` (check exact IDs), `track
562
576
  fewer items). CLI refusals exit 2 and retain `alternatives_<code>` and a remedy in
563
577
  the host's expected-error contract. See the [worked example](docs/examples/alternatives.md).
564
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
+
565
647
  ## Without git
566
648
 
567
649
  Briefs, prompts, ranking, history deltas, governance, duplicate checks and all
568
- handoff and decision alternatives commands work in plain initialized trackers without a git executable.
650
+ handoff, decision alternatives and stakeholder disclosure commands work in plain initialized trackers without a git executable.
569
651
  Handoff storage uses the native SDK dispatcher and can reuse a host client.
570
652
  `brief diverge` needs a git repository and git refs. Handoff receipts have no
571
653
  branch, commit or repository dependency.
@@ -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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"}
@@ -0,0 +1,227 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { PmClient, certifyCompleteListResult, createPmCliExpectedError, estimatePmOutputTokens, readSettings, resolveRuntimeStatusRegistry, scanMutationSecrets } from "@unbrained/pm-cli/sdk";
3
+ import { buildBrief } from "./index.js";
4
+ /** Expected failure containing no source values, paths, policy text or nested causes. */
5
+ export class DisclosureError extends Error {
6
+ /** Stable machine category for recovery logic. */
7
+ code;
8
+ /** Safe action to take before retrying. */
9
+ remedy;
10
+ /** Preserve recovery information without exposing the failing input. */
11
+ constructor(code, message, remedy) {
12
+ super(message);
13
+ this.name = "DisclosureError";
14
+ this.code = code;
15
+ this.remedy = remedy;
16
+ }
17
+ /** Normalize an unexpected failure without retaining potentially forbidden nested text. */
18
+ static from(error) {
19
+ return error instanceof DisclosureError ? error : new DisclosureError("tracker", "Disclosure could not complete", "Run pm health and check tracker permissions before retrying");
20
+ }
21
+ }
22
+ const LEVEL = { public: 0, external: 1, internal: 2 };
23
+ const FIELDS = new Map([
24
+ ["generatedAt", 0], ["workspace.root", 2], ["workspace.pmVersion", 2], ["workspace.itemCount", 0],
25
+ ["budget.requestedTokens", 2], ["budget.estimatedTokens", 2], ["budget.truncated", 2],
26
+ ]);
27
+ for (const section of ["focus", "next", "decisionsNeeded"]) {
28
+ for (const field of ["id", "title", "type", "status", "priority"])
29
+ FIELDS.set(`${section}.*.${field}`, 0);
30
+ for (const field of ["whyNow", "rankingScore", "confidence", "tokenCostEstimate", "mergeCompromised", "tags.*", "rankingReasons.*", "dependencyIds.*", "dependentIds.*"])
31
+ FIELDS.set(`${section}.*.${field}`, 1);
32
+ for (const field of ["assignee", "requiredContext.*"])
33
+ FIELDS.set(`${section}.*.${field}`, 2);
34
+ }
35
+ for (const field of ["itemId", "blockedBy", "kind", "title", "status"])
36
+ FIELDS.set(`blockers.*.${field}`, 1);
37
+ for (const field of ["itemId", "severity", "reason"])
38
+ FIELDS.set(`risks.*.${field}`, 1);
39
+ for (const field of ["itemId", "title", "updatedAt", "daysStale"])
40
+ FIELDS.set(`staleContext.*.${field}`, 1);
41
+ for (const field of ["timestamp", "author", "operation", "itemId", "message"])
42
+ FIELDS.set(`recentActivity.*.${field}`, 2);
43
+ for (const field of ["itemId", "command", "reason", "safeToAutoApply"])
44
+ FIELDS.set(`recommendedPmUpdates.*.${field}`, 2);
45
+ for (const field of ["level", "message", "suggestion"])
46
+ FIELDS.set(`insights.*.${field}`, 2);
47
+ /** Compile only trusted profile selectors; data keys remain exact path segments. */
48
+ const FIELD_PATHS = [...FIELDS].map(([field, level]) => ({ field: field, level, segments: field.split(".") }));
49
+ /** Match a structured data-path prefix; profile wildcards accept only numeric array indices. */
50
+ function matchesDisclosurePath(pattern, path) {
51
+ return path.length <= pattern.length && path.every((segment, i) => pattern[i] === "*" ? typeof segment === "number" : pattern[i] === segment);
52
+ }
53
+ /** Refuse a malformed or widening policy without echoing its contents. */
54
+ function invalidPolicy() {
55
+ throw new DisclosureError("policy", "Unknown or invalid disclosure policy", "Use only profile (internal, external or public) and optional exclude containing documented field selectors; policies can only remove fields");
56
+ }
57
+ /** Check JSON object shape without coercing arrays or null into a policy. */
58
+ function object(value) { return typeof value === "object" && value !== null && !Array.isArray(value); }
59
+ /** Validate policy keys and every field selector before any tracker read or render. */
60
+ export function parseDisclosurePolicy(value) {
61
+ if (!object(value) || !Object.hasOwn(value, "profile") || Reflect.ownKeys(value).some(key => key !== "profile" && key !== "exclude") || typeof value.profile !== "string" || !Object.hasOwn(LEVEL, value.profile))
62
+ return invalidPolicy();
63
+ if (value.exclude !== undefined && (!Array.isArray(value.exclude) || value.exclude.length > FIELDS.size || value.exclude.some(field => typeof field !== "string" || !FIELDS.has(field))))
64
+ return invalidPolicy();
65
+ return { profile: value.profile, exclude: value.exclude === undefined ? [] : [...new Set(value.exclude)] };
66
+ }
67
+ /** Bound the entire native JSON/TOON envelope, including framing and diagnostics. */
68
+ function budget(options) {
69
+ const amount = options.tokenBudget ?? 8000;
70
+ if (!Number.isSafeInteger(amount) || amount < 1 || amount > 64000 || (options.dryRun !== undefined && typeof options.dryRun !== "boolean"))
71
+ throw new DisclosureError("invalid", "Invalid disclosure controls", "Use a boolean dryRun and an integer --token-budget from 1 to 64000 (default 8000)");
72
+ return amount;
73
+ }
74
+ /** Account for the complete manifest after both source and render exclusions. */
75
+ function bounded(result, limit) {
76
+ result.estimatedTokenCeiling = 64000;
77
+ result.estimatedTokenCeiling = estimatePmOutputTokens(Buffer.byteLength(JSON.stringify(result, null, 2)) * 2 + 256);
78
+ if (result.estimatedTokenCeiling > limit)
79
+ throw new DisclosureError("budget", "Disclosure and its exclusion manifest exceed the token budget", "Increase --token-budget (maximum 64000) or supply a smaller brief; no exclusion evidence is silently dropped");
80
+ return result;
81
+ }
82
+ /** Render the same brief through a closed field vocabulary before native serialization. */
83
+ export function renderDisclosureBrief(brief, input, options = {}) {
84
+ const policy = parseDisclosurePolicy(input);
85
+ const limit = budget(options);
86
+ if (!object(brief))
87
+ throw new DisclosureError("invalid", "Invalid brief", "Supply the object returned by buildBrief; arbitrary scalar or array input is not a brief");
88
+ const exclusions = { profile: {}, policy: {}, secret: {}, unknown_field: {}, invalid_value: {} };
89
+ const denied = new Set(policy.exclude);
90
+ const active = new Set();
91
+ /** Aggregate repeated policy paths without source values or redundant per-row metadata. */
92
+ function exclude(reason, path) { exclusions[reason][path] = (exclusions[reason][path] ?? 0) + 1; }
93
+ /** Traverse only known containers; never expose unknown key text or scan diagnostics. */
94
+ function walk(value, segments, path) {
95
+ if (typeof value === "object" && value !== null && active.has(value))
96
+ throw new DisclosureError("invalid", "Invalid recursive brief", "Supply an acyclic buildBrief result; known containers have a fixed vocabulary and nesting shape");
97
+ const matches = FIELD_PATHS.filter(entry => matchesDisclosurePath(entry.segments, segments));
98
+ const exact = matches.find(entry => entry.segments.length === segments.length);
99
+ if (exact !== undefined) {
100
+ const { field, level } = exact;
101
+ if (level > LEVEL[policy.profile]) {
102
+ exclude("profile", `/${field.replaceAll(".", "/")}`);
103
+ return undefined;
104
+ }
105
+ if (denied.has(field)) {
106
+ exclude("policy", `/${field.replaceAll(".", "/")}`);
107
+ return undefined;
108
+ }
109
+ if (!(typeof value === "string" || typeof value === "boolean" || (typeof value === "number" && Number.isFinite(value)))) {
110
+ exclude("invalid_value", path);
111
+ return undefined;
112
+ }
113
+ if (scanMutationSecrets(value).length > 0) {
114
+ exclude("secret", path);
115
+ return undefined;
116
+ }
117
+ return value;
118
+ }
119
+ if (matches.length === 0) {
120
+ exclude("unknown_field", path);
121
+ return undefined;
122
+ }
123
+ if (Array.isArray(value)) {
124
+ active.add(value);
125
+ const result = [];
126
+ for (let i = 0; i < value.length; i++) {
127
+ const entry = walk(value[i], [...segments, i], `${path}/${i}`);
128
+ if (entry !== undefined)
129
+ result.push(entry);
130
+ }
131
+ active.delete(value);
132
+ return result;
133
+ }
134
+ if (object(value)) {
135
+ active.add(value);
136
+ const result = {};
137
+ for (const [i, [key, entry]] of Object.entries(value).entries()) {
138
+ if (entry === undefined)
139
+ continue;
140
+ const child = [...segments, key];
141
+ const known = FIELD_PATHS.some(field => matchesDisclosurePath(field.segments, child));
142
+ const rendered = walk(entry, child, `${path}/${known ? key : `@${i}`}`);
143
+ if (rendered !== undefined)
144
+ result[key] = rendered;
145
+ }
146
+ active.delete(value);
147
+ return result;
148
+ }
149
+ exclude("invalid_value", path);
150
+ return undefined;
151
+ }
152
+ const filtered = walk(brief, [], "");
153
+ const result = { protocol: "pm-brief.disclosure/v1", profile: policy.profile, dryRun: options.dryRun ?? false, sourceTruncated: brief.budget?.truncated === true, exclusions, estimatedTokenCeiling: 64000 };
154
+ if (!result.dryRun)
155
+ result.brief = filtered;
156
+ return bounded(result, limit);
157
+ }
158
+ /** Read a certified native snapshot and reuse pm-brief ranking before disclosure. */
159
+ export async function buildDisclosureBrief(input, options) {
160
+ const policy = parseDisclosurePolicy(input);
161
+ budget(options);
162
+ let brief;
163
+ const sourceSecrets = {};
164
+ try {
165
+ const client = options.client ?? new PmClient({ pmRoot: options.pmRoot, noExtensions: true });
166
+ const items = certifyCompleteListResult(await client.listAllComplete({ includeBody: true })).items;
167
+ // Guard before compaction: a shortened credential may no longer match its detector.
168
+ const protectedItems = items.flatMap((item, i) => {
169
+ if (scanMutationSecrets(item.id).length) {
170
+ sourceSecrets[`/source/${i}`] = 1;
171
+ return [];
172
+ }
173
+ const safe = { ...item };
174
+ for (const [j, [field, value]] of Object.entries(item).entries()) {
175
+ if (scanMutationSecrets(value).length) {
176
+ delete safe[field];
177
+ sourceSecrets[`/source/${i}/@${j}`] = 1;
178
+ }
179
+ }
180
+ return [safe];
181
+ });
182
+ const statusRegistry = resolveRuntimeStatusRegistry((await readSettings(options.pmRoot)).schema);
183
+ brief = buildBrief(protectedItems, { pmRoot: ".agents/pm", generatedAt: options.generatedAt, statusRegistry });
184
+ }
185
+ catch {
186
+ throw new DisclosureError("tracker", "Cannot build a certified disclosure brief", "Run pm health and resolve unreadable or incomplete records before retrying");
187
+ }
188
+ const result = renderDisclosureBrief(brief, policy, { ...options, tokenBudget: 64000 });
189
+ Object.assign(result.exclusions.secret, sourceSecrets);
190
+ return bounded(result, budget(options));
191
+ }
192
+ /** Register native structured output and sanitized expected errors, with no git dependency. */
193
+ export function registerDisclosureCommand(api) {
194
+ api.registerCommand({
195
+ name: "brief disclose",
196
+ description: "Render a brief for an explicit stakeholder profile with a value-free exclusion manifest",
197
+ flags: [
198
+ { long: "--audience", type: "string", value_name: "audience", description: "Required audience: internal, external or public (or supply --policy)" },
199
+ { long: "--policy", type: "string", value_name: "file", description: "JSON policy containing profile and optional exclude; cannot widen a profile" },
200
+ { long: "--dry-run", type: "boolean", description: "Explain exclusions without returning brief values" },
201
+ { long: "--token-budget", type: "string", value_name: "n", description: "Conservative complete JSON/TOON ceiling (default 8000; maximum 64000)" },
202
+ ],
203
+ async run(ctx) {
204
+ try {
205
+ if (ctx.args.length || (ctx.options.audience !== undefined && ctx.options.policy !== undefined))
206
+ return invalidPolicy();
207
+ let policy;
208
+ if (ctx.options.policy !== undefined) {
209
+ try {
210
+ policy = parseDisclosurePolicy(JSON.parse(await readFile(String(ctx.options.policy), "utf8")));
211
+ }
212
+ catch {
213
+ return invalidPolicy();
214
+ }
215
+ }
216
+ else
217
+ policy = parseDisclosurePolicy({ profile: ctx.options.audience });
218
+ return await buildDisclosureBrief(policy, { pmRoot: ctx.pm_root, client: ctx.sdk?.client, dryRun: ctx.options.dryRun, tokenBudget: ctx.options.tokenBudget === undefined ? undefined : Number(ctx.options.tokenBudget) });
219
+ }
220
+ catch (error) {
221
+ const refusal = DisclosureError.from(error);
222
+ throw createPmCliExpectedError(`disclosure ${refusal.code}: ${refusal.message}. Remedy: ${refusal.remedy}`, { exitCode: 2, context: { code: `disclosure_${refusal.code}`, required: refusal.remedy } });
223
+ }
224
+ },
225
+ });
226
+ }
227
+ //# sourceMappingURL=disclosure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disclosure.js","sourceRoot":"","sources":["../disclosure.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export { buildDisclosureBrief, renderDisclosureBrief, parseDisclosurePolicy, DisclosureError } from "./disclosure.ts";
2
+ export type { DisclosureProfile, DisclosureField, DisclosurePolicy, DisclosureValue, DisclosureExclusionReason, DisclosureExclusion, DisclosureResult, DisclosureRenderOptions, DisclosureOptions, DisclosureRefusalCode } from "./disclosure.ts";
1
3
  export { buildDecisionAlternatives, DecisionAlternativesError } from "./alternatives.ts";
2
4
  export type { DecisionExcerpt, DecisionAlternative, DecisionAlternativesDigest, DecisionAlternativesOptions, DecisionAlternativesRefusalCode } from "./alternatives.ts";
3
5
  export { previewHandoff, createHandoff, acknowledgeHandoff, inspectHandoff, parseHandoffContract, parseHandoffResponse, HandoffError } from "./handoff.ts";
@@ -7,6 +9,7 @@ import type { ExtensionApi } from "@unbrained/pm-cli/sdk/authoring";
7
9
  import type { SimilarItemMatch } from "@unbrained/pm-cli/sdk";
8
10
  import type { SecretGuardFinding } from "@unbrained/pm-cli/sdk/governance";
9
11
  import type { MergeDecisionReceipt, MergePreferredSide } from "@unbrained/pm-cli/sdk/merge";
12
+ import { type RuntimeStatusRegistry } from "@unbrained/pm-cli/sdk";
10
13
  export type { SimilarItemMatch } from "@unbrained/pm-cli/sdk";
11
14
  export type { DuplicateCluster, SecretGuardFinding, StorageIntegrityScanResult, StaleInProgressScan, } from "@unbrained/pm-cli/sdk/governance";
12
15
  export type { MergeDecisionReceipt, MergePreferredSide } from "@unbrained/pm-cli/sdk/merge";
@@ -84,10 +87,12 @@ export interface PmItem {
84
87
  files?: unknown;
85
88
  [key: string]: unknown;
86
89
  }
87
- /** Renderings whose complete character estimate can be budgeted by buildBrief. */
90
+ /** Renderings whose complete UTF-8 byte estimate can be budgeted by buildBrief. */
88
91
  export type BriefFormat = "json" | "markdown" | "prompt" | "slack";
89
92
  /** Selection and rendering controls for a brief whose output must fit the requested ceiling. */
90
93
  export interface BriefOptions {
94
+ /** Workspace lifecycle roles; omitted library calls use the SDK core defaults. */
95
+ statusRegistry?: RuntimeStatusRegistry;
91
96
  /** Rendering to budget, including whitespace and disclosure (default: json). */
92
97
  format?: BriefFormat;
93
98
  tokenBudget?: number;
@@ -464,6 +469,8 @@ interface Relationship {
464
469
  from: string;
465
470
  to: string;
466
471
  kind: string;
472
+ source_kind?: string;
473
+ external?: boolean;
467
474
  }
468
475
  /** Collect dependency relationships from item metadata for ranking and blocker summaries. */
469
476
  export declare function extractRelationships(item: PmItem): Relationship[];
@@ -611,6 +618,7 @@ export declare function parseActivitySinceOutput(output: string): DeltaActivityE
611
618
  */
612
619
  export declare function buildDelta(entries: DeltaActivityEntry[], itemsById: Map<string, PmItem>, options?: {
613
620
  since: string;
621
+ statusRegistry?: RuntimeStatusRegistry;
614
622
  until?: string;
615
623
  author?: string;
616
624
  generatedAt?: string;
@@ -994,6 +1002,8 @@ export interface DuplicatePair {
994
1002
  }
995
1003
  /** Options controlling which items are scanned and how pairs are ranked/truncated. */
996
1004
  export interface DuplicateSweepOptions {
1005
+ /** Lifecycle registry used by duplicate remediation. */
1006
+ statusRegistry?: RuntimeStatusRegistry;
997
1007
  /** Inclusive similarity threshold on the 0..1 scale (default 0.6). */
998
1008
  threshold?: number;
999
1009
  /** Maximum pairs to report, after ranking (default 20). */
@@ -1054,14 +1064,14 @@ export declare function parseDuplicateThreshold(raw: string | undefined, fallbac
1054
1064
  * `created_at`) as canonical and relate the newer to it, falling back to id
1055
1065
  * ordering when creation timestamps are missing.
1056
1066
  */
1057
- export declare function duplicateRemediationCommand(a: DuplicatePairItem, b: DuplicatePairItem): string;
1067
+ export declare function duplicateRemediationCommand(a: DuplicatePairItem, b: DuplicatePairItem, statusRegistry?: RuntimeStatusRegistry): string;
1058
1068
  /**
1059
1069
  * Collapse raw per-candidate similarity matches into unordered pairs. When A
1060
1070
  * matches B and B matches A, a single pair keyed on the stable sorted-id pair is
1061
1071
  * emitted and keeps the highest score (and that score's reason) seen in either
1062
1072
  * direction. Pairs are ranked by score descending then pair id for stable output.
1063
1073
  */
1064
- export declare function collapseDuplicatePairs(candidates: readonly PmItem[], matchesByCandidate: ReadonlyMap<string, readonly SimilarItemMatch[]>, itemsById: ReadonlyMap<string, PmItem>): DuplicatePair[];
1074
+ export declare function collapseDuplicatePairs(candidates: readonly PmItem[], matchesByCandidate: ReadonlyMap<string, readonly SimilarItemMatch[]>, itemsById: ReadonlyMap<string, PmItem>, statusRegistry?: RuntimeStatusRegistry): DuplicatePair[];
1065
1075
  /**
1066
1076
  * Score every candidate against the tracker with the shared SDK similarity
1067
1077
  * primitive, running at most {@link DUPLICATE_SCAN_CONCURRENCY} scans at a time.