approval-md 0.4.5 → 0.4.7

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.
Files changed (83) hide show
  1. package/SPEC.md +24 -3
  2. package/dist/src/channels/contract.d.ts +15 -0
  3. package/dist/src/channels/contract.js +23 -1
  4. package/dist/src/channels/contract.js.map +1 -1
  5. package/dist/src/channels/telegram.d.ts +180 -33
  6. package/dist/src/channels/telegram.js +256 -87
  7. package/dist/src/channels/telegram.js.map +1 -1
  8. package/dist/src/cli/channel-telegram.d.ts +114 -35
  9. package/dist/src/cli/channel-telegram.js +259 -120
  10. package/dist/src/cli/channel-telegram.js.map +1 -1
  11. package/dist/src/cli/doctor.js +33 -13
  12. package/dist/src/cli/doctor.js.map +1 -1
  13. package/dist/src/cli/help.d.ts +2 -0
  14. package/dist/src/cli/help.js +39 -3
  15. package/dist/src/cli/help.js.map +1 -1
  16. package/dist/src/cli/hook-exec-code.d.ts +150 -0
  17. package/dist/src/cli/hook-exec-code.js +357 -0
  18. package/dist/src/cli/hook-exec-code.js.map +1 -0
  19. package/dist/src/cli/hook.d.ts +154 -1
  20. package/dist/src/cli/hook.js +2344 -111
  21. package/dist/src/cli/hook.js.map +1 -1
  22. package/dist/src/cli/instructions.js +9 -6
  23. package/dist/src/cli/instructions.js.map +1 -1
  24. package/dist/src/cli/main.js +9 -0
  25. package/dist/src/cli/main.js.map +1 -1
  26. package/dist/src/cli/study.d.ts +22 -0
  27. package/dist/src/cli/study.js +153 -0
  28. package/dist/src/cli/study.js.map +1 -0
  29. package/dist/src/cli/verb-registry.d.ts +14 -0
  30. package/dist/src/cli/verb-registry.js +37 -0
  31. package/dist/src/cli/verb-registry.js.map +1 -1
  32. package/dist/src/cli/wordmark.d.ts +2 -2
  33. package/dist/src/cli/wordmark.js +2 -2
  34. package/dist/src/core/command-class.d.ts +349 -1
  35. package/dist/src/core/command-class.js +2347 -87
  36. package/dist/src/core/command-class.js.map +1 -1
  37. package/dist/src/core/exec-code.d.ts +77 -0
  38. package/dist/src/core/exec-code.js +60 -0
  39. package/dist/src/core/exec-code.js.map +1 -0
  40. package/dist/src/core/gate.d.ts +38 -0
  41. package/dist/src/core/gate.js +26 -0
  42. package/dist/src/core/gate.js.map +1 -1
  43. package/dist/src/core/git-push-argv.d.ts +111 -0
  44. package/dist/src/core/git-push-argv.js +375 -0
  45. package/dist/src/core/git-push-argv.js.map +1 -0
  46. package/dist/src/core/harness-version.d.ts +71 -30
  47. package/dist/src/core/harness-version.js +101 -34
  48. package/dist/src/core/harness-version.js.map +1 -1
  49. package/dist/src/core/policy-load.d.ts +8 -0
  50. package/dist/src/core/policy-load.js.map +1 -1
  51. package/dist/src/core/sender-identity.d.ts +13 -1
  52. package/dist/src/core/sender-identity.js +15 -0
  53. package/dist/src/core/sender-identity.js.map +1 -1
  54. package/dist/src/core/study-withdraw.d.ts +137 -0
  55. package/dist/src/core/study-withdraw.js +280 -0
  56. package/dist/src/core/study-withdraw.js.map +1 -0
  57. package/dist/src/daemon/git-evidence.d.ts +2 -2
  58. package/dist/src/daemon/git-evidence.js +1 -1
  59. package/dist/src/mcp/server.js +1 -1
  60. package/dist/src/mcp/server.js.map +1 -1
  61. package/docs/README-extended.md +3 -2
  62. package/docs/cli-reference.md +83 -7
  63. package/package.json +2 -2
  64. package/schema/event.schema.json +213 -1
  65. package/schema/fixtures/event/invalid/approval-granted-study.json +23 -0
  66. package/schema/fixtures/event/invalid/approval-rejected-looks-wrong-cli-channel.json +23 -0
  67. package/schema/fixtures/event/invalid/approval-rejected-looks-wrong-operator.json +24 -0
  68. package/schema/fixtures/event/invalid/approval-rejected-study-extra-key.json +24 -0
  69. package/schema/fixtures/event/invalid/approval-rejected-study-unknown-reason.json +23 -0
  70. package/schema/fixtures/event/invalid/approval-rejected-study-withdrawn-email-operator.json +20 -0
  71. package/schema/fixtures/event/invalid/approval-rejected-study-withdrawn-no-operator.json +19 -0
  72. package/schema/fixtures/event/invalid/approval-rejected-study-withdrawn-no-ref.json +19 -0
  73. package/schema/fixtures/event/invalid/approval-rejected-study-withdrawn-wrong-actor.json +20 -0
  74. package/schema/fixtures/event/invalid/approval-rejected-study-withdrawn-wrong-channel.json +20 -0
  75. package/schema/fixtures/event/invalid/approval-revoked-study.json +20 -0
  76. package/schema/fixtures/event/valid/approval-rejected-looks-wrong.json +23 -0
  77. package/schema/fixtures/event/valid/approval-rejected-study-withdrawn.json +20 -0
  78. package/schema/fixtures/policy/invalid/exec-code-custody-boolean.json +11 -0
  79. package/schema/fixtures/policy/invalid/exec-code-execute-code-value.json +11 -0
  80. package/schema/fixtures/policy/invalid/exec-code-unknown-key.json +12 -0
  81. package/schema/fixtures/policy/valid/exec-code-both.json +17 -0
  82. package/schema/fixtures/policy/valid/exec-code-custody.json +11 -0
  83. package/schema/policy.schema.json +23 -0
@@ -489,7 +489,8 @@ export declare const DISPATCH_LOUD_ATTEMPTS = 3;
489
489
  */
490
490
  export declare const DISPATCH_RETENTION_MS: number;
491
491
  /**
492
- * The line that introduces the first batch a listener process sends (APRV-196).
492
+ * The one message that introduces the first batch a listener process sends
493
+ * (APRV-196). Two lines, sent together by `announce`, the first in bold.
493
494
  *
494
495
  * **Why a banner and not an edit of the earlier copies.** The incident was a
495
496
  * restart re-sending five pending requests with no warning, on top of five
@@ -505,19 +506,42 @@ export declare const DISPATCH_RETENTION_MS: number;
505
506
  * (`actionRefOf` in `channels/telegram.ts`), so a human who taps the copy they
506
507
  * can see decides the request they meant.
507
508
  *
508
- * It says "started" rather than "restarted" because a listener cannot tell the
509
- * two apart, having deliberately kept nothing that would let it, and a first
510
- * start that claimed to be a restart would be this channel's own text lying
511
- * about the system's history.
509
+ * **The words are a resident's, not the system's.** The reader is whoever
510
+ * holds the phone, so the banner is one short message in plain words: how many
511
+ * requests are still waiting, and whether the buttons on the older messages
512
+ * above still work. It names no process, no log and no cycle, and it says
513
+ * neither "started" nor "restarted": a listener cannot tell the two apart,
514
+ * having deliberately kept nothing that would let it, so the text claims only
515
+ * what is true either way (these requests are still waiting). The old third
516
+ * line, about where the pending set is read from, is gone; it described the
517
+ * runtime to someone who only needs to know which button to press.
512
518
  *
513
519
  * **With the stale-copy fallback off (APRV-456)** the second line says the
514
- * opposite, because the earlier copies' buttons no longer decide anything: a
515
- * relayed listener refuses a nonce it is not holding (`nonce-not-issued`), so
516
- * the banner tells the approver to use the copies below it. A banner that kept
520
+ * opposite, because the earlier copies' buttons no longer work: a relayed
521
+ * listener refuses a nonce it is not holding (`nonce-not-issued`), so the
522
+ * banner tells the approver to use the buttons below it. A banner that kept
517
523
  * promising working older copies would be this channel's own text sending the
518
524
  * approver to a button that refuses them.
519
525
  */
520
526
  export declare function bannerLines(pending: number, staleCopy?: boolean): string[];
527
+ /**
528
+ * The reminder a collapsed re-delivery opens with, in place of the banner
529
+ * (P-9).
530
+ *
531
+ * Before this, a restart with two stale requests and one live one sent the
532
+ * stale summary first and the {@link bannerLines} banner second, and the banner
533
+ * counted only the cards after it: "1 request is still waiting" with three
534
+ * pending and the summary of the other two directly above. Two reminders, the
535
+ * more verbose one first, and a count that read as wrong. Now the summary IS the
536
+ * reminder: its first line counts everything this cycle re-sends (`pending`,
537
+ * collapsed and carded together), and the banner is skipped.
538
+ *
539
+ * `following` is how many requests get their own card after the summary. When
540
+ * there are any, the second line says so and says whether the buttons on older
541
+ * messages still work, which is what the banner it replaces said (APRV-456).
542
+ * When there are none, the summary is the whole restart and nothing follows.
543
+ */
544
+ export declare function staleReminderLines(pending: number, following: number, staleCopy?: boolean): string[];
521
545
  /**
522
546
  * Whether APRV-196's stale-copy fallback is on for a listener launched with
523
547
  * this `--api-base` and this `--no-stale-copy` (APRV-456).
@@ -535,34 +559,73 @@ export declare function bannerLines(pending: number, staleCopy?: boolean): strin
535
559
  */
536
560
  export declare function staleCopyFor(apiBase: string | null, noStaleCopy: boolean): boolean;
537
561
  /**
538
- * The summary line that precedes a paced send, and the body of `/queue`.
539
- *
540
- * One message, and everything in it is arithmetic on the verified log at the
541
- * instant it is written: how many requests are pending, how long the oldest has
542
- * waited, and which classes they are. Nothing is remembered between calls, so
543
- * two summaries a minute apart can disagree only because the log moved.
544
- *
545
- * The class tally is the part worth the space. The count alone says how much
546
- * work is waiting; the classes say what KIND of work, which is what tells an
547
- * approver whether the queue is six identical `network.call`s they can walk
548
- * through or one `policy.edit` they should read carefully.
562
+ * The launch variable that turns study mode on (amended SPEC.md §8, the study
563
+ * record). Generic on purpose: the core is a public spec and names no study.
564
+ * A hosted deployment writes it into the listener's environment for the
565
+ * tenants a study covers; nothing else sets it.
566
+ */
567
+ export declare const STUDY_MODE_ENV = "APPROVAL_STUDY_MODE";
568
+ /**
569
+ * Whether `env` turns study mode on: the value is exactly `1`, and anything
570
+ * else (unset, blank, `true`, ` 1`, `0`) is off. Called once, by
571
+ * {@link prepareListen}; the channel keeps the answer for its lifetime, so a
572
+ * change takes effect only when the listener restarts.
573
+ */
574
+ export declare function studyModeFor(env: NodeJS.ProcessEnv): boolean;
575
+ /**
576
+ * The count line a paced cycle sends when the pending set has grown, and the
577
+ * header of `/queue` (APRV-216), in a resident's words (P-9).
578
+ *
579
+ * One line, and everything in it is arithmetic on the verified log at the
580
+ * instant it is written: how many requests are waiting and how long the oldest
581
+ * has waited. Nothing is remembered between calls, so two summaries a minute
582
+ * apart can disagree only because the log moved.
583
+ *
584
+ * Before P-9 it also carried a class tally ("communicate.email.external ×3").
585
+ * The tally told an operator what kind of work was queued, and told a resident
586
+ * nothing they could read; the kind of each request is on its own card, and
587
+ * `/queue` now lists each by the agent's own summary ({@link queueLines}).
588
+ *
589
+ * The oldest is the one asked longest ago, whatever order `requests` is in:
590
+ * `/queue` passes the set in presentation order ({@link orderPending}, live
591
+ * newest first), where the first entry is the NEWEST, and a header that read
592
+ * the first entry's age called the newest one the oldest.
549
593
  */
550
594
  export declare function summaryLines(requests: ChannelRequest[], now: string): string[];
595
+ /**
596
+ * The reminder a paced listener's first cycle opens with (P-9).
597
+ *
598
+ * Paced is the product default (APRV-216), and a restart there used to open
599
+ * with the bare count line and then one card. Nothing in it said this was a
600
+ * reminder, or whether the buttons on older messages above still worked, which
601
+ * matters most behind a relay, where they do not (APRV-456). So the first
602
+ * cycle's line is a reminder in the burst banner's words ({@link bannerLines}):
603
+ * how many are waiting, how many are below, and what the older buttons do.
604
+ *
605
+ * `shown` is how many requests this cycle puts below it: one, or a digest
606
+ * group. With the stale-copy fallback on, older buttons decide only while their
607
+ * request is the one being shown, so when fewer are shown than are pending the
608
+ * line says only the ones below work right now (fold round 1, S1). Later cycles that find the set has grown send {@link summaryLines}
609
+ * instead, which is a count and not a reminder.
610
+ */
611
+ export declare function pacedReminderLines(pending: number, shown: number, staleCopy?: boolean): string[];
551
612
  /**
552
613
  * `/queue`'s reply: the summary, then one numbered line per pending request.
553
614
  *
554
615
  * Derived, like the summary, from the verified log at reply time and not from
555
616
  * anything this process is holding: the numbering is positional and names no
556
617
  * button, so a stale copy of this list cannot be used to decide anything. The
557
- * marker says which one this listener has selected and once delivered, because
558
- * the question `/queue` is usually asked to answer is "what else is there
559
- * besides the one I am looking at" — and, since APRV-256, its unhappy twin,
560
- * "where is the one I am supposed to be looking at".
561
- *
562
- * The footer answers that second question the only honest way available to a
563
- * process whose knowledge of the chat ends at "a send returned success": it
564
- * says what was sent, says it cannot tell whether the card survived, and then
565
- * spends its remaining words on recovery rather than reassurance.
618
+ * marker says which one was sent earlier, because the question `/queue` is
619
+ * usually asked to answer is "what else is there besides the one I am looking
620
+ * at" and, since APRV-256, its unhappy twin, "where is the one I am supposed to
621
+ * be looking at".
622
+ *
623
+ * P-9: each line is the agent's own summary and its age, under the label that
624
+ * says the summary is the agent's and unchecked. Before P-9 each line was the
625
+ * action key, the task id, the class and the age, and in real use the first
626
+ * two are `hook:<session uuid>:<tool_use_id>…`, two long raw ids per line. The
627
+ * three recovery paragraphs are two short lines: what /skip and /next do, and
628
+ * that neither answers anything.
566
629
  */
567
630
  export declare function queueLines(requests: ChannelRequest[], now: string, shown: readonly string[]): string[];
568
631
  /**
@@ -992,16 +1055,32 @@ export declare function supersededPending(requests: ChannelRequest[]): Set<strin
992
1055
  */
993
1056
  export declare function orderPending(requests: ChannelRequest[], now: string): ChannelRequest[];
994
1057
  /**
995
- * The computed lines a collapsed re-delivery leads with (APRV-287).
1058
+ * The computed lines a collapsed re-delivery leads with (APRV-287), in a
1059
+ * resident's words (P-9).
996
1060
  *
997
1061
  * `superseded` is the subset a newer pending request replaced (APRV-425), and
998
- * the first line states the split rather than claiming every member is old.
999
- * Before this the line said "all older than the hook's wait plus its retry
1000
- * grace", which stopped being true the moment the collapse widened: a message
1001
- * that overstates what it collapsed is the stale-documentation failure in
1002
- * message form, and this one is read by the person deciding.
1062
+ * the line states the split rather than claiming every member is old. Before
1063
+ * APRV-425 it said every member was past the hook's wait, which stopped being
1064
+ * true the moment the collapse widened: a message that overstates what it
1065
+ * collapsed is the stale-documentation failure in message form, and this one is
1066
+ * read by the person deciding.
1067
+ *
1068
+ * Before P-9 these lines also spelled out the hook's wait and retry grace in
1069
+ * seconds and minutes, a tally of class names, and a sentence about log events
1070
+ * and identical retries. The reader is whoever holds the phone, so what is left
1071
+ * is the one thing they need: how many are listed, and why nobody needs an
1072
+ * answer to them now. The age of each one moves onto its own line
1073
+ * ({@link staleAges}).
1074
+ */
1075
+ export declare function staleLines(requests: ChannelRequest[], _now: string, superseded?: ReadonlySet<string>): string[];
1076
+ /**
1077
+ * How long ago each collapsed request was asked, in the order given (P-9).
1078
+ *
1079
+ * Computed from the verified log's own `requested_ts`, like the rest of the
1080
+ * summary, and rendered beside each member's claimed summary line so the
1081
+ * resident can tell the requests apart without an action key.
1003
1082
  */
1004
- export declare function staleLines(requests: ChannelRequest[], now: string, superseded?: ReadonlySet<string>): string[];
1083
+ export declare function staleAges(requests: readonly ChannelRequest[], now: string): string[];
1005
1084
  /**
1006
1085
  * Put the requests nobody is waiting on into ONE message, and hand back the
1007
1086
  * ones that still get a message each (APRV-287, widened by APRV-425).