pm-github 2026.10.14 → 2026.10.16

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,23 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026.10.16 - 2026-10-16
4
+
5
+ ### Added
6
+
7
+ - Add a reusable gated closeout PR workflow ([pm-github-0x3y](https://github.com/unbraind/pm-github/blob/main/.agents/pm/tasks/pm-github-0x3y.toon))
8
+ - Let reusable sync choose its npm project directory ([pm-github-z5z1](https://github.com/unbraind/pm-github/blob/main/.agents/pm/features/pm-github-z5z1.toon))
9
+
10
+ ### Fixed
11
+
12
+ - Refuse reusable sync runs outside the caller default branch ([pm-github-q4uz](https://github.com/unbraind/pm-github/blob/main/.agents/pm/issues/pm-github-q4uz.toon))
13
+
14
+ ## 2026.10.15 - 2026-10-15
15
+
16
+ ### Added
17
+
18
+ - Close pm items delivered by merged pull requests with verifiable GitHub evidence ([pm-github-t4i2](https://github.com/unbraind/pm-github/blob/main/.agents/pm/features/pm-github-t4i2.toon))
19
+ - Regenerate caller changelogs and dispatch required CI for gated sync PRs ([pm-github-wrmt](https://github.com/unbraind/pm-github/blob/main/.agents/pm/features/pm-github-wrmt.toon))
20
+
3
21
  ## 2026.10.14 - 2026-10-14
4
22
 
5
23
  ### Added
package/README.md CHANGED
@@ -17,6 +17,109 @@ pm install npm:pm-github --global
17
17
  > `github.com/unbraind/pm-github` source cannot work either — pm copies a GitHub
18
18
  > source as-is without building it, and this repository does not commit `dist/`.
19
19
 
20
+ ## Close items delivered by merged pull requests
21
+
22
+ Agents can use `pm github closeout` to replace manual post-merge tracker cleanup.
23
+ It resolves `--repo` or `PM_GITHUB_REPO` through the existing
24
+ repository resolver, and uses the normal `GITHUB_TOKEN` / `GH_TOKEN` / `gh auth`
25
+ token resolution. Use repeatable `--pr` numbers **or** `--since` with an ISO date
26
+ or timestamp including a timezone. `--since` selects merge times inclusively,
27
+ drains the closed-PR listing, and verifies each selected PR individually.
28
+
29
+ ```sh
30
+ # Agent: inspect the plan first. No tracker writes happen by default.
31
+ pm github closeout --repo owner/repo --pr 42 --pr 43 --skip pm-deferred --json
32
+ # Apply the reviewed selection; repeatable --skip always excludes those ids.
33
+ pm github closeout --repo owner/repo --pr 42 --pr 43 --skip pm-deferred --apply
34
+ # Incremental sweep, including merges exactly at the cutoff.
35
+ PM_GITHUB_REPO=owner/repo pm github closeout --since 2026-10-01T00:00:00Z --json
36
+ ```
37
+
38
+ Only `https://github.com/owner/repo/blob/main/.agents/pm/<folder>/<id>.toon`
39
+ links in PR bodies are recognized. Percent-encoded names and nested SDK tracker
40
+ folders are supported; malformed encodings and traversal segments are ignored. Repository comparisons ignore case. Links to
41
+ other repositories, unknown ids, closed/canceled items and `--skip` ids produce
42
+ explicit skip rows. Bare ids and `pm:` trailers are not supported. If several
43
+ selected PRs reference one item, the lowest PR number supplies its evidence and
44
+ later references are skipped.
45
+
46
+ **A mention is not delivery.** PR bodies routinely link follow-ups, epics and
47
+ related work for context, so a link alone never closes an item. An item is
48
+ closed only when:
49
+
50
+ - it is `in_progress` (claimed work), **or** its link is preceded on the same
51
+ line by a GitHub-style closing keyword: `Closes`, `Fixes`, `Resolves` or
52
+ `Delivers` (and their tense forms), for example `- Closes [pm-x](…/pm-x.toon)`;
53
+ - it is not an `Epic`; epics close when their children are done;
54
+ - it has no non-terminal child items.
55
+
56
+ Each refused item gets a skip row naming the rule, so the plan shows why
57
+ deferred follow-ups stay open. `--skip` still excludes any id unconditionally. Items are read through a certified complete SDK
58
+ corpus, including terminal items.
59
+
60
+ A PR must be merged and have complete merge facts. Required head checks from
61
+ classic branch protection and active branch rulesets must conclude **success**;
62
+ missing, pending, neutral, skipped, failed or app-mismatched required checks
63
+ prevent closure. Required legacy commit-status contexts must succeed too, using their
64
+ latest status. Check-run, status and ruleset pages are fully read. Rulesets are
65
+ read through GitHub's [effective branch rules API](https://docs.github.com/en/rest/repos/rules#get-rules-for-a-branch).
66
+ The check policy reflects the rules readable at invocation time.
67
+
68
+ When a protection source is unreadable (HTTP 403/404), or no required contexts
69
+ are configured, the report labels the **fallback** rule. Every readable required
70
+ context still must conclude success, including its app binding. The fallback
71
+ additionally requires at least one head check run, every run completed with
72
+ `success`, `neutral` or `skipped`, and successful latest legacy head statuses.
73
+ It never discards a known requirement because another source is unreadable.
74
+ Missing, malformed or incomplete head evidence, malformed metadata and other
75
+ metadata errors fail closed. The plan reports which rule was used.
76
+
77
+ TOON lists actionable `close`/`refuse` rows individually and summarizes routine skips
78
+ as counts by stable code, for example `skipped: {already_terminal: 30,
79
+ other_repository: 10, duplicate_selection: 5}`. Explicit exclusions use
80
+ `explicit_skip`. Only checks for actionable rows are shown. Use `--full` for every
81
+ plan row and selected PR check. Global `--json` always returns the full shape
82
+ `{command, repo, dry_run, plan, checks, closed, failed}`. Each full plan row is
83
+ `{item, pr, action: "close" | "skip", code, reason}`. Codes distinguish
84
+ `head_evidence_unavailable`, `incomplete_merge`, `head_checks_failed`, and
85
+ `head_checks_passed` without parsing explanations. `checks` reports each PR's rule,
86
+ verdict, explanation and successful check names. Dry-run rows describe intended
87
+ closes; `closed` counts writes only with `--apply`. `--dry-run` overrides
88
+ `--apply`. All API planning finishes before the first SDK close. Individual SDK
89
+ refusals become skip rows containing a diagnostic code (or a generic failure
90
+ class), without raw error prose, paths or lock-owner identities. Remaining
91
+ closes continue; `failed` counts refused writes and `closed` counts successful
92
+ writes. After processing everything, any failed close produces a `CommandError`
93
+ with exit code 1 and the complete JSON report in its message. Eligibility skips
94
+ alone do not fail the command. Inspect the report before retrying.
95
+
96
+ The SDK close reason is a JSON string containing **only** verified facts:
97
+ `{pr, url, merge_commit_sha, head_sha, merged_at, checks}`. `checks` contains the
98
+ sorted unique names that actually succeeded at that head; neutral/skipped runs
99
+ are not described as passed. PR body, title and comments are never persisted.
100
+ For both default and strict close validation, the SDK always receives the three
101
+ structured close fields it supports, without overriding tracker policy:
102
+
103
+ - `resolution`: `Delivered by <PR URL> (merge <sha12>, head <sha12>)`.
104
+ - `expected_result`: the item's own acceptance criteria verbatim when present;
105
+ otherwise `Delivered by the linked pull request, merged after its head check gate passed.`
106
+ - `actual_result`: `Merged at <time>; required checks satisfied; successful head checks:
107
+ <names>` when branch protection or rulesets name required checks (the list holds every
108
+ successful head check, optional ones included). Under the fallback rule (no readable
109
+ required contexts) it reads `Merged at <time>; no readable required checks, so every
110
+ completed head check run had to succeed, be neutral or be skipped; successful checks:
111
+ <names>`, or `…; no check reported success` when only neutral or skipped runs exist.
112
+ Only the verified merge time, the applied check policy and sorted successful check
113
+ names are used; no platform, coverage or test-execution claims are made.
114
+
115
+ Item titles never supply any of these fields. Existing tracker acceptance
116
+ criteria remain the only prose source; PR body and comments supply no field text.
117
+ Completion time is the GitHub merge time. Repeating a completed selection skips
118
+ terminal items and performs zero additional tracker writes. The command edits
119
+ only the tracker; commit it with its history and regenerate the caller's
120
+ changelog in a closeout PR. The [automated closeout workflow](#automated-closeout-workflow)
121
+ performs that daily review-PR preparation for fleet repositories.
122
+
20
123
  ## Revalidate GitHub blockers
21
124
 
22
125
  **Compatibility:** pm-github now requires PM CLI 2026.10.5 or newer for complete
@@ -69,7 +172,7 @@ containing this command before adopting the updated workflow.
69
172
  |---|---|
70
173
  | `importers` | `pm github import <owner/repo>` — idempotent native import pipeline |
71
174
  | `importers` (exporter) | `pm github export` — pm items → GitHub issues (dry-run by default; upsert) |
72
- | `commands` | `pm gh-issues import` (legacy import alias), `pm github sync` (push status), `pm github gate` (fail-closed pre-push privacy gate), `pm github validate` (diagnostics), `pm github project list\|fields\|import\|sync` (Projects v2) |
175
+ | `commands` | `pm gh-issues import` (legacy import alias), `pm github sync` (push status), `pm github gate` (fail-closed pre-push privacy gate), `pm github validate` (diagnostics), `pm github closeout` (verified merged-PR delivery), `pm github project list\|fields\|import\|sync` (Projects v2) |
73
176
  | `schema` | declares `github_url`, `github_number`, `github_state`, `github_author`, `github_created_at`, `github_updated_at` item fields |
74
177
  | `hooks` | `afterCommand` — opt-in sync reminder (`PM_GITHUB_SYNC`) for linked items |
75
178
  | `preflight` | early warning when a mutating github command lacks a token |
@@ -347,9 +450,94 @@ Rendered values are also scanned in memory before mutation, so a known finding c
347
450
 
348
451
  The `gate` receipt reports the verdict, scanned file count, findings, and allowlisted count. With `--json`, successful reports go to stdout; failures use the host CLI's JSON error envelope on stderr, with the redacted gate report serialized in `detail` (`jq ' .detail | fromjson ' gate-error.json`). Unreadable inputs produce a nonzero JSON refusal.
349
452
 
453
+ ## Automated closeout workflow
454
+
455
+ [`.github/workflows/pm-github-closeout.yml`](.github/workflows/pm-github-closeout.yml)
456
+ is a reusable `workflow_call` that opens or updates **one** PR titled
457
+ `chore(pm): close items delivered by merged pull requests` from `pm-github/closeout`.
458
+ Copy [the caller template](docs/closeout-workflow-caller.yml) into the caller's
459
+ workflows directory and replace `RELEASE_COMMIT_SHA` and `RELEASE_VERSION` with a
460
+ reviewed workflow commit and an exact published pm-github version containing
461
+ `github closeout`. The template schedules a daily run and allows manual dispatch.
462
+ Adopting callers is a separate change; the existing sync workflow is unchanged.
463
+
464
+ The workflow resolves the caller's default branch through the repository API,
465
+ with event metadata as fallback, and refuses other run refs before checkout.
466
+ This works for scheduled payloads without a `repository` object and for branches
467
+ such as `trunk` or `release/stable`. The caller's pinned PM CLI comes from
468
+ `npm ci --ignore-scripts` in `npm-project-dir` (default `.`), which must resolve
469
+ inside the workspace and contain `package.json`. The SDK resolves the tracker
470
+ from the repository root. The exact `pm-github-version` is installed and verified.
471
+
472
+ Each run rebuilds the bot branch from the current default branch and invokes
473
+ `pm github closeout --since 1970-01-01 --apply --json`. Scanning all merge history
474
+ avoids losing deliveries during schedule outages; it costs more API reads for
475
+ large repositories. Terminal items are skipped and the command retains its
476
+ normal eligibility, child/epic, required-check and strict-close rules. Full
477
+ closeout reports stay in runner scratch storage. The PR body lists
478
+ actionable rows with item, PR number, action and code, plus skip counts by reason.
479
+ This compact summary passes its own privacy scan before publication. The caller's `post-closeout-script` defaults to `changelog:full`,
480
+ run through `npm run --if-present` in the npm project; empty disables it.
481
+ The script must emit the root `CHANGELOG.md` and remain inside the publication scope.
482
+
483
+ | Safety boundary | Closeout and sync parity |
484
+ | --- | --- |
485
+ | Entry and install | Caller default-branch guard, contained npm project, exact package version, SHA-pinned Actions, no persisted checkout credentials |
486
+ | Proposed publication | SDK-resolved tracker plus root changelog; setup, extension, lock and checkpoint files excluded; every changed path checked |
487
+ | Privacy | Same fail-closed full-context staged-diff scan after the caller script and immediately before commit; unreadable input refuses publication |
488
+ | Validation | Strict PM health; explicit item/history scope committed together |
489
+ | Branch and PR | Explicit force-with-lease against the observed bot ref; push only bot branch; owned PR lookup excludes forks |
490
+ | No-op | Zero closes or no tracker diff creates no remote branch or PR; caller-only drift unpublished; stale owned PR closed |
491
+ | CI | Caller workflow dispatch after PR create/update; parked approval-required runs reported; no merge |
492
+
493
+ `ci-workflows` defaults to `ci.yml`; use whitespace-separated filenames for every
494
+ required caller CI workflow. Each must support `workflow_dispatch` and produce
495
+ its required checks on that event. Missing files are skipped with a notice,
496
+ matching sync; empty disables dispatch. CI dispatch starts checks; it does not
497
+ certify that they passed. Review and required-check enforcement remain with the
498
+ caller's protected branch. A repository concurrency group serializes closeout
499
+ runs, and the explicit lease rejects competing writers.
500
+
501
+ The caller grants only `contents: write`, `pull-requests: write`, `checks: read`
502
+ and `actions: write`. Closeout uses `checks: read` instead of sync's `issues: read`
503
+ to retrieve head-check evidence ([GitHub Checks API permissions](https://docs.github.com/en/rest/checks/runs#list-check-runs-for-a-git-reference)).
504
+ The reusable workflow cannot elevate the caller's token
505
+ permissions ([GitHub reusable workflow permissions](https://docs.github.com/en/actions/reference/workflows-and-actions/reusing-workflow-configurations)).
506
+ Repository Actions settings must allow Actions to create PRs. Read denial stops
507
+ closeout before push with a diagnostic, including unavailable head-check evidence
508
+ reported by the command as a skip when it blocks a local, existing, non-terminal,
509
+ non-excluded tracker item. Unlinked PRs and foreign/terminal/excluded links do
510
+ not fail the run for unavailable evidence. Incomplete merge facts use a separate
511
+ `incomplete_merge` refusal before any head lookup. The pinned extension must
512
+ emit plan decision codes; repin to a release containing this contract. A push/PR denial fails publication and
513
+ CI dispatch denial fails the job explicitly. A PR creation denial may leave the
514
+ gated bot branch pushed, and a dispatch denial leaves the review PR open; neither
515
+ case changes the default branch or merges anything. Explicit dispatch is used
516
+ for reliable caller CI invocation with `GITHUB_TOKEN`
517
+ ([GitHub token event behavior](https://docs.github.com/en/actions/concepts/security/github_token)).
518
+
350
519
  ## Automated sync workflow
351
520
 
352
- Fleet repos sync their issues into pm through ONE audited implementation: the reusable `workflow_call` workflow at [`.github/workflows/pm-github-sync.yml`](.github/workflows/pm-github-sync.yml) in this repository. It runs the gated pipeline in fail-closed order — checkout → install the **pinned** extension → `pm github validate` → dry-run plan → **gated import** → verify the repeat import is a no-op → `pm health --strict-exit` → and only then commit, push the sync branch, and open/update a review PR whose body links every changed item as `https://github.com/<repo>/blob/main/.agents/pm/<folder>/<id>.toon`. Because `--gate` exits non-zero on any finding, the job can never reach the push step with a leak in the change. Actions are pinned by commit SHA; permissions are least-privilege (`contents: write`, `pull-requests: write`, `issues: read`).
521
+ The reusable workflow's first step resolves the caller's default branch using the repository API with the job token, falling back to `github.event.repository.default_branch` only when present. Scheduled payloads need no `repository` object. If neither source provides a valid branch, the job fails closed with a clear error before checkout. It requires `github.ref` to equal `refs/heads/<resolved-default-branch>`. A mismatch fails before checkout or any sync operation with a one-line error naming both refs. Scheduled calls and manual `workflow_dispatch` calls on the default branch are accepted; manual dispatches selecting another branch are refused. Checkout, sync-branch preparation, PR lookup/base and tracker links all use that resolved branch, including defaults such as `trunk` or `release/stable`. Callers need no guard of their own. Repin the reusable workflow to a release commit containing this guard to receive it.
522
+
523
+ Fleet repos sync their issues into pm through ONE audited implementation: the reusable `workflow_call` workflow at [`.github/workflows/pm-github-sync.yml`](.github/workflows/pm-github-sync.yml). Its safety order is validate → dry-run plan → **gated import** → verify the repeat import is a no-op → caller post-import script → **full changed-path scope check and privacy gate** → strict health → repeat scope check and scan immediately before commit/push/review PR → caller CI dispatch. The default `post-import-script` is `changelog:full`, invoked with `npm run --if-present`: it runs the caller's own generator when present, so imported closed issues and their changelog entries land in the same commit. Actions are pinned by commit SHA. The job requests `contents: write`, `pull-requests: write`, `issues: read`, and `actions: write` for dispatch.
524
+
525
+ When the tracker has no changes, regenerated `CHANGELOG.md` drift is discarded and the run emits a notice that the caller's own `changelog:check` owns that drift. The sync closes any owned open review PR and exits successfully without pushing or dispatching CI. Changelog changes are published only together with tracker changes.
526
+
527
+ The explicit allowed scope for changed paths is:
528
+
529
+ - Files beneath the SDK-resolved repository-local pm tracker, excluding its `extensions/`, `locks/`, and `checkpoints/` runtime directories. The extension setup files `settings.json` and `history/_workspace.jsonl` are permitted during setup, then restored before publication and excluded from both the scan and commit.
530
+ - The repository-root `CHANGELOG.md`.
531
+
532
+ After the caller script and again immediately before committing, `git status --porcelain=v1 -z --untracked-files=all` enumerates staged, unstaged, and untracked changes, including both sides of renames. Every path outside this list produces an error and prevents publication. Allowed changes are staged and the privacy gate scans the exact NUL-delimited path list passed to `git commit --only --pathspec-from-file` with literal pathspecs. The final scan is regenerated from current content; any finding, unreadable input, or script failure prevents publication. The restricted commit also excludes unrelated staged content if a scope check is bypassed.
533
+
534
+ Optional inputs:
535
+
536
+ | Input | Default | Behavior |
537
+ | --- | --- | --- |
538
+ | `npm-project-dir` | `.` | Relative npm project directory for `npm ci --ignore-scripts`, the CLI `node_modules/.bin` PATH entry, and `post-import-script`. Must have `package.json`, contain no `..` segments, and resolve inside the workspace (including symlinks); invalid paths fail before caching/install. The tracker and publication scope stay at the repository root. |
539
+ | `post-import-script` | `changelog:full` | Caller npm script name invoked with `npm run --if-present` after import and before the final scan. Override for a different package script, or set `""` to disable. Missing scripts are skipped. Raw shell commands are not accepted. Generated `CHANGELOG.md` is staged with the tracker. Changing any file outside the documented scope fails the run, whether staged, unstaged, or untracked. |
540
+ | `ci-workflows` | `ci.yml` | Whitespace-separated filenames in the caller's `.github/workflows`, for example `ci.yml codeql.yml`. Missing files emit a notice and are skipped; set `""` to disable dispatch. Existing workflows must enable `workflow_dispatch`; dispatch errors fail the sync job. |
353
541
 
354
542
  A fleet repo owns the schedule and calls it with the pinned versions (see [`docs/sync-workflow-caller.yml`](docs/sync-workflow-caller.yml)):
355
543
 
@@ -364,6 +552,7 @@ permissions:
364
552
  contents: write
365
553
  pull-requests: write
366
554
  issues: read
555
+ actions: write
367
556
 
368
557
  jobs:
369
558
  gated-sync:
@@ -372,7 +561,15 @@ jobs:
372
561
  pm-github-version: "RELEASE_VERSION" # required: exact published version
373
562
  ```
374
563
 
375
- Replace the two release placeholders after the gated extension is published; the current published version does not contain this feature. The calling repo needs `@unbrained/pm-cli` as a devDependency (the workflow's `npm ci` provides the CLI) and its pm tracker at `.agents/pm` committed on `main`. Under **Settings → Actions → General → Workflow permissions** it must also allow read and write token permissions and enable **Allow GitHub Actions to create and approve pull requests** (an organization can disable this), or the run pushes the sync branch and then fails to open the review PR. A PR that `GITHUB_TOKEN` opens or edits does not trigger `pull_request` workflows, so the sync PR gets no CI checks until a maintainer re-runs them (for example by closing and reopening the PR); the reusable workflow always uses the job's `GITHUB_TOKEN`.
564
+ Replace the two release placeholders with the release commit and package version containing this change; existing callers must repin both. The selected npm project needs a committed npm lockfile (`package-lock.json` or `npm-shrinkwrap.json`) and `@unbrained/pm-cli` as a devDependency (the workflow's `npm ci` provides the CLI) and its pm tracker at `.agents/pm` committed on the caller's default branch. Under **Settings → Actions → General → Workflow permissions** it must allow read and write token permissions and enable **Allow GitHub Actions to create and approve pull requests** (an organization can disable this), or the run pushes the sync branch and then fails to open the review PR. The caller must grant `actions: write`; a reusable workflow cannot elevate its caller's permissions.
565
+
566
+ For a caller such as `unbraind/pm-rust` with no root `package.json`, add
567
+ `npm-project-dir: tests/oracle` under `with:`. Its `tests/oracle/package.json`
568
+ provides the CLI and post-import npm script; Git and pm tracker operations still
569
+ run from the repository root. A script that regenerates the changelog must write
570
+ the repository-root `CHANGELOG.md` to stay within the publication allowlist.
571
+
572
+ Bot-created review PRs may have missing required checks or `pull_request` runs parked in `action_required`. After a successful push and PR creation/update, the reusable workflow uses the job's `GITHUB_TOKEN` to run `gh workflow run <file> --ref "$SYNC_BRANCH"` for each configured caller CI workflow. Explicit `workflow_dispatch` creates runs on the sync head, so callers must enable that trigger and ensure those runs produce their required check names (and do not restrict the required jobs to the `pull_request` event). It also lists `action_required` runs for the exact pushed SHA and prints their URLs as notices without failing because approval is needed. Missing workflows, disabled dispatch, or approval notices do not establish that required CI passed; inspect the dispatched checks. A no-change sync closes its stale own review PR and dispatches nothing. See GitHub's [GITHUB_TOKEN event rules](https://docs.github.com/en/actions/concepts/security/github_token) and [dispatch trigger and permission requirements](https://docs.github.com/en/rest/actions/workflows#create-a-workflow-dispatch-event).
376
573
 
377
574
  ### Installed CLI timeout acceptance
378
575
 
@@ -0,0 +1,104 @@
1
+ /** Existing GitHub REST transport, supplied by the extension entry point. */
2
+ export interface CloseoutApi {
3
+ base: string;
4
+ get(url: string): Promise<{
5
+ body: string;
6
+ linkHeader?: string;
7
+ }>;
8
+ next(link?: string): string | undefined;
9
+ }
10
+ /** Stable machine-readable decision; reasons never quote pull-request prose. */
11
+ export interface CloseoutRow {
12
+ item: string;
13
+ pr: number;
14
+ action: "close" | "skip";
15
+ reason: string;
16
+ code: CloseoutCode;
17
+ }
18
+ /** Stable decisions used by automation and compact skip counts. */
19
+ export type CloseoutCode = "already_terminal" | "other_repository" | "duplicate_selection" | "explicit_skip" | "unknown_item" | "epic" | "active_children" | "not_delivery" | "close_failed" | "head_checks_passed" | "head_checks_failed" | "head_evidence_unavailable" | "incomplete_merge";
20
+ /** Which head-check policy was evaluated for one selected pull request. */
21
+ interface CheckGate {
22
+ pr: number;
23
+ code: CloseoutCode;
24
+ rule: "required" | "fallback" | "unavailable";
25
+ reason: string;
26
+ passed: string[];
27
+ ok: boolean;
28
+ }
29
+ /** Fields retained from a pull request; its body is used only for extraction. */
30
+ interface PullRequest {
31
+ number: number;
32
+ body: string | null;
33
+ merged: boolean;
34
+ merged_at: string | null;
35
+ merge_commit_sha: string | null;
36
+ html_url: string;
37
+ head: {
38
+ sha: string;
39
+ };
40
+ base: {
41
+ ref: string;
42
+ repo: {
43
+ full_name: string;
44
+ };
45
+ };
46
+ }
47
+ /** Verify required checks or the explicitly reported conservative fallback at the PR head. */
48
+ export declare function checkCloseoutHead(api: CloseoutApi, repo: string, pr: PullRequest): Promise<CheckGate>;
49
+ /**
50
+ * Whether a closing keyword directly precedes a link, given the line text before the link.
51
+ *
52
+ * Only earlier links (markdown or bare), commas and "and" may sit between the keyword and the link, so
53
+ * `Delivers [a](…) and [b](…)` declares both while `Not fixed here; see <link>` declares nothing.
54
+ * Scans backwards with plain string operations; no backtracking pattern touches PR text.
55
+ */
56
+ export declare function declaresDelivery(prefix: string): boolean;
57
+ /** Extract only canonical tracker links, retaining foreign references solely for skip rows. */
58
+ export declare function extractCloseoutItems(body: string): {
59
+ item: string;
60
+ repo: string;
61
+ declared: boolean;
62
+ }[];
63
+ /** Report SDK refusal codes without exposing paths, identities or arbitrary error prose. */
64
+ export declare function closeoutFailureReason(error: unknown): string;
65
+ /** Invalid selectors or repository input: the caller must change the command, so the host maps it to a usage exit. */
66
+ export declare class CloseoutUsageError extends Error {
67
+ }
68
+ /**
69
+ * Describe the verified check evidence for a passed gate without overstating it.
70
+ *
71
+ * The required rule states that the required checks were satisfied and lists every successful head check (optional
72
+ * ones included). The fallback rule (no readable required contexts)
73
+ * may pass on neutral or skipped runs alone, so it states that policy and lists successful checks only when any exist.
74
+ */
75
+ export declare function checkEvidence(gate: CheckGate): string;
76
+ /** Plan all selected PRs before closing eligible items through the real SDK. */
77
+ export declare function runCloseout(pmRoot: string, repo: string | undefined, options: Record<string, unknown>, api: CloseoutApi): Promise<{
78
+ command: string;
79
+ repo: string;
80
+ dry_run: boolean;
81
+ plan: CloseoutRow[];
82
+ checks: CheckGate[];
83
+ closed: number;
84
+ failed: number;
85
+ }>;
86
+ /** Keep actionable decisions and their checks while counting routine skips by stable code. */
87
+ export declare function compactCloseoutReport(report: Awaited<ReturnType<typeof runCloseout>>): {
88
+ command: string;
89
+ repo: string;
90
+ dry_run: boolean;
91
+ closed: number;
92
+ failed: number;
93
+ plan: {
94
+ item: string;
95
+ pr: number;
96
+ reason: string;
97
+ code: CloseoutCode;
98
+ action: string;
99
+ }[];
100
+ skipped: Partial<Record<CloseoutCode, number>>;
101
+ checks: CheckGate[];
102
+ };
103
+ export {};
104
+ //# sourceMappingURL=closeout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"closeout.d.ts","sourceRoot":"","sources":["../closeout.ts"],"names":[],"mappings":"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"}