@toon-protocol/rig 4.2.0 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -231,6 +231,12 @@ interface NostrFilter {
231
231
  '#a'?: string[];
232
232
  /** Event-reference tag filter (#278 tracker: statuses + comments). */
233
233
  '#e'?: string[];
234
+ /** Commit tag filter (#125 CI: results/progress/jobs for one commit). */
235
+ '#c'?: string[];
236
+ /** Addressee tag filter (#125 CI: a coordinator's inbox — 9843/9844/9840/29846). */
237
+ '#p'?: string[];
238
+ /** Only events at or after this unix time (#125 coordinator cursor resume). */
239
+ since?: number;
234
240
  limit?: number;
235
241
  }
236
242
  /**
@@ -1424,4 +1430,737 @@ interface FactoryJobExecution {
1424
1430
  */
1425
1431
  declare function executeFactoryJob(options: ExecuteFactoryJobOptions): Promise<FactoryJobExecution>;
1426
1432
 
1427
- export { type BuildIncrementOfferOptions, type BuildNarrationOptions, type BuildResultEventOptions, type ClosureResult, type CollectRepoObjectsOptions, type CollectRepoObjectsResult, DEFAULT_CONCURRENCY, type DownloadOptions, type DownloadResult, type EncryptedArtifact, type EncryptedArtifactRef, type ExecuteFactoryJobOptions, type ExecutePushOptions, FACTORY_JOB_FEEDBACK_KIND, FACTORY_JOB_REQUEST_KIND, FACTORY_JOB_RESULT_KIND, type FactoryJobExecution, type FactoryJobHooks, type FactoryJobOutcome, type FactoryJobRequest, type FactoryJobWork, type FactoryMilestone, type FactoryTicket, FeeRates, type FetchLike, type FetchRemoteStateOptions, type FetchedObject, type GateCheck, type GateResult, type GatewayFetchOptions, type GitCommentRequest, GitError, type GitErrorEnvelope, type GitEstimateRequest, type GitEstimateResponse, type GitEventResponse, type GitFeeEstimate, type GitIssueRequest, GitObjectType, type GitPatchRequest, type GitPlannedObject, type GitPublishReceipt, type GitPushRequest, type GitPushResponse, type GitRef, type GitRefUpdate, type GitRepoAddr, GitRepoReader, type GitStatusRequest, type GitStatusValue, type GitUploadStep, type IncrementSpec, type JobDeliveryPort, type MissingObject, NonFastForwardError, type NostrEvent, type NostrFilter, ObjectIntegrityError, type ObjectStat, type ObjectWithPath, ObjectWriteMismatchError, type OfferedIncrement, type OversizeObject, OversizeObjectsError, PayoutPointer, type PlanPushOptions, type PlannedObject, PublishReceipt, Publisher, type PushFeeEstimate, type PushPlan, type PushResult, type ReadGitObject, type ReadObjectsResult, type RefUpdate, type RefUpdateKind, type RejectedRefUpdate, type RelayEvent, type RemoteState, type RepoRefs, type StatObjectsResult, UnsignedEvent, type UploadStepResult, type WebSocketFactory, type WebSocketLike, buildIncrementOfferEvent, buildNarrationEvent, buildQuoteEvent, buildResultEvent, collectRepoObjects, downloadGitObjects, executeFactoryJob, executePush, fetchRemoteState, fetchTxBytes, gatePassed, hexToNpub, isSafeRefname, missingObjectsMessage, npubToHex, ownerToHex, parseFactoryJobRequest, planFactoryJob, planPush, queryRelay, referencedShas, serializeEventReceipt, serializeFeeEstimate, serializePushPlan, serializePushResult, setHeadSymref, updateRef, verifyObjectBody, walkClosure, writeGitObject, writeGitObjects };
1433
+ /**
1434
+ * NIP-C1 (Nostr CI) event builders + parsers — the wire layer of rig's
1435
+ * relay-native CI (rig#125, slice 1). The spec is vendored at
1436
+ * docs/specs/nip-c1.md; this module adopts it VERBATIM for kinds, tags,
1437
+ * content, and ordering rules, so ngit tooling keeps reading rig's events and
1438
+ * rig keeps reading ngit-ci's.
1439
+ *
1440
+ * Builders return UnsignedEvent (the Publisher signs — see ../publisher.ts,
1441
+ * the same posture as ../nip34-events.ts). Parsers take a read-side
1442
+ * NostrEvent and return `null` on ANY malformed shape: the relay is
1443
+ * permissionless, so a consumer must never let a hand-crafted event smuggle a
1444
+ * meaning the spec does not give it (an unknown `X` policy is NOT automatic
1445
+ * service; a request naming another coordinator is NOT ours; a trigger whose
1446
+ * `a` tags name two repo ids is NOT a run).
1447
+ *
1448
+ * rig's deliberate departures from the ngit reference, all within the spec:
1449
+ * - `["software","rig","<version>"]` on the Advertisement;
1450
+ * - Advertisement policy `M=maintainer-request`, `X=request-required`,
1451
+ * `B=out-of-band` (the coordinator is funded by its operator);
1452
+ * - logs/artifacts are TOON store gateway URLs, not Blossom (the tag
1453
+ * shapes are identical — only the URL host differs);
1454
+ * - PR context may carry `K`/`k` = 1617: `rig pr create` publishes NIP-34
1455
+ * patches, so a 1617 is the PR shape rig's own contributors produce.
1456
+ */
1457
+
1458
+ declare const CI_ADVERTISEMENT_KIND = 19843;
1459
+ declare const CI_SERVICE_REQUEST_KIND = 9843;
1460
+ declare const CI_SERVICE_STOP_KIND = 9844;
1461
+ declare const CI_SECRET_UPDATE_KIND = 29846;
1462
+ declare const CI_MANUAL_TRIGGER_KIND = 9840;
1463
+ declare const CI_JOB_RESULT_KIND = 9841;
1464
+ declare const CI_WORKFLOW_RESULT_KIND = 9842;
1465
+ declare const CI_WORKFLOW_PROGRESS_KIND = 39842;
1466
+ /** The one runner family rig supports (`W` tag / `R` prefix). */
1467
+ declare const CI_RUNNER_FAMILY = "act";
1468
+ /** The `software` tag name rig advertises under. */
1469
+ declare const CI_SOFTWARE = "rig";
1470
+ /** NIP-40 bound on Advertisement + Progress lifetime (seconds). */
1471
+ declare const CI_MAX_ADVERTISEMENT_TTL: number;
1472
+ declare const CI_MAX_PROGRESS_TTL: number;
1473
+ type CiConclusion = 'success' | 'failure' | 'neutral' | 'cancelled' | 'skipped' | 'timed_out' | 'startup_failure';
1474
+ declare function isCiConclusion(value: string): value is CiConclusion;
1475
+ type CiProgressStatus = 'queued' | 'in_progress' | 'concluded';
1476
+ /** Normalized trigger reasons rig runs (`schedule` is out of scope). */
1477
+ type CiTriggerReason = 'push' | 'pull_request' | 'manual';
1478
+ type CiAdmissionPolicy = 'operator-selected' | 'maintainer-request' | 'open';
1479
+ type CiExecutionPolicy = 'automatic' | 'request-required';
1480
+ type CiBillingPolicy = 'not-required' | 'out-of-band';
1481
+ /** Repo address string `30617:<owner-hex>:<repo-id>`. */
1482
+ type RepoAddress = string;
1483
+ declare function repoAddress(ownerPubkey: string, repoId: string): RepoAddress;
1484
+ declare function parseRepoAddress(a: string): {
1485
+ ownerPubkey: string;
1486
+ repoId: string;
1487
+ } | null;
1488
+ interface CiWorkflowRef {
1489
+ /** Workflow file path, relative to the repo root (`w` tag). */
1490
+ path: string;
1491
+ /** SHA-256 (hex) of the workflow file content at the run's commit. */
1492
+ sha256: string;
1493
+ }
1494
+ /**
1495
+ * NIP-22 PR context of a `pull_request` run: the PR event as root (`E`/`K`/
1496
+ * `P`) and the PR or PR-update event that supplied the commit as parent
1497
+ * (`e`/`k`/`p`). `prKind`/`sourceKind` 1617 is rig's departure — see the
1498
+ * module header.
1499
+ */
1500
+ interface CiPrContext {
1501
+ prEventId: string;
1502
+ prAuthor: string;
1503
+ prKind: 1617 | 1618;
1504
+ sourceEventId: string;
1505
+ sourceAuthor: string;
1506
+ sourceKind: 1617 | 1618 | 1619;
1507
+ }
1508
+ interface CiTriggerContext {
1509
+ /** The repo the run is for — the FIRST `a` tag. */
1510
+ repoAddr: RepoAddress;
1511
+ /** Further `a` tags: the same repo id under other maintainers' announcements. */
1512
+ extraRepoAddrs?: string[];
1513
+ /** The commit the workflow ran against — the FIRST `c` tag. */
1514
+ commit: string;
1515
+ /** Extra `c` tags: annotated tag object ids peeling to `commit`. */
1516
+ tagObjectIds?: string[];
1517
+ workflow: CiWorkflowRef;
1518
+ reason: CiTriggerReason;
1519
+ /** `r` tag — push runs (and optionally manual runs); never with `pr`. */
1520
+ ref?: string;
1521
+ pr?: CiPrContext;
1522
+ }
1523
+ /** The frozen request-provenance quote a run carries (`q … service-request|manual-trigger`). */
1524
+ type CiProvenance = {
1525
+ kind: 'service-request';
1526
+ eventId: string;
1527
+ relayUrl: string;
1528
+ pubkey: string;
1529
+ } | {
1530
+ kind: 'manual-trigger';
1531
+ eventId: string;
1532
+ relayUrl: string;
1533
+ pubkey: string;
1534
+ };
1535
+ /** The common + trigger-context tags (`a*`, `c*`, `w`, `o`, then `r` | `E K P e k p`). */
1536
+ declare function commonTriggerTags(trigger: CiTriggerContext): string[][];
1537
+ /**
1538
+ * Parse the common + trigger-context tags. `defaultReason` supplies the
1539
+ * reason when no `o` tag is present (Manual Triggers omit it and are always
1540
+ * `manual`); without it a missing `o` is malformed.
1541
+ */
1542
+ declare function parseCiTriggerContext(tags: string[][], opts?: {
1543
+ defaultReason?: CiTriggerReason;
1544
+ }): CiTriggerContext | null;
1545
+ interface CiAdvertisementInput {
1546
+ version: string;
1547
+ /** Accepted `act` selectors (emitted as `R = act:<selector>`). */
1548
+ selectors: string[];
1549
+ admission: CiAdmissionPolicy;
1550
+ execution: CiExecutionPolicy;
1551
+ billing?: CiBillingPolicy;
1552
+ secretsKey?: {
1553
+ pubkey: string;
1554
+ inboxRelays: string[];
1555
+ };
1556
+ /** NIP-40 expiration: > created_at, ≤ created_at + 30 min. */
1557
+ expiresAt: number;
1558
+ }
1559
+ interface CiAdvertisement {
1560
+ eventId: string;
1561
+ pubkey: string;
1562
+ createdAt: number;
1563
+ version: string;
1564
+ /** Supported runner families (`W`), case-folded + deduplicated. */
1565
+ families: string[];
1566
+ /** Accepted `<family>:<selector>` values (`R`), case-folded + deduplicated. */
1567
+ selectors: string[];
1568
+ admission: CiAdmissionPolicy;
1569
+ execution: CiExecutionPolicy;
1570
+ billing?: CiBillingPolicy;
1571
+ secretsKey?: {
1572
+ pubkey: string;
1573
+ inboxRelays: string[];
1574
+ };
1575
+ expiresAt: number;
1576
+ }
1577
+ declare function buildCiAdvertisement(input: CiAdvertisementInput, createdAt?: number): UnsignedEvent;
1578
+ declare function parseCiAdvertisement(ev: NostrEvent): CiAdvertisement | null;
1579
+ interface ServiceControl {
1580
+ kind: 'request' | 'stop';
1581
+ eventId: string;
1582
+ pubkey: string;
1583
+ createdAt: number;
1584
+ repoAddr: RepoAddress;
1585
+ coordinatorPubkey: string;
1586
+ relayHint?: string;
1587
+ }
1588
+ declare function buildCiServiceRequest(repoAddr: RepoAddress, coordinatorPubkey: string, relayHint?: string, createdAt?: number): UnsignedEvent;
1589
+ declare function buildCiServiceStop(repoAddr: RepoAddress, coordinatorPubkey: string, relayHint?: string, createdAt?: number): UnsignedEvent;
1590
+ declare function parseCiServiceControl(ev: NostrEvent): ServiceControl | null;
1591
+ /**
1592
+ * NIP-C1 total order for controls (and secret updates): a greater
1593
+ * `created_at` is later; at equal timestamps the lexicographically LOWER
1594
+ * event id is later. Returns <0 when `a` is earlier than `b`.
1595
+ */
1596
+ declare function controlOrder(a: {
1597
+ createdAt: number;
1598
+ eventId: string;
1599
+ }, b: {
1600
+ createdAt: number;
1601
+ eventId: string;
1602
+ }): number;
1603
+ interface SelectServiceRequestsOptions {
1604
+ coordinatorPubkey: string;
1605
+ /** When given, controls for other repo addresses are ignored. */
1606
+ repoAddr?: RepoAddress;
1607
+ /** Current owner ∪ maintainers (lowercase hex) — the accepted requesters. */
1608
+ authorized: Set<string>;
1609
+ /**
1610
+ * Extra requester pubkeys the operator explicitly accepts (NIP-C1: "an
1611
+ * operator MAY explicitly accept other requester pubkeys"). Their Requests
1612
+ * count, but they stay non-maintainers: their Stops close only their own
1613
+ * Requests, and runs they cause carry lower trust.
1614
+ */
1615
+ acceptedRequesters?: Set<string>;
1616
+ }
1617
+ interface SelectedServiceRequests {
1618
+ /** The newest accepted, unstopped Request — service is eligible iff non-null. */
1619
+ active: ServiceControl | null;
1620
+ /** Every accepted Request still open, earliest first. */
1621
+ open: ServiceControl[];
1622
+ }
1623
+ /**
1624
+ * Reduce the Service Request / Stop history for one coordinator + repo
1625
+ * perspective under the default policy (only current maintainers' Requests
1626
+ * are accepted). A maintainer's Stop closes every earlier Request; any other
1627
+ * author's Stop closes only that author's own earlier Requests — so a removed
1628
+ * maintainer keeps the author-local effect but loses the repo-wide one.
1629
+ */
1630
+ declare function selectServiceRequests(controls: ServiceControl[], opts: SelectServiceRequestsOptions): SelectedServiceRequests;
1631
+ interface CiManualTrigger {
1632
+ eventId: string;
1633
+ pubkey: string;
1634
+ createdAt: number;
1635
+ coordinatorPubkey: string;
1636
+ trigger: Omit<CiTriggerContext, 'reason'>;
1637
+ }
1638
+ declare function buildCiManualTrigger(coordinatorPubkey: string, trigger: Omit<CiTriggerContext, 'reason'>, createdAt?: number): UnsignedEvent;
1639
+ /**
1640
+ * Parse a Manual Trigger. With `coordinatorPubkey` given, a request addressed
1641
+ * to any other coordinator is ignored (`null`). The ONLY lowercase `p` on a
1642
+ * Manual Trigger is the coordinator — a second one is malformed.
1643
+ */
1644
+ declare function parseCiManualTrigger(ev: NostrEvent, coordinatorPubkey?: string): CiManualTrigger | null;
1645
+ interface CiSecretUpdateArgs {
1646
+ repoAddr: RepoAddress;
1647
+ coordinatorPubkey: string;
1648
+ advertisementId: string;
1649
+ advertisementRelayHint?: string;
1650
+ senderPubkey: string;
1651
+ recipientPubkey: string;
1652
+ ciphertext: string;
1653
+ createdAt: number;
1654
+ }
1655
+ interface CiSecretUpdate {
1656
+ eventId: string;
1657
+ pubkey: string;
1658
+ createdAt: number;
1659
+ repoAddr: RepoAddress;
1660
+ coordinatorPubkey: string;
1661
+ advertisementId: string;
1662
+ senderPubkey: string;
1663
+ recipientPubkey: string;
1664
+ ciphertext: string;
1665
+ }
1666
+ declare function buildCiSecretUpdate(args: CiSecretUpdateArgs): UnsignedEvent;
1667
+ declare function parseCiSecretUpdate(ev: NostrEvent): CiSecretUpdate | null;
1668
+ interface CiArtifact {
1669
+ url: string;
1670
+ filename: string;
1671
+ name: string;
1672
+ }
1673
+ interface CiJobResultInput {
1674
+ trigger: CiTriggerContext;
1675
+ /** `39842:<coordinator>:<runId>` — the run's Workflow Progress address. */
1676
+ progressAddress: string;
1677
+ /** Relay the Progress event was published to (the `q` relay hint). */
1678
+ relayUrl: string;
1679
+ jobId: string;
1680
+ name?: string;
1681
+ conclusion: CiConclusion;
1682
+ logsUrl: string;
1683
+ logTail: string;
1684
+ logOmittedBytes: number;
1685
+ artifacts?: CiArtifact[];
1686
+ queuedAt?: number;
1687
+ startedAt?: number;
1688
+ exitCode?: number;
1689
+ runsOn?: string[];
1690
+ /** MAY be carried on a Job Result (never a service-request by rig's coordinator). */
1691
+ provenance?: CiProvenance;
1692
+ }
1693
+ interface CiJobResult {
1694
+ eventId: string;
1695
+ pubkey: string;
1696
+ createdAt: number;
1697
+ trigger: CiTriggerContext;
1698
+ progressAddress: string;
1699
+ jobId: string;
1700
+ name?: string;
1701
+ conclusion: CiConclusion;
1702
+ logsUrl?: string;
1703
+ logTail: string;
1704
+ logOmittedBytes: number;
1705
+ artifacts: CiArtifact[];
1706
+ queuedAt?: number;
1707
+ startedAt?: number;
1708
+ exitCode?: number;
1709
+ runsOn: string[];
1710
+ provenance?: CiProvenance;
1711
+ }
1712
+ declare function buildCiJobResult(input: CiJobResultInput, createdAt?: number): UnsignedEvent;
1713
+ declare function parseCiJobResult(ev: NostrEvent): CiJobResult | null;
1714
+ /** A `q` quote of one Job Result (job id as the marker). */
1715
+ interface CiJobQuote {
1716
+ eventId: string;
1717
+ relayUrl: string;
1718
+ pubkey: string;
1719
+ jobId: string;
1720
+ }
1721
+ interface CiWorkflowResultInput {
1722
+ trigger: CiTriggerContext;
1723
+ runId: string;
1724
+ conclusion: CiConclusion;
1725
+ queuedAt?: number;
1726
+ startedAt?: number;
1727
+ provenance?: CiProvenance;
1728
+ jobs: CiJobQuote[];
1729
+ }
1730
+ interface CiWorkflowResult {
1731
+ eventId: string;
1732
+ pubkey: string;
1733
+ createdAt: number;
1734
+ trigger: CiTriggerContext;
1735
+ runId: string;
1736
+ conclusion: CiConclusion;
1737
+ queuedAt?: number;
1738
+ startedAt?: number;
1739
+ provenance?: CiProvenance;
1740
+ jobs: CiJobQuote[];
1741
+ }
1742
+ declare function buildCiWorkflowResult(input: CiWorkflowResultInput, createdAt?: number): UnsignedEvent;
1743
+ declare function parseCiWorkflowResult(ev: NostrEvent): CiWorkflowResult | null;
1744
+ interface CiWorkflowProgressInput extends Omit<CiWorkflowResultInput, 'conclusion'> {
1745
+ status: CiProgressStatus;
1746
+ /** Required iff `status === 'concluded'`. */
1747
+ conclusion?: CiConclusion;
1748
+ /** Capacity rounds before start (queued only). */
1749
+ queue?: number;
1750
+ /** Job ids currently executing. */
1751
+ inProgress?: string[];
1752
+ /** NIP-40 expiration: > created_at, ≤ created_at + 30 min. */
1753
+ expiresAt: number;
1754
+ }
1755
+ interface CiWorkflowProgress {
1756
+ eventId: string;
1757
+ pubkey: string;
1758
+ createdAt: number;
1759
+ trigger: CiTriggerContext;
1760
+ runId: string;
1761
+ status: CiProgressStatus;
1762
+ conclusion?: CiConclusion;
1763
+ queue?: number;
1764
+ inProgress: string[];
1765
+ queuedAt?: number;
1766
+ startedAt?: number;
1767
+ expiresAt: number;
1768
+ provenance?: CiProvenance;
1769
+ jobs: CiJobQuote[];
1770
+ }
1771
+ declare function buildCiWorkflowProgress(input: CiWorkflowProgressInput, createdAt?: number): UnsignedEvent;
1772
+ declare function parseCiWorkflowProgress(ev: NostrEvent): CiWorkflowProgress | null;
1773
+
1774
+ /**
1775
+ * Repository Secret Update payloads (rig#125): the NIP-44 v2 ciphertext a
1776
+ * kind:29846 carries, its plaintext rules, and the per-name ordering that
1777
+ * turns a stream of updates into the coordinator's secret inventory.
1778
+ * docs/specs/nip-c1.md "Repository Secret Update" is the contract.
1779
+ *
1780
+ * The maintainer signs the OUTER event with their identity but encrypts
1781
+ * with a FRESH per-submission sender key to the coordinator's advertised
1782
+ * `secrets-key` (a short-lived transport key, never the coordinator's
1783
+ * signing key). The plaintext repeats only two bindings — `author` and
1784
+ * `created_at` — so captured ciphertext cannot be re-signed into another
1785
+ * maintainer's authority or moved to a newer ordering position; the rest is
1786
+ * authenticated by the outer signature and not duplicated.
1787
+ *
1788
+ * The inventory keeps a value-or-tombstone per name with the update's
1789
+ * `(created_at, event id)` so that out-of-order or duplicate relay delivery
1790
+ * can never resurrect an older value (a remove is an ordering tombstone).
1791
+ * rig persists this inventory under the coordinator's state dir (slice 4);
1792
+ * the bunker-sealed storage mode NIP-C1 defines is out of scope.
1793
+ */
1794
+ declare const SECRET_NAME_RE: RegExp;
1795
+ /** Names a coordinator never injects into jobs (NIP-C1 reserved). */
1796
+ declare const RESERVED_SECRET_NAMES: readonly string[];
1797
+ declare const MAX_SECRET_NAMES = 100;
1798
+ declare const MAX_SECRET_VALUE_BYTES = 16384;
1799
+ declare const MAX_SECRET_PLAINTEXT_BYTES = 65535;
1800
+ declare const MAX_SECRET_CIPHERTEXT_BYTES: number;
1801
+ interface SecretUpdatePlaintext {
1802
+ author: string;
1803
+ created_at: number;
1804
+ set: Record<string, string>;
1805
+ remove: string[];
1806
+ }
1807
+ /**
1808
+ * Validate the plaintext SHAPE + limits (not the outer bindings — see
1809
+ * {@link validateSecretUpdate}). Throws on any violation; returns the
1810
+ * narrowed value.
1811
+ */
1812
+ declare function assertSecretUpdateShape(value: unknown): SecretUpdatePlaintext;
1813
+ /** Bind a decrypted plaintext to its outer event: author + created_at MUST match. */
1814
+ declare function validateSecretUpdate(plain: SecretUpdatePlaintext, outer: {
1815
+ pubkey: string;
1816
+ created_at: number;
1817
+ }): void;
1818
+ /** Encrypt one update (NIP-44 v2) from a fresh sender key to the advertised recipient. */
1819
+ declare function encryptSecretUpdate(plain: SecretUpdatePlaintext, senderSecretKey: Uint8Array, recipientPubkey: string): string;
1820
+ /**
1821
+ * Decrypt + validate one update with the recipient (secrets-key) secret key
1822
+ * and the event's `sender` pubkey. Bounds the ciphertext BEFORE decrypting
1823
+ * (nostr-tools asks callers to) and the plaintext after.
1824
+ */
1825
+ declare function decryptSecretUpdate(ciphertext: string, recipientSecretKey: Uint8Array, senderPubkey: string): SecretUpdatePlaintext;
1826
+ interface SecretInventoryEntry {
1827
+ /** The value, or `null` for a remove tombstone. */
1828
+ value: string | null;
1829
+ /** Ordering position of the update that last touched this name. */
1830
+ createdAt: number;
1831
+ eventId: string;
1832
+ /** The maintainer whose update supplied this entry. */
1833
+ origin: string;
1834
+ }
1835
+ type SecretInventory = Record<string, SecretInventoryEntry>;
1836
+ /**
1837
+ * Apply one accepted update to an inventory (immutably). Per name, the
1838
+ * NIP-C1 total order decides: an update only replaces an entry it is LATER
1839
+ * than, so replaying an old event — or a remove that arrived before the set
1840
+ * it tombstones — never resurrects a stale value.
1841
+ */
1842
+ declare function applySecretUpdate(inventory: SecretInventory, plain: SecretUpdatePlaintext, eventId: string): SecretInventory;
1843
+ /** The injectable name → value map (tombstones dropped). */
1844
+ declare function effectiveSecrets(inventory: SecretInventory): Record<string, string>;
1845
+ /** A fresh NIP-44 recipient (secrets-key) or sender keypair. */
1846
+ declare function generateSecretsKey(): {
1847
+ secretKey: Uint8Array;
1848
+ pubkey: string;
1849
+ };
1850
+
1851
+ /**
1852
+ * NIP-C1 trust levels (rig#125): how a run's results relate to the repo's
1853
+ * maintainers, derived ONLY from Service Requests / Stops and the repo's
1854
+ * declared maintainers — never from anything the coordinator asserts about
1855
+ * itself. The relay is permissionless, so a stranger's coordinator can
1856
+ * publish a green 9842 for anyone's commit; this is the consumer-side filter
1857
+ * (the same posture as #287's authorized status authors) that lets
1858
+ * `rig ci status --require-ci-trust` and rig-web tell whose CI they are
1859
+ * looking at.
1860
+ *
1861
+ * maintainer-directed the run's frozen provenance quote names a
1862
+ * maintainer: a manual trigger they signed, or a
1863
+ * Service Request they signed that we have SEEN
1864
+ * and that targets this run's publisher;
1865
+ * operationally-associated no qualifying quote, but at run time an
1866
+ * accepted, unstopped maintainer Request stood for
1867
+ * this publisher (it was authorized, just silent);
1868
+ * seen-in-network the publisher is itself a maintainer, or SOME
1869
+ * pubkey (not a maintainer) requested its service
1870
+ * for this repo — e.g. a contributor running their
1871
+ * own coordinator against a repo they don't own;
1872
+ * no-known-context nothing ties the publisher to the repo.
1873
+ */
1874
+
1875
+ type CiTrustLevel = 'maintainer-directed' | 'operationally-associated' | 'seen-in-network' | 'no-known-context';
1876
+ /** Strongest first. */
1877
+ declare const CI_TRUST_ORDER: readonly CiTrustLevel[];
1878
+ declare function isCiTrustLevel(value: string): value is CiTrustLevel;
1879
+ interface DeriveTrustLevelArgs {
1880
+ /** The run's 9842/39842 signer — the coordinator. */
1881
+ publisherPubkey: string;
1882
+ /** The run's frozen `q … service-request|manual-trigger` quote, if any. */
1883
+ provenance?: CiProvenance;
1884
+ /** Owner ∪ maintainers of the repo (hex, any case). */
1885
+ authorized: Set<string>;
1886
+ /** Every 9843/9844 seen for this repo address (any coordinator). */
1887
+ controls: ServiceControl[];
1888
+ /** The run's `created_at` — requests are evaluated as of this instant. */
1889
+ runCreatedAt: number;
1890
+ }
1891
+ declare function deriveTrustLevel(args: DeriveTrustLevelArgs): CiTrustLevel;
1892
+ /** True when `level` is at least as strong as `required`. */
1893
+ declare function trustAtLeast(level: CiTrustLevel, required: CiTrustLevel): boolean;
1894
+
1895
+ /**
1896
+ * The Runner seam (rig#125) — the ONE new interface the relay-native CI
1897
+ * layer introduces. The coordinator (./coordinator.ts) materializes a commit,
1898
+ * picks a workflow, decides the secret set, and hands all of that to a
1899
+ * Runner; the Runner executes the jobs and reports per-job conclusions, exit
1900
+ * codes, timings, logs and artifact files. Nothing about relays, payments,
1901
+ * or NIP-C1 events crosses this boundary in either direction.
1902
+ *
1903
+ * Two implementations exist today:
1904
+ *
1905
+ * - {@link FakeRunner} (here): scripted outcomes for coordinator tests.
1906
+ * - `ActRunner` (./act-runner.ts): shells out to `act` against the host
1907
+ * Docker daemon — the first-slice "coordinator is its own runner" shape
1908
+ * ngit's reference coordinator also uses.
1909
+ *
1910
+ * A later TOON-lease runner (rent a workload from a TOON Network provider,
1911
+ * blocked on TOON_Network Milestone 1) is a third class behind the SAME
1912
+ * interface; that is the whole point of the seam.
1913
+ */
1914
+
1915
+ /** One artifact file a job produced (one entry per FILE, never an archive). */
1916
+ interface RunnerArtifact {
1917
+ /** Absolute path of the file on the coordinator host. */
1918
+ path: string;
1919
+ /** The file's path within the artifact (mirrors upload-artifact). */
1920
+ filename: string;
1921
+ /** The artifact name grouping related files. */
1922
+ name: string;
1923
+ }
1924
+ /** The outcome of one job within a run. */
1925
+ interface RunnerJobResult {
1926
+ /** Job id as declared in the workflow file. */
1927
+ jobId: string;
1928
+ /** Human-readable job name, when the workflow declares one. */
1929
+ name?: string;
1930
+ conclusion: CiConclusion;
1931
+ exitCode?: number;
1932
+ /** Unix seconds. */
1933
+ startedAt: number;
1934
+ /** Unix seconds. */
1935
+ finishedAt: number;
1936
+ /** The job's complete log output. */
1937
+ log: string;
1938
+ artifacts: RunnerArtifact[];
1939
+ }
1940
+ /** The outcome of one workflow run. */
1941
+ interface RunnerRunResult {
1942
+ /** Combined conclusion — the execution backend's own verdict, passed through. */
1943
+ conclusion: CiConclusion;
1944
+ jobs: RunnerJobResult[];
1945
+ startedAt: number;
1946
+ finishedAt: number;
1947
+ }
1948
+ /** Everything a Runner needs to execute one workflow once. */
1949
+ interface RunnerRequest {
1950
+ /** A real git repository, checked out at `trigger.commit`. */
1951
+ checkoutDir: string;
1952
+ /** Workflow file path relative to `checkoutDir`, plus its content SHA-256. */
1953
+ workflow: {
1954
+ path: string;
1955
+ sha256: string;
1956
+ };
1957
+ trigger: CiTriggerContext;
1958
+ /** Secrets to inject; `{}` for runs the coordinator did not authorize secrets for. */
1959
+ secrets: Record<string, string>;
1960
+ /** Extra environment for the jobs. */
1961
+ env?: Record<string, string>;
1962
+ /** Wall-clock budget for the whole run; exceeding it concludes `timed_out`. */
1963
+ timeoutMs: number;
1964
+ /** Streaming log sink (per job). */
1965
+ onLog?: (jobId: string, chunk: string) => void;
1966
+ /** Cancels the run (concludes `cancelled`). */
1967
+ signal?: AbortSignal;
1968
+ }
1969
+ /** Executes one workflow run. See the module header. */
1970
+ interface Runner {
1971
+ /** Runner family, as advertised in the NIP-C1 `W` tag. */
1972
+ readonly family: 'act';
1973
+ /** Accepted selectors for the family (`R` = `act:<selector>`). */
1974
+ readonly selectors: string[];
1975
+ run(request: RunnerRequest): Promise<RunnerRunResult>;
1976
+ }
1977
+ type FakeRunnerScript = (request: RunnerRequest) => RunnerRunResult | Promise<RunnerRunResult>;
1978
+ /** The default script: one successful `build` job with a short log. */
1979
+ declare function defaultFakeRunResult(request: RunnerRequest): RunnerRunResult;
1980
+ /**
1981
+ * A Runner that returns scripted outcomes and records every request, so a
1982
+ * coordinator test can assert on what was asked (secrets, timeout, commit)
1983
+ * and drive the publish sequence from a chosen result. Never touches Docker.
1984
+ */
1985
+ declare class FakeRunner implements Runner {
1986
+ private readonly script;
1987
+ readonly family: "act";
1988
+ readonly selectors: string[];
1989
+ /** Every request, in call order. */
1990
+ readonly requests: RunnerRequest[];
1991
+ constructor(script?: FakeRunnerScript);
1992
+ run(request: RunnerRequest): Promise<RunnerRunResult>;
1993
+ }
1994
+
1995
+ /**
1996
+ * Workflow discovery and trigger matching (rig#125).
1997
+ *
1998
+ * Workflows are GitHub-Actions-syntax files the coordinator reads out of a
1999
+ * MATERIALIZED checkout (never from the relay, never from GitHub): first
2000
+ * `.github/workflows/*.yml|yaml`, then `.ngit/act/workflows/*.yml|yaml` so
2001
+ * repos already on ngit CI are served as-is. Each is identified on every
2002
+ * NIP-C1 event by its path and the SHA-256 of its bytes (the `w` tag), so a
2003
+ * consumer can verify exactly which file ran.
2004
+ *
2005
+ * Only the `on:` clause and the job list are interpreted here — enough to
2006
+ * decide WHETHER a workflow runs for a push/pull-request trigger and which
2007
+ * job ids to expect. Everything else in the file is act's business
2008
+ * (./act-runner.ts). Parsing never throws: a malformed file comes back with
2009
+ * `parseError` set so the coordinator can publish an honest
2010
+ * `startup_failure` for it instead of silently skipping it.
2011
+ */
2012
+ /** Where workflows live, in scan order (relative to the checkout root). */
2013
+ declare const WORKFLOW_DIRS: readonly [".github/workflows", ".ngit/act/workflows"];
2014
+ /** Branch/tag filters of a `push:` or `pull_request:` trigger. */
2015
+ interface RefFilters {
2016
+ branches?: string[];
2017
+ tags?: string[];
2018
+ }
2019
+ interface WorkflowTriggers {
2020
+ push?: RefFilters;
2021
+ pull_request?: RefFilters;
2022
+ workflow_dispatch?: boolean;
2023
+ }
2024
+ interface WorkflowJob {
2025
+ id: string;
2026
+ name?: string;
2027
+ runsOn?: string[];
2028
+ }
2029
+ interface DiscoveredWorkflow {
2030
+ /** Path relative to the checkout root, forward slashes. */
2031
+ path: string;
2032
+ /** Lowercase hex SHA-256 of the file's exact bytes. */
2033
+ sha256: string;
2034
+ name?: string;
2035
+ triggers: WorkflowTriggers;
2036
+ jobs: WorkflowJob[];
2037
+ /** Set when the file could not be understood; `triggers`/`jobs` are then empty. */
2038
+ parseError?: string;
2039
+ }
2040
+ /** Lowercase hex SHA-256 of `bytes`. */
2041
+ declare function sha256Hex(bytes: Uint8Array | string): string;
2042
+ /**
2043
+ * Parse one workflow file's bytes. Never throws — see the module header.
2044
+ * YAML 1.1 loaders read the unquoted `on` key as boolean `true`; the `yaml`
2045
+ * package (YAML 1.2) keeps it a string, but a file re-saved by such a loader
2046
+ * carries a literal `true:` key, so both spellings are honoured.
2047
+ */
2048
+ declare function parseWorkflow(path: string, content: string | Uint8Array): DiscoveredWorkflow;
2049
+ /**
2050
+ * Every workflow file under {@link WORKFLOW_DIRS} in `checkoutDir`, in a
2051
+ * stable order (directory order, then filename). Missing directories are
2052
+ * simply empty.
2053
+ */
2054
+ declare function discoverWorkflows(checkoutDir: string): Promise<DiscoveredWorkflow[]>;
2055
+ /**
2056
+ * GitHub's `branches`/`tags` filter rule: patterns are applied in order, a
2057
+ * `!` pattern excludes, and a name is included only if the LAST matching
2058
+ * pattern was positive. A negation can never include on its own.
2059
+ */
2060
+ declare function refMatchesPatterns(shortName: string, patterns: string[]): boolean;
2061
+ /**
2062
+ * Does `wf` run for a push that moved `ref` (`refs/heads/...` or
2063
+ * `refs/tags/...`)? Mirrors GitHub: no filters → every ref; a `branches`
2064
+ * filter alone → only branches; a `tags` filter alone → only tags.
2065
+ */
2066
+ declare function matchesPush(wf: DiscoveredWorkflow, ref: string): boolean;
2067
+ /**
2068
+ * Does `wf` run for a pull request against `baseRef` (a `refs/heads/...` ref
2069
+ * or a bare branch name)? With a `branches` filter and no known base the
2070
+ * match cannot be proven, so the workflow does not run.
2071
+ */
2072
+ declare function matchesPullRequest(wf: DiscoveredWorkflow, baseRef?: string): boolean;
2073
+
2074
+ /**
2075
+ * `rig ci status <commit>` — the FREE read side of relay-native CI (#125):
2076
+ * every NIP-C1 run (kind:9842 Workflow Result / kind:39842 Workflow
2077
+ * Progress) and job (kind:9841 Job Result) a relay holds for one commit of
2078
+ * one repo, with each run's trust level derived from the repo's maintainers
2079
+ * (kind:30617) and the Service Request / Stop history (kind:9843/9844).
2080
+ *
2081
+ * It is the one-command merge gate: exit 0 only when every COUNTED run has
2082
+ * concluded green. A run counts when it is the latest attempt by its
2083
+ * publisher for its workflow, survives `--workflow` and
2084
+ * `--require-ci-trust`, and — since the relay is permissionless — a
2085
+ * stranger's coordinator can never make a commit green under a trust
2086
+ * requirement it does not meet. A commit with no concluded run is NOT green
2087
+ * (exit 1, "no concluded run"), so a gate cannot pass by accident.
2088
+ *
2089
+ * Like the #278 tracker reads: no identity, no payment, reads may target
2090
+ * several relays (merged by event id), and `--json` emits exactly one
2091
+ * document.
2092
+ */
2093
+
2094
+ interface CiStatusJob {
2095
+ jobId: string;
2096
+ name?: string;
2097
+ conclusion: CiConclusion;
2098
+ logsUrl?: string;
2099
+ artifacts: CiArtifact[];
2100
+ exitCode?: number;
2101
+ startedAt?: number;
2102
+ eventId: string;
2103
+ publisher: string;
2104
+ }
2105
+ interface CiStatusRun {
2106
+ runId: string;
2107
+ coordinator: string;
2108
+ workflow: CiWorkflowRef;
2109
+ reason: CiTriggerReason;
2110
+ status: CiProgressStatus;
2111
+ conclusion?: CiConclusion;
2112
+ trust: CiTrustLevel;
2113
+ createdAt: number;
2114
+ startedAt?: number;
2115
+ queuedAt?: number;
2116
+ provenance?: CiProvenance;
2117
+ jobs: CiStatusJob[];
2118
+ /** Event id of the 9842 (concluded) or the latest 39842. */
2119
+ eventId: string;
2120
+ }
2121
+ interface CiStatusSummary {
2122
+ counted: number;
2123
+ green: number;
2124
+ red: number;
2125
+ pending: number;
2126
+ }
2127
+ interface CiStatusReport {
2128
+ command: 'ci status';
2129
+ commit: string;
2130
+ repo: {
2131
+ owner: string;
2132
+ repoId: string;
2133
+ };
2134
+ relays: string[];
2135
+ requiredTrust: CiTrustLevel | null;
2136
+ runs: CiStatusRun[];
2137
+ summary: CiStatusSummary;
2138
+ ok: boolean;
2139
+ /** Why `ok` is false, for humans and logs. */
2140
+ reason?: string;
2141
+ }
2142
+ interface AssembleStatusOptions {
2143
+ commit: string;
2144
+ ownerPubkey: string;
2145
+ repoId: string;
2146
+ /** Owner ∪ declared maintainers (lowercase hex). */
2147
+ authorized: Set<string>;
2148
+ events: NostrEvent[];
2149
+ requireTrust?: CiTrustLevel;
2150
+ workflow?: string;
2151
+ }
2152
+ /**
2153
+ * Turn relay events into the run list + verdict. Runs are keyed by
2154
+ * (publisher, runId): a 9842 marks the run concluded; otherwise the newest
2155
+ * 39842 (by created_at) gives its status. Jobs attach by the 9841's quoted
2156
+ * progress address. Per (publisher, workflow path) only the LATEST attempt
2157
+ * (by created_at, ties → lowest id) counts.
2158
+ */
2159
+ declare function assembleCiStatus(opts: AssembleStatusOptions): {
2160
+ runs: CiStatusRun[];
2161
+ summary: CiStatusSummary;
2162
+ ok: boolean;
2163
+ reason?: string;
2164
+ };
2165
+
2166
+ export { type BuildIncrementOfferOptions, type BuildNarrationOptions, type BuildResultEventOptions, CI_ADVERTISEMENT_KIND, CI_JOB_RESULT_KIND, CI_MANUAL_TRIGGER_KIND, CI_MAX_ADVERTISEMENT_TTL, CI_MAX_PROGRESS_TTL, CI_RUNNER_FAMILY, CI_SECRET_UPDATE_KIND, CI_SERVICE_REQUEST_KIND, CI_SERVICE_STOP_KIND, CI_SOFTWARE, CI_TRUST_ORDER, CI_WORKFLOW_PROGRESS_KIND, CI_WORKFLOW_RESULT_KIND, type CiAdmissionPolicy, type CiAdvertisement, type CiAdvertisementInput, type CiArtifact, type CiBillingPolicy, type CiConclusion, type CiExecutionPolicy, type CiJobQuote, type CiJobResult, type CiJobResultInput, type CiManualTrigger, type CiPrContext, type CiProgressStatus, type CiProvenance, type CiSecretUpdate, type CiSecretUpdateArgs, type CiStatusJob, type CiStatusReport, type CiStatusRun, type CiStatusSummary, type CiTriggerContext, type CiTriggerReason, type CiTrustLevel, type CiWorkflowProgress, type CiWorkflowProgressInput, type CiWorkflowRef, type CiWorkflowResult, type CiWorkflowResultInput, type ClosureResult, type CollectRepoObjectsOptions, type CollectRepoObjectsResult, DEFAULT_CONCURRENCY, type DeriveTrustLevelArgs, type DiscoveredWorkflow, type DownloadOptions, type DownloadResult, type EncryptedArtifact, type EncryptedArtifactRef, type ExecuteFactoryJobOptions, type ExecutePushOptions, FACTORY_JOB_FEEDBACK_KIND, FACTORY_JOB_REQUEST_KIND, FACTORY_JOB_RESULT_KIND, type FactoryJobExecution, type FactoryJobHooks, type FactoryJobOutcome, type FactoryJobRequest, type FactoryJobWork, type FactoryMilestone, type FactoryTicket, FakeRunner, type FakeRunnerScript, FeeRates, type FetchLike, type FetchRemoteStateOptions, type FetchedObject, type GateCheck, type GateResult, type GatewayFetchOptions, type GitCommentRequest, GitError, type GitErrorEnvelope, type GitEstimateRequest, type GitEstimateResponse, type GitEventResponse, type GitFeeEstimate, type GitIssueRequest, GitObjectType, type GitPatchRequest, type GitPlannedObject, type GitPublishReceipt, type GitPushRequest, type GitPushResponse, type GitRef, type GitRefUpdate, type GitRepoAddr, GitRepoReader, type GitStatusRequest, type GitStatusValue, type GitUploadStep, type IncrementSpec, type JobDeliveryPort, MAX_SECRET_CIPHERTEXT_BYTES, MAX_SECRET_NAMES, MAX_SECRET_PLAINTEXT_BYTES, MAX_SECRET_VALUE_BYTES, type MissingObject, NonFastForwardError, type NostrEvent, type NostrFilter, ObjectIntegrityError, type ObjectStat, type ObjectWithPath, ObjectWriteMismatchError, type OfferedIncrement, type OversizeObject, OversizeObjectsError, PayoutPointer, type PlanPushOptions, type PlannedObject, PublishReceipt, Publisher, type PushFeeEstimate, type PushPlan, type PushResult, RESERVED_SECRET_NAMES, type ReadGitObject, type ReadObjectsResult, type RefFilters, type RefUpdate, type RefUpdateKind, type RejectedRefUpdate, type RelayEvent, type RemoteState, type RepoAddress, type RepoRefs, type Runner, type RunnerArtifact, type RunnerJobResult, type RunnerRequest, type RunnerRunResult, SECRET_NAME_RE, type SecretInventory, type SecretInventoryEntry, type SecretUpdatePlaintext, type SelectServiceRequestsOptions, type SelectedServiceRequests, type ServiceControl, type StatObjectsResult, UnsignedEvent, type UploadStepResult, WORKFLOW_DIRS, type WebSocketFactory, type WebSocketLike, type WorkflowJob, type WorkflowTriggers, applySecretUpdate, assembleCiStatus, assertSecretUpdateShape, buildCiAdvertisement, buildCiJobResult, buildCiManualTrigger, buildCiSecretUpdate, buildCiServiceRequest, buildCiServiceStop, buildCiWorkflowProgress, buildCiWorkflowResult, buildIncrementOfferEvent, buildNarrationEvent, buildQuoteEvent, buildResultEvent, collectRepoObjects, commonTriggerTags, controlOrder, decryptSecretUpdate, defaultFakeRunResult, deriveTrustLevel, discoverWorkflows, downloadGitObjects, effectiveSecrets, encryptSecretUpdate, executeFactoryJob, executePush, fetchRemoteState, fetchTxBytes, gatePassed, generateSecretsKey, hexToNpub, isCiConclusion, isCiTrustLevel, isSafeRefname, matchesPullRequest, matchesPush, missingObjectsMessage, npubToHex, ownerToHex, parseCiAdvertisement, parseCiJobResult, parseCiManualTrigger, parseCiSecretUpdate, parseCiServiceControl, parseCiTriggerContext, parseCiWorkflowProgress, parseCiWorkflowResult, parseFactoryJobRequest, parseRepoAddress, parseWorkflow, planFactoryJob, planPush, queryRelay, refMatchesPatterns, referencedShas, repoAddress, selectServiceRequests, serializeEventReceipt, serializeFeeEstimate, serializePushPlan, serializePushResult, setHeadSymref, sha256Hex, trustAtLeast, updateRef, validateSecretUpdate, verifyObjectBody, walkClosure, writeGitObject, writeGitObjects };