approval-md 0.4.0 → 0.4.1
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/SPEC.md +3 -0
- package/cli.js +72 -4
- package/dist/src/channels/contract.d.ts +53 -0
- package/dist/src/channels/contract.js +56 -0
- package/dist/src/channels/contract.js.map +1 -1
- package/dist/src/channels/tagging.d.ts +25 -0
- package/dist/src/channels/tagging.js +57 -5
- package/dist/src/channels/tagging.js.map +1 -1
- package/dist/src/channels/telegram-minimal.d.ts +251 -0
- package/dist/src/channels/telegram-minimal.js +618 -0
- package/dist/src/channels/telegram-minimal.js.map +1 -0
- package/dist/src/channels/telegram.d.ts +454 -19
- package/dist/src/channels/telegram.js +931 -80
- package/dist/src/channels/telegram.js.map +1 -1
- package/dist/src/cli/amend.js +8 -1
- package/dist/src/cli/amend.js.map +1 -1
- package/dist/src/cli/audit-card.d.ts +1 -1
- package/dist/src/cli/audit-card.js +40 -1
- package/dist/src/cli/audit-card.js.map +1 -1
- package/dist/src/cli/audit.d.ts +7 -5
- package/dist/src/cli/audit.js +22 -10
- package/dist/src/cli/audit.js.map +1 -1
- package/dist/src/cli/channel-telegram-webhook.d.ts +2 -0
- package/dist/src/cli/channel-telegram-webhook.js +7 -0
- package/dist/src/cli/channel-telegram-webhook.js.map +1 -1
- package/dist/src/cli/channel-telegram.d.ts +75 -2
- package/dist/src/cli/channel-telegram.js +170 -15
- package/dist/src/cli/channel-telegram.js.map +1 -1
- package/dist/src/cli/execute.d.ts +12 -0
- package/dist/src/cli/execute.js +46 -1
- package/dist/src/cli/execute.js.map +1 -1
- package/dist/src/cli/help.d.ts +1 -0
- package/dist/src/cli/help.js +39 -18
- package/dist/src/cli/help.js.map +1 -1
- package/dist/src/cli/hook.d.ts +114 -3
- package/dist/src/cli/hook.js +468 -50
- package/dist/src/cli/hook.js.map +1 -1
- package/dist/src/cli/log-unlock.d.ts +23 -0
- package/dist/src/cli/log-unlock.js +109 -0
- package/dist/src/cli/log-unlock.js.map +1 -0
- package/dist/src/cli/main.js +23 -6
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/cli/up.js +5 -0
- package/dist/src/cli/up.js.map +1 -1
- package/dist/src/cli/verb-registry.js +1 -0
- package/dist/src/cli/verb-registry.js.map +1 -1
- package/dist/src/cli/wordmark.d.ts +2 -2
- package/dist/src/cli/wordmark.js +2 -2
- package/dist/src/core/audit.d.ts +98 -9
- package/dist/src/core/audit.js +363 -15
- package/dist/src/core/audit.js.map +1 -1
- package/dist/src/core/command-class.js +6 -0
- package/dist/src/core/command-class.js.map +1 -1
- package/dist/src/core/gate.d.ts +58 -1
- package/dist/src/core/gate.js +30 -3
- package/dist/src/core/gate.js.map +1 -1
- package/dist/src/core/log-lock.d.ts +435 -0
- package/dist/src/core/log-lock.js +1093 -0
- package/dist/src/core/log-lock.js.map +1 -0
- package/dist/src/core/log.d.ts +82 -3
- package/dist/src/core/log.js +285 -40
- package/dist/src/core/log.js.map +1 -1
- package/dist/src/core/policy-proposal.d.ts +17 -0
- package/dist/src/core/policy-proposal.js +29 -14
- package/dist/src/core/policy-proposal.js.map +1 -1
- package/dist/src/core/prompt-layout.d.ts +186 -1
- package/dist/src/core/prompt-layout.js +345 -3
- package/dist/src/core/prompt-layout.js.map +1 -1
- package/dist/src/core/sender-identity.d.ts +24 -1
- package/dist/src/core/sender-identity.js +31 -0
- package/dist/src/core/sender-identity.js.map +1 -1
- package/dist/src/core/validate.d.ts +20 -6
- package/dist/src/core/validate.js +0 -0
- package/dist/src/core/validate.js.map +1 -1
- package/dist/src/daemon/git-evidence.d.ts +2 -2
- package/dist/src/daemon/git-evidence.js +1 -1
- package/dist/src/serve/archive.d.ts +8 -0
- package/dist/src/serve/archive.js +11 -2
- package/dist/src/serve/archive.js.map +1 -1
- package/docs/README-extended.md +2 -0
- package/docs/cli-reference.md +507 -25
- package/package.json +2 -2
- package/schema/event.schema.json +354 -28
- package/schema/fixtures/event/invalid/audit-lock-reclaimed-age-without-created.json +19 -0
- package/schema/fixtures/event/invalid/audit-lock-reclaimed-agent-actor.json +14 -0
- package/schema/fixtures/event/invalid/audit-lock-reclaimed-lockfile-path.json +14 -0
- package/schema/fixtures/event/invalid/audit-lock-reclaimed-operator-cleared-system-actor.json +14 -0
- package/schema/fixtures/event/invalid/audit-lock-reclaimed-unknown-reason.json +14 -0
- package/schema/fixtures/event/invalid/audit-lock-reclaimed-without-age.json +13 -0
- package/schema/fixtures/event/invalid/audit-reviewed-agent-actor.json +6 -1
- package/schema/fixtures/event/invalid/audit-reviewed-bad-payload-hash.json +21 -0
- package/schema/fixtures/event/invalid/audit-reviewed-loved-no-note.json +5 -0
- package/schema/fixtures/event/invalid/audit-reviewed-no-subject-hash.json +19 -0
- package/schema/fixtures/event/invalid/audit-reviewed-no-subject-seq.json +19 -0
- package/schema/fixtures/event/invalid/audit-reviewed-no-verdict-source.json +19 -0
- package/schema/fixtures/event/invalid/audit-reviewed-no-verdict.json +19 -0
- package/schema/fixtures/event/invalid/audit-reviewed-system-actor.json +6 -1
- package/schema/fixtures/event/invalid/audit-sampled-no-policy-hash.json +14 -0
- package/schema/fixtures/event/valid/audit-lock-reclaimed-implausible-created.json +18 -0
- package/schema/fixtures/event/valid/audit-lock-reclaimed-legacy.json +14 -0
- package/schema/fixtures/event/valid/audit-lock-reclaimed-unlock.json +19 -0
- package/schema/fixtures/event/valid/audit-lock-reclaimed.json +19 -0
- package/schema/fixtures/event/valid/audit-reviewed-reaction.json +5 -0
- package/schema/fixtures/event/valid/audit-reviewed.json +6 -1
- package/schema/fixtures/event/valid/audit-sampled.json +2 -1
- package/schema/fixtures/event/valid/daemon-identity.json +2 -1
- package/schema/policy.schema.json +52 -0
package/dist/src/cli/hook.d.ts
CHANGED
|
@@ -75,7 +75,7 @@ import { type ClassifiedSegment, type CommandClassification, type ProtectedPathE
|
|
|
75
75
|
import { type GateOptions } from "../core/gate.js";
|
|
76
76
|
import { type HarnessKind } from "../core/harness-version.js";
|
|
77
77
|
import { type HarnessLoopState } from "../core/loop.js";
|
|
78
|
-
import type
|
|
78
|
+
import { type EventRecord } from "../core/log.js";
|
|
79
79
|
import { type ReadRecordsResult } from "../core/state.js";
|
|
80
80
|
import type { Streams } from "./main.js";
|
|
81
81
|
import { type Style } from "./style.js";
|
|
@@ -537,6 +537,51 @@ export declare function harnessBlockDirective(code: string, detail: string, harn
|
|
|
537
537
|
stdout: string;
|
|
538
538
|
exitCode: number;
|
|
539
539
|
};
|
|
540
|
+
/**
|
|
541
|
+
* Raised on `globalThis` while the runtime's own Hermes signal guards are
|
|
542
|
+
* registered (APRV-466). The `approval` bin reads the same registry symbol and
|
|
543
|
+
* steps aside while it is `true`, so the bin and the runtime never both print.
|
|
544
|
+
* An explicit flag rather than a listener count: an unrelated listener that
|
|
545
|
+
* does not exit must not switch the bin's guard off.
|
|
546
|
+
*/
|
|
547
|
+
export declare const HERMES_SIGNAL_OWNER: unique symbol;
|
|
548
|
+
/**
|
|
549
|
+
* The block directive a Hermes hook prints when a signal arrives before it
|
|
550
|
+
* reached a verdict (APRV-445, APRV-466), as bytes.
|
|
551
|
+
*
|
|
552
|
+
* Two places print it: `hermesFailClosed`'s guard below, and the `approval` bin
|
|
553
|
+
* (`cli.js`), which has to answer a signal that lands while this module is
|
|
554
|
+
* still loading and so cannot import it. The bin spells the same bytes by hand,
|
|
555
|
+
* and `tests/hermes-bin-signal-guard.test.ts` pins the two equal, so the
|
|
556
|
+
* early-signal answer is one code with one spelling (SPEC.md §11.1 invariant
|
|
557
|
+
* 6). The wait's own handler words its message differently ("while waiting for
|
|
558
|
+
* a decision") under the same code.
|
|
559
|
+
*
|
|
560
|
+
* On the CLI the runtime's guard prints it for a signal held through the
|
|
561
|
+
* synchronous stretch before the first spend (the stdin read, the
|
|
562
|
+
* classification), at the pause `BEFORE_SPEND` (APRV-473); the bin prints it
|
|
563
|
+
* for a signal during the load (docs/hermes-hook.md, "Two layers against a
|
|
564
|
+
* signal").
|
|
565
|
+
*/
|
|
566
|
+
export declare function hermesInterruptedDirective(signal: NodeJS.Signals): string;
|
|
567
|
+
/**
|
|
568
|
+
* The block directive a harness wait answers when a SIGTERM or SIGINT ends it
|
|
569
|
+
* (APRV-473 for Hermes, APRV-475 for every harness), as bytes and exit code.
|
|
570
|
+
*
|
|
571
|
+
* It is the harness's ORDINARY deny, built by {@link harnessBlockDirective}
|
|
572
|
+
* and so by {@link deny}, under the `hook-interrupted` code: the nested
|
|
573
|
+
* `hookSpecificOutput` deny at exit 0 for Claude Code, Codex and Muse,
|
|
574
|
+
* `{permission:"deny"}` at exit 0 for Cursor, `{decision:"deny"}` at exit 2
|
|
575
|
+
* for Grok, `{action:"block"}` at exit 2 for Hermes. One construction site per
|
|
576
|
+
* harness, so the answer to an interruption is spelled exactly as every other
|
|
577
|
+
* refusal that harness receives from this hook, and a harness that blocks on
|
|
578
|
+
* those blocks on this. `tests/harness-wait-interrupt.test.ts` pins the bytes
|
|
579
|
+
* per harness.
|
|
580
|
+
*/
|
|
581
|
+
export declare function interruptedWaitDirective(signal: NodeJS.Signals, harness: HarnessKind): {
|
|
582
|
+
stdout: string;
|
|
583
|
+
exitCode: number;
|
|
584
|
+
};
|
|
540
585
|
/** The machine-readable code a Hermes `execute_code` call is refused with. */
|
|
541
586
|
export declare const HERMES_EXECUTE_CODE_REFUSAL = "hook-hermes-execute-code-unbound";
|
|
542
587
|
/** The machine-readable code a Contributor-tier session is refused with. */
|
|
@@ -740,6 +785,41 @@ export declare function classifyForHook(command: string, protectedPaths: readonl
|
|
|
740
785
|
* that the `json` veto on colour is the answer this process memoizes.
|
|
741
786
|
*/
|
|
742
787
|
export declare function renderClassification(result: CommandClassification, json: boolean, st?: Style): string;
|
|
788
|
+
/**
|
|
789
|
+
* The gate path from the event to a verdict, as steps (APRV-473).
|
|
790
|
+
*
|
|
791
|
+
* Each value the generator yields is a pause in milliseconds: the wait's poll
|
|
792
|
+
* interval, or `0` for one turn of the event loop and nothing longer. The
|
|
793
|
+
* return value is the verdict. ONE implementation of classify, register,
|
|
794
|
+
* request, wait and spend, run by one of two drivers:
|
|
795
|
+
*
|
|
796
|
+
* - {@link driveSync} sleeps each pause with `Atomics.wait`. Every caller that
|
|
797
|
+
* needs a synchronous answer keeps one: `commandHook` for the in-process
|
|
798
|
+
* callers and the serve worker, `decideHarnessCall` for the Codex bridge. A
|
|
799
|
+
* zero pause is no pause, so their behaviour is what it was.
|
|
800
|
+
* - {@link driveYielding} sleeps each pause on a timer, so the event loop turns
|
|
801
|
+
* while the hook waits and a JS signal listener runs then. Every
|
|
802
|
+
* `approval hook <harness>` CLI route runs through it: Hermes first
|
|
803
|
+
* (APRV-473), which sends SIGTERM on its hook timeout and on gateway
|
|
804
|
+
* shutdown, then Claude Code, Cursor, Codex, Grok and Muse (APRV-475). A
|
|
805
|
+
* signal held through a synchronous wait let a grant that landed afterwards
|
|
806
|
+
* record `execution.started` for a call the harness had already abandoned.
|
|
807
|
+
* The harness makes no difference to the steps: the pause before a spend
|
|
808
|
+
* ({@link BEFORE_SPEND}) and the wait's withdrawing handler are the same code
|
|
809
|
+
* for all six, and only the directive the handler prints is the harness's
|
|
810
|
+
* own ({@link interruptedWaitDirective}).
|
|
811
|
+
*
|
|
812
|
+
* The pauses are the same durations under either driver, so the deadline
|
|
813
|
+
* arithmetic and the poll cadence do not depend on which one runs them.
|
|
814
|
+
*
|
|
815
|
+
* Each `next()` also tells the steps which driver is running them (APRV-478):
|
|
816
|
+
* `true` from {@link driveYielding}, a pause that turns the event loop, and
|
|
817
|
+
* `false` or nothing from {@link driveSync}. The one step that reads it is
|
|
818
|
+
* {@link spendUnderLock}, which waits for the log's lock on the event loop
|
|
819
|
+
* only when there is an event loop to wait on, and otherwise runs the writer's
|
|
820
|
+
* own synchronous wait exactly as before.
|
|
821
|
+
*/
|
|
822
|
+
type GateSteps<T> = Generator<number, T, boolean | undefined>;
|
|
743
823
|
/**
|
|
744
824
|
* Where a hook invocation stops appending and starts waiting, for a caller that
|
|
745
825
|
* shares one store with other work in the same process (APRV-427).
|
|
@@ -963,7 +1043,9 @@ export type HarnessVerdict = {
|
|
|
963
1043
|
code: string;
|
|
964
1044
|
detail: string;
|
|
965
1045
|
};
|
|
966
|
-
export declare function gateHarnessCall(
|
|
1046
|
+
export declare function gateHarnessCall(...args: Parameters<typeof gateHarnessSteps>): HarnessVerdict;
|
|
1047
|
+
/** {@link gateHarnessCall} as steps, for a driver that yields (APRV-473). */
|
|
1048
|
+
declare function gateHarnessSteps(streams: Streams, run: HookRun, classes: string[],
|
|
967
1049
|
/**
|
|
968
1050
|
* The bytes the grant binds to: `{command, cwd}` for a Bash call, the change
|
|
969
1051
|
* itself for a file tool (APRV-124). Whatever this is, it is what reaches the
|
|
@@ -997,7 +1079,7 @@ note?: string,
|
|
|
997
1079
|
* reads, and {@link floorApplies} below carves the read classes out of a mixed
|
|
998
1080
|
* one, so a floor never puts a question about looking on a human's phone.
|
|
999
1081
|
*/
|
|
1000
|
-
floor?: HarnessLoopState | null): HarnessVerdict
|
|
1082
|
+
floor?: HarnessLoopState | null): GateSteps<HarnessVerdict>;
|
|
1001
1083
|
/**
|
|
1002
1084
|
* Every line the counterpart can print, closed and machine-readable (§11.1
|
|
1003
1085
|
* invariant 7).
|
|
@@ -1152,4 +1234,33 @@ export declare function commandHook(argv: string[], streams: Streams, cwd: strin
|
|
|
1152
1234
|
* the call polls. Every CLI route omits it. See {@link HookWaitSeam}.
|
|
1153
1235
|
*/
|
|
1154
1236
|
waitSeam?: HookWaitSeam | null): number;
|
|
1237
|
+
/**
|
|
1238
|
+
* {@link commandHook}, with its pauses on the event loop (APRV-473).
|
|
1239
|
+
*
|
|
1240
|
+
* Every `approval hook` CLI route, from `main`: Hermes since APRV-473, the
|
|
1241
|
+
* other five harnesses (and `classify`, which never pauses) since APRV-475.
|
|
1242
|
+
* The same steps as the synchronous form; the difference is that a SIGTERM or
|
|
1243
|
+
* SIGINT reaches the listener in force within one pause of arriving, instead
|
|
1244
|
+
* of after the run returns. In the wait that listener withdraws the question
|
|
1245
|
+
* this invocation opened, prints the harness's own `hook-interrupted` block
|
|
1246
|
+
* directive ({@link interruptedWaitDirective}) and exits with that directive's
|
|
1247
|
+
* exit code, so a grant that lands after the harness abandoned the call is
|
|
1248
|
+
* never spent on it. See {@link GateSteps} and {@link BEFORE_SPEND}.
|
|
1249
|
+
*/
|
|
1250
|
+
export declare function commandHookYielding(argv: string[], streams: Streams, cwd: string, readStdin?: () => string): Promise<number>;
|
|
1251
|
+
/**
|
|
1252
|
+
* The steps {@link commandHook} and {@link commandHookYielding} drive, for a
|
|
1253
|
+
* test that drives them itself (APRV-475 refuter).
|
|
1254
|
+
*
|
|
1255
|
+
* A test seam and nothing more: it exists so a test can stop at each pause and
|
|
1256
|
+
* look at the log, which is the only deterministic way to pin that the pause
|
|
1257
|
+
* before a spend ({@link BEFORE_SPEND}) sits between the read that found a
|
|
1258
|
+
* grant and the append that spends it, on every harness. No CLI route and no
|
|
1259
|
+
* embedding caller uses it; the one entry for those is the two drivers above.
|
|
1260
|
+
*
|
|
1261
|
+
* Pass `true` to each `next()` to step as {@link commandHookYielding} does
|
|
1262
|
+
* (the spend then waits for a held log lock in yields, APRV-478); `false` or
|
|
1263
|
+
* nothing steps as {@link commandHook} does.
|
|
1264
|
+
*/
|
|
1265
|
+
export declare function commandHookSteps(argv: string[], streams: Streams, cwd: string, readStdin: () => string): Generator<number, number, boolean | undefined>;
|
|
1155
1266
|
export {};
|