@authorbot/domain 0.1.25 → 0.1.27
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 +36 -19
- package/dist/annotation-policy.d.ts +6 -6
- package/dist/annotation-policy.js +4 -4
- package/dist/annotation-state.d.ts +1 -1
- package/dist/annotation-state.js +1 -1
- package/dist/lease-token.d.ts +2 -2
- package/dist/lease-token.js +2 -2
- package/dist/lease.d.ts +4 -4
- package/dist/lease.js +4 -4
- package/dist/overrides.d.ts +1 -1
- package/dist/overrides.js +1 -1
- package/dist/submission.d.ts +1 -1
- package/dist/submission.js +2 -2
- package/dist/token.d.ts +1 -1
- package/dist/token.js +1 -1
- package/dist/vote.d.ts +4 -4
- package/dist/vote.js +4 -4
- package/dist/work-item-lifecycle.d.ts +1 -1
- package/dist/work-item-lifecycle.js +1 -1
- package/dist/work-item-state.d.ts +1 -1
- package/dist/work-item-state.js +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
3
|
What changed in each release, and why it mattered. Written for the person
|
|
4
|
-
deciding whether to upgrade, not for the person who wrote the commit
|
|
4
|
+
deciding whether to upgrade, not for the person who wrote the commit - so a
|
|
5
5
|
release that fixed something serious says what was broken and what it did to
|
|
6
6
|
you, rather than naming the function that changed.
|
|
7
7
|
|
|
@@ -9,11 +9,28 @@ Every published package shares this version. A tag builds, tests, and publishes
|
|
|
9
9
|
all of them together, so `@authorbot/cli@0.1.15` and `@authorbot/api@0.1.15` are
|
|
10
10
|
always the same commit.
|
|
11
11
|
|
|
12
|
+
## 0.1.27
|
|
13
|
+
|
|
14
|
+
- **The reading site and author console have been redesigned together.** The
|
|
15
|
+
reader now has clearer book navigation, chapter context, responsive story
|
|
16
|
+
views, and exact inline annotation highlights. Authors get focused Work,
|
|
17
|
+
Settings, and Access consoles with honest conflict handling, accessible
|
|
18
|
+
controls, and account-aware navigation.
|
|
19
|
+
- Outline, Timeline, and Characters now expose the book's planning structure
|
|
20
|
+
directly, including the planning method selected in `book.yml`.
|
|
21
|
+
- No book-format migration or database migration is required for this release.
|
|
22
|
+
|
|
23
|
+
## 0.1.26
|
|
24
|
+
|
|
25
|
+
- Removed every em-dash and en-dash from the tool's output, docs, and code. No
|
|
26
|
+
behaviour change; the wizard, error messages, and generated files now use
|
|
27
|
+
plain hyphens.
|
|
28
|
+
|
|
12
29
|
## 0.1.25
|
|
13
30
|
|
|
14
31
|
- **The collaborator skill.** `npx skills add JoeMattie/authorbot` installs a
|
|
15
|
-
skill that teaches an agent to contribute to an Authorbot book
|
|
16
|
-
the safety rules, per-role guidance, and the full API reference
|
|
32
|
+
skill that teaches an agent to contribute to an Authorbot book - the loop,
|
|
33
|
+
the safety rules, per-role guidance, and the full API reference - into Claude
|
|
17
34
|
Code and any other supported agent tooling. Also installable as a Claude Code
|
|
18
35
|
plugin (`/plugin marketplace add JoeMattie/authorbot`). The `agent` stage now
|
|
19
36
|
points at it.
|
|
@@ -21,7 +38,7 @@ always the same commit.
|
|
|
21
38
|
## 0.1.24
|
|
22
39
|
|
|
23
40
|
- **`collaborate` commits and pushes what it writes.** It used to ask you to do
|
|
24
|
-
it "when you are ready"
|
|
41
|
+
it "when you are ready" - and until that push lands, the API cannot project
|
|
25
42
|
your book, so the settings page reports that it cannot read its own
|
|
26
43
|
configuration, with nothing connecting the two.
|
|
27
44
|
- **The agent stage stopped asking for a maintainer bearer token.** No author
|
|
@@ -29,7 +46,7 @@ always the same commit.
|
|
|
29
46
|
credential from elsewhere. `AUTHORBOT_API_TOKEN` still works for that case,
|
|
30
47
|
and everyone else is sent to the button on the settings page.
|
|
31
48
|
- Declining an optional step no longer tells you to run that step "to
|
|
32
|
-
continue", which made every optional thing look unfinished
|
|
49
|
+
continue", which made every optional thing look unfinished - `upgrade` most
|
|
33
50
|
of all, on a book far too new to need it.
|
|
34
51
|
|
|
35
52
|
## 0.1.23
|
|
@@ -44,7 +61,7 @@ always the same commit.
|
|
|
44
61
|
- **You can create an agent token from your book's settings.** Until now
|
|
45
62
|
nothing in Authorbot could make one: the API needs a maintainer session,
|
|
46
63
|
which only a browser holds, and the settings page could list and revoke
|
|
47
|
-
tokens but not create them
|
|
64
|
+
tokens but not create them - while the setup wizard asked for a bearer token
|
|
48
65
|
no author has ever been issued. The control sits under Agent tokens, shows
|
|
49
66
|
the value once, and defaults to the narrowest scopes an agent needs to read
|
|
50
67
|
chapters, claim work, and submit a draft.
|
|
@@ -53,7 +70,7 @@ always the same commit.
|
|
|
53
70
|
|
|
54
71
|
- **Installing the GitHub App no longer lands you on a 404.** GitHub was asked
|
|
55
72
|
to run its OAuth flow during installation, which redirected to a callback
|
|
56
|
-
that cannot exist yet
|
|
73
|
+
that cannot exist yet - the Worker's config needs the installation id that
|
|
57
74
|
installing is in the middle of producing. It now returns you to your book's
|
|
58
75
|
own site.
|
|
59
76
|
- **The agent stage stopped asking for a credential nobody has.** It wanted "a
|
|
@@ -68,8 +85,8 @@ always the same commit.
|
|
|
68
85
|
- **The GitHub App key was stored in a format the Worker cannot read.** GitHub's
|
|
69
86
|
manifest hands back a PKCS#1 key; WebCrypto, which is all a Cloudflare Worker
|
|
70
87
|
has, can only import PKCS#8. So every book reported its integration as
|
|
71
|
-
`invalid` and did no Git work at all
|
|
72
|
-
projection never ran, settings could not read `book.yml`
|
|
88
|
+
`invalid` and did no Git work at all - chapters could not be saved, the
|
|
89
|
+
projection never ran, settings could not read `book.yml` - with all three
|
|
73
90
|
credentials present and correct. **Books set up before this release need
|
|
74
91
|
their GitHub App deleted and `collaborate` run again**, because the key was
|
|
75
92
|
stored once and cannot be re-read.
|
|
@@ -81,7 +98,7 @@ always the same commit.
|
|
|
81
98
|
|
|
82
99
|
## 0.1.19
|
|
83
100
|
|
|
84
|
-
- Spinners with an elapsed timer on the steps that take minutes
|
|
101
|
+
- Spinners with an elapsed timer on the steps that take minutes - installing
|
|
85
102
|
the toolchain, waiting for a site to answer, checking the API. Silence for
|
|
86
103
|
four minutes reads as a hang.
|
|
87
104
|
- The mark is centred on the terminal's true width.
|
|
@@ -99,7 +116,7 @@ always the same commit.
|
|
|
99
116
|
- **`npm install` failed for everyone who started the documented way.** npx
|
|
100
117
|
exports its own configuration as `npm_config_*`, the wizard's `npm install`
|
|
101
118
|
inherited it, and resolved against npx's cache directory instead of your
|
|
102
|
-
book
|
|
119
|
+
book - so the install failed and you were left without a
|
|
103
120
|
`package-lock.json`, which both generated workflows refuse to run without. It
|
|
104
121
|
worked fine for anyone running the built binary directly, which is why it
|
|
105
122
|
looked like a problem with the machine.
|
|
@@ -113,10 +130,10 @@ always the same commit.
|
|
|
113
130
|
- **`unpublish` and `teardown`.** `npx @authorbot/create unpublish` removes the
|
|
114
131
|
Worker, the database and the GitHub App, leaving your repository and its
|
|
115
132
|
history alone so `publish` can put the site back. `teardown` also deletes the
|
|
116
|
-
remote repository, then tells you what to type to remove the local copy
|
|
133
|
+
remote repository, then tells you what to type to remove the local copy - it
|
|
117
134
|
never deletes files on your own disk.
|
|
118
135
|
- **The wizard is drawn rather than printed**: boxed stage headings, an arrow
|
|
119
|
-
for steps, and check/triangle/cross for outcomes
|
|
136
|
+
for steps, and check/triangle/cross for outcomes - each degrading to plain
|
|
120
137
|
ASCII under `NO_COLOR`, in a pipe, or on a dumb terminal.
|
|
121
138
|
- **A changelog**, here and inside every published package.
|
|
122
139
|
|
|
@@ -124,7 +141,7 @@ always the same commit.
|
|
|
124
141
|
|
|
125
142
|
- **The wizard can tell whether your book can actually save anything.** It used
|
|
126
143
|
to finish by checking that the API refused an anonymous caller, which a
|
|
127
|
-
completely unusable deployment does just as correctly as a healthy one
|
|
144
|
+
completely unusable deployment does just as correctly as a healthy one - see
|
|
128
145
|
0.1.14. New `GET /v1/health` reports whether the GitHub App is usable, and
|
|
129
146
|
`collaborate` refuses to switch a book's collaboration controls on when the
|
|
130
147
|
answer is no.
|
|
@@ -134,14 +151,14 @@ always the same commit.
|
|
|
134
151
|
- **Collaboration never worked on any book this wizard created.** The Worker
|
|
135
152
|
needs three GitHub App credentials and received two: the app id was read,
|
|
136
153
|
used to poll for the installation, and then dropped. With one missing it does
|
|
137
|
-
no Git work at all
|
|
154
|
+
no Git work at all - so chapters could not be saved, the projection never
|
|
138
155
|
ran, and settings could not read the book's own `book.yml`, while every
|
|
139
156
|
read-only page answered perfectly. If you set up a book before this release,
|
|
140
157
|
re-run `create-authorbot collaborate`.
|
|
141
158
|
- **You can sign out.** There was no way to. Two routes created a session and
|
|
142
159
|
none ended one, so a reader on a shared machine stayed signed in until the
|
|
143
160
|
cookie expired.
|
|
144
|
-
- **An account strip in the site header**
|
|
161
|
+
- **An account strip in the site header** - sign in, sign out, and the way into
|
|
145
162
|
Settings and the work queue. Previously a book with no chapters had no
|
|
146
163
|
sign-in anywhere, and `/settings/` and `/work/` were linked from nowhere.
|
|
147
164
|
- The API health check polls instead of judging on its first answer, which was
|
|
@@ -157,7 +174,7 @@ always the same commit.
|
|
|
157
174
|
|
|
158
175
|
- **A book with collaboration on showed no sign-in and no annotations.**
|
|
159
176
|
`book.yml` said annotations were public; the Worker was never told, so the
|
|
160
|
-
API refused every anonymous read
|
|
177
|
+
API refused every anonymous read - and the site gives up and renders nothing
|
|
161
178
|
when its first read fails, removing the very control that would have fixed
|
|
162
179
|
it.
|
|
163
180
|
|
|
@@ -194,7 +211,7 @@ always the same commit.
|
|
|
194
211
|
## 0.1.7
|
|
195
212
|
|
|
196
213
|
- **A successful deploy was reported as a failure** when the local resolver
|
|
197
|
-
still had the new hostname cached as non-existent
|
|
214
|
+
still had the new hostname cached as non-existent - which the wizard's own
|
|
198
215
|
domain check made near-certain.
|
|
199
216
|
- Every "run this to carry on" hint named `create-authorbot`, a binary `npx`
|
|
200
217
|
never installs.
|
|
@@ -212,7 +229,7 @@ always the same commit.
|
|
|
212
229
|
## 0.1.5
|
|
213
230
|
|
|
214
231
|
- Pointing the wizard at a directory that did not exist yet failed with a bare
|
|
215
|
-
ENOENT
|
|
232
|
+
ENOENT - including for the `directory: ./my-book` its own example config
|
|
216
233
|
prints.
|
|
217
234
|
- The pinned GitHub Actions moved off a deprecated line.
|
|
218
235
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Annotation policy (Phase 7 contract "Restricting")
|
|
2
|
+
* Annotation policy (Phase 7 contract "Restricting") - who may write to a
|
|
3
3
|
* book, and whether what they write appears immediately.
|
|
4
4
|
*
|
|
5
5
|
* | Mode | Who may write | Appears |
|
|
@@ -36,7 +36,7 @@ export type AnnotationPolicy = (typeof ANNOTATION_POLICIES)[number];
|
|
|
36
36
|
* The mode a book with no declared policy runs in: the Phase 2 behaviour,
|
|
37
37
|
* unchanged. A deployment upgrading into Phase 7 must not find its book
|
|
38
38
|
* suddenly writable by strangers, so the default is the restrictive end of the
|
|
39
|
-
* progression that people were already on
|
|
39
|
+
* progression that people were already on - not the permissive end, and not
|
|
40
40
|
* `locked` either, which would lock out the collaborators they already have.
|
|
41
41
|
*/
|
|
42
42
|
export declare const DEFAULT_ANNOTATION_POLICY: AnnotationPolicy;
|
|
@@ -52,21 +52,21 @@ export type AnnotationPolicyDenialReason =
|
|
|
52
52
|
| "locked"
|
|
53
53
|
/**
|
|
54
54
|
* Signed in and not a member, asking for something a non-member could never
|
|
55
|
-
* do (voting, claiming, submitting) even in an open book
|
|
55
|
+
* do (voting, claiming, submitting) even in an open book - those are member
|
|
56
56
|
* capabilities, and `open` widens commenting, not the work queue.
|
|
57
57
|
*/
|
|
58
58
|
| "member-capability";
|
|
59
59
|
/**
|
|
60
60
|
* The write capabilities the policy arbitrates.
|
|
61
61
|
*
|
|
62
|
-
* `annotate` is the one the policy table is actually about
|
|
62
|
+
* `annotate` is the one the policy table is actually about - commenting and
|
|
63
63
|
* suggesting. The other three are member capabilities that `open` and
|
|
64
64
|
* `approval-gated` do NOT widen to strangers: a book that welcomes comments
|
|
65
65
|
* from the internet is not thereby handing the internet its governance votes
|
|
66
66
|
* or its work queue.
|
|
67
67
|
*
|
|
68
68
|
* `locked` restricts all four, because "existing collaborators keep their
|
|
69
|
-
* membership and their history
|
|
69
|
+
* membership and their history - they simply cannot write until the policy
|
|
70
70
|
* opens again", and a vote that manufactures a work item is unambiguously a
|
|
71
71
|
* write.
|
|
72
72
|
*/
|
|
@@ -83,7 +83,7 @@ export interface AnnotationPolicyRequest {
|
|
|
83
83
|
* Decide whether the policy admits this write.
|
|
84
84
|
*
|
|
85
85
|
* This answers the policy question ONLY. Scope checks, freeze, the agent pause,
|
|
86
|
-
* and rate limits are separate gates applied alongside it
|
|
86
|
+
* and rate limits are separate gates applied alongside it - a request must
|
|
87
87
|
* satisfy all of them, and each refuses with its own problem type so the caller
|
|
88
88
|
* can tell "the book is locked" from "the book is frozen" from "you are going
|
|
89
89
|
* too fast".
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Annotation policy (Phase 7 contract "Restricting")
|
|
2
|
+
* Annotation policy (Phase 7 contract "Restricting") - who may write to a
|
|
3
3
|
* book, and whether what they write appears immediately.
|
|
4
4
|
*
|
|
5
5
|
* | Mode | Who may write | Appears |
|
|
@@ -39,7 +39,7 @@ export const ANNOTATION_POLICIES = [
|
|
|
39
39
|
* The mode a book with no declared policy runs in: the Phase 2 behaviour,
|
|
40
40
|
* unchanged. A deployment upgrading into Phase 7 must not find its book
|
|
41
41
|
* suddenly writable by strangers, so the default is the restrictive end of the
|
|
42
|
-
* progression that people were already on
|
|
42
|
+
* progression that people were already on - not the permissive end, and not
|
|
43
43
|
* `locked` either, which would lock out the collaborators they already have.
|
|
44
44
|
*/
|
|
45
45
|
export const DEFAULT_ANNOTATION_POLICY = "collaborators-only";
|
|
@@ -54,7 +54,7 @@ export function policyRequiresApproval(policy) {
|
|
|
54
54
|
* Decide whether the policy admits this write.
|
|
55
55
|
*
|
|
56
56
|
* This answers the policy question ONLY. Scope checks, freeze, the agent pause,
|
|
57
|
-
* and rate limits are separate gates applied alongside it
|
|
57
|
+
* and rate limits are separate gates applied alongside it - a request must
|
|
58
58
|
* satisfy all of them, and each refuses with its own problem type so the caller
|
|
59
59
|
* can tell "the book is locked" from "the book is frozen" from "you are going
|
|
60
60
|
* too fast".
|
|
@@ -89,7 +89,7 @@ export function checkAnnotationPolicy(request) {
|
|
|
89
89
|
}
|
|
90
90
|
return ALLOWED;
|
|
91
91
|
}
|
|
92
|
-
// collaborators-only
|
|
92
|
+
// collaborators-only - the Phase 2 behaviour, and the default.
|
|
93
93
|
if (isMember) {
|
|
94
94
|
return ALLOWED;
|
|
95
95
|
}
|
|
@@ -8,7 +8,7 @@ export type { AnnotationStatus };
|
|
|
8
8
|
* section 4). `open` fans out; `rejected -> open` is the Phase 3 maintainer
|
|
9
9
|
* reopen override (Phase 3 contract section 4); every other status is
|
|
10
10
|
* terminal. The reanchor flow (`needs_reanchor -> open`) is intentionally not
|
|
11
|
-
* legal yet
|
|
11
|
+
* legal yet - adding transitions later is additive.
|
|
12
12
|
*/
|
|
13
13
|
export declare const ANNOTATION_TRANSITIONS: Readonly<Record<AnnotationStatus, readonly AnnotationStatus[]>>;
|
|
14
14
|
export declare function canTransitionAnnotation(from: AnnotationStatus, to: AnnotationStatus): boolean;
|
package/dist/annotation-state.js
CHANGED
|
@@ -6,7 +6,7 @@ export { ANNOTATION_STATUSES };
|
|
|
6
6
|
* section 4). `open` fans out; `rejected -> open` is the Phase 3 maintainer
|
|
7
7
|
* reopen override (Phase 3 contract section 4); every other status is
|
|
8
8
|
* terminal. The reanchor flow (`needs_reanchor -> open`) is intentionally not
|
|
9
|
-
* legal yet
|
|
9
|
+
* legal yet - adding transitions later is additive.
|
|
10
10
|
*/
|
|
11
11
|
export const ANNOTATION_TRANSITIONS = Object.freeze({
|
|
12
12
|
open: [
|
package/dist/lease-token.d.ts
CHANGED
|
@@ -3,11 +3,11 @@ import { z } from "zod";
|
|
|
3
3
|
* Lease-token FORMAT helpers only (Phase 4 contract section 2): parse and
|
|
4
4
|
* shape-check, no crypto. Generating the 256-bit random secret, hashing it
|
|
5
5
|
* (SHA-256), storing only the hash, and the constant-time compare are the
|
|
6
|
-
* API layer's job
|
|
6
|
+
* API layer's job - exactly the split used for agent tokens in `token.ts`.
|
|
7
7
|
* Failure results carry a reason only and never echo any part of the value;
|
|
8
8
|
* lease tokens are never logged.
|
|
9
9
|
*
|
|
10
|
-
* Format (resolved ambiguity
|
|
10
|
+
* Format (resolved ambiguity - the contracts pin "opaque 256-bit token" but
|
|
11
11
|
* no encoding): `authorbot_lease_` + 43 base64url chars, matching the agent
|
|
12
12
|
* token secret encoding. The distinct prefix makes a leaked lease token
|
|
13
13
|
* identifiable and unconfusable with an agent credential (an agent token is
|
package/dist/lease-token.js
CHANGED
|
@@ -3,11 +3,11 @@ import { z } from "zod";
|
|
|
3
3
|
* Lease-token FORMAT helpers only (Phase 4 contract section 2): parse and
|
|
4
4
|
* shape-check, no crypto. Generating the 256-bit random secret, hashing it
|
|
5
5
|
* (SHA-256), storing only the hash, and the constant-time compare are the
|
|
6
|
-
* API layer's job
|
|
6
|
+
* API layer's job - exactly the split used for agent tokens in `token.ts`.
|
|
7
7
|
* Failure results carry a reason only and never echo any part of the value;
|
|
8
8
|
* lease tokens are never logged.
|
|
9
9
|
*
|
|
10
|
-
* Format (resolved ambiguity
|
|
10
|
+
* Format (resolved ambiguity - the contracts pin "opaque 256-bit token" but
|
|
11
11
|
* no encoding): `authorbot_lease_` + 43 base64url chars, matching the agent
|
|
12
12
|
* token secret encoding. The distinct prefix makes a leaked lease token
|
|
13
13
|
* identifiable and unconfusable with an agent credential (an agent token is
|
package/dist/lease.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ export type IsoDurationParseResult = {
|
|
|
18
18
|
};
|
|
19
19
|
/**
|
|
20
20
|
* Parse the ISO-8601 duration subset the contracts use (`PT30M`, `PT4H`,
|
|
21
|
-
* `P1D`, combinations with integer designators; no years/months/weeks
|
|
21
|
+
* `P1D`, combinations with integer designators; no years/months/weeks -
|
|
22
22
|
* calendar units are ambiguous in milliseconds). Used to validate `LEASE_*`
|
|
23
23
|
* env overrides at boot (Phase 4 contract section 2).
|
|
24
24
|
*/
|
|
@@ -66,7 +66,7 @@ export type LeaseInactiveReason = "expired" | "released" | "revoked";
|
|
|
66
66
|
* Whether a lease still backs commands at `now`. Check order follows the
|
|
67
67
|
* contract section 4 verification order ("not expired / not released"):
|
|
68
68
|
* expired first, then released, then revoked. Used by renew, release, and
|
|
69
|
-
* submission checks alike
|
|
69
|
+
* submission checks alike - an expired, released, or revoked lease can do
|
|
70
70
|
* nothing further (contract section 2: renewing an expired lease is a 409).
|
|
71
71
|
*/
|
|
72
72
|
export declare function checkLeaseActive(lease: LeaseSnapshot, now: Date): Decision<LeaseInactiveReason>;
|
|
@@ -93,7 +93,7 @@ export type ClaimCheckResult = {
|
|
|
93
93
|
* "none" is unambiguous). That combination is what an interrupted expiry or a
|
|
94
94
|
* bare administrative revocation leaves behind, and treating it as
|
|
95
95
|
* `lease-held` made such items permanently unclaimable, unreleasable, and
|
|
96
|
-
* unsweepable
|
|
96
|
+
* unsweepable - recoverable only by direct database surgery. Claiming
|
|
97
97
|
* self-heals it instead: `priorLeaseExpired` sends the caller down the
|
|
98
98
|
* expire-then-claim path, whose compare-and-swap starts from `leased`.
|
|
99
99
|
*/
|
|
@@ -108,7 +108,7 @@ export type RenewCheckResult = {
|
|
|
108
108
|
* renews; the new expiry is the current `expires_at` plus the renewal
|
|
109
109
|
* duration ("extends by"), clamped to `max_expires_at`. When the lease
|
|
110
110
|
* already sits at its max-total cap so no extension is possible, the renewal
|
|
111
|
-
* is rejected with `max-total-exceeded` rather than succeeding as a no-op
|
|
111
|
+
* is rejected with `max-total-exceeded` rather than succeeding as a no-op -
|
|
112
112
|
* a partially clamped extension is still allowed. Verifying the presented
|
|
113
113
|
* token against the stored hash happens before this in the API layer.
|
|
114
114
|
*/
|
package/dist/lease.js
CHANGED
|
@@ -26,7 +26,7 @@ export const LEASE_RENEWAL_PROMPT_BEFORE_MS = 5 * MS_PER_MINUTE;
|
|
|
26
26
|
const ISO_DURATION_REGEX = /^P(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?$/;
|
|
27
27
|
/**
|
|
28
28
|
* Parse the ISO-8601 duration subset the contracts use (`PT30M`, `PT4H`,
|
|
29
|
-
* `P1D`, combinations with integer designators; no years/months/weeks
|
|
29
|
+
* `P1D`, combinations with integer designators; no years/months/weeks -
|
|
30
30
|
* calendar units are ambiguous in milliseconds). Used to validate `LEASE_*`
|
|
31
31
|
* env overrides at boot (Phase 4 contract section 2).
|
|
32
32
|
*/
|
|
@@ -97,7 +97,7 @@ export function isLeaseExpired(lease, now) {
|
|
|
97
97
|
* Whether a lease still backs commands at `now`. Check order follows the
|
|
98
98
|
* contract section 4 verification order ("not expired / not released"):
|
|
99
99
|
* expired first, then released, then revoked. Used by renew, release, and
|
|
100
|
-
* submission checks alike
|
|
100
|
+
* submission checks alike - an expired, released, or revoked lease can do
|
|
101
101
|
* nothing further (contract section 2: renewing an expired lease is a 409).
|
|
102
102
|
*/
|
|
103
103
|
export function checkLeaseActive(lease, now) {
|
|
@@ -125,7 +125,7 @@ export function checkLeaseActive(lease, now) {
|
|
|
125
125
|
* "none" is unambiguous). That combination is what an interrupted expiry or a
|
|
126
126
|
* bare administrative revocation leaves behind, and treating it as
|
|
127
127
|
* `lease-held` made such items permanently unclaimable, unreleasable, and
|
|
128
|
-
* unsweepable
|
|
128
|
+
* unsweepable - recoverable only by direct database surgery. Claiming
|
|
129
129
|
* self-heals it instead: `priorLeaseExpired` sends the caller down the
|
|
130
130
|
* expire-then-claim path, whose compare-and-swap starts from `leased`.
|
|
131
131
|
*/
|
|
@@ -146,7 +146,7 @@ export function checkWorkItemClaimable(status, activeLease, now) {
|
|
|
146
146
|
* renews; the new expiry is the current `expires_at` plus the renewal
|
|
147
147
|
* duration ("extends by"), clamped to `max_expires_at`. When the lease
|
|
148
148
|
* already sits at its max-total cap so no extension is possible, the renewal
|
|
149
|
-
* is rejected with `max-total-exceeded` rather than succeeding as a no-op
|
|
149
|
+
* is rejected with `max-total-exceeded` rather than succeeding as a no-op -
|
|
150
150
|
* a partially clamped extension is still allowed. Verifying the presented
|
|
151
151
|
* token against the stored hash happens before this in the API layer.
|
|
152
152
|
*/
|
package/dist/overrides.d.ts
CHANGED
|
@@ -36,7 +36,7 @@ export declare const reopenSuggestionCommandSchema: z.ZodObject<{
|
|
|
36
36
|
export type ReopenSuggestionCommand = z.infer<typeof reopenSuggestionCommandSchema>;
|
|
37
37
|
/**
|
|
38
38
|
* Override 4: force-create a work item bypassing the rule. `work_type` is not
|
|
39
|
-
* part of the command
|
|
39
|
+
* part of the command - it resolves from the annotation scope exactly as
|
|
40
40
|
* rule-created items do (Phase 3 contract section 3).
|
|
41
41
|
*/
|
|
42
42
|
export declare const forceCreateWorkItemCommandSchema: z.ZodObject<{
|
package/dist/overrides.js
CHANGED
|
@@ -38,7 +38,7 @@ export const reopenSuggestionCommandSchema = z.strictObject({
|
|
|
38
38
|
});
|
|
39
39
|
/**
|
|
40
40
|
* Override 4: force-create a work item bypassing the rule. `work_type` is not
|
|
41
|
-
* part of the command
|
|
41
|
+
* part of the command - it resolves from the annotation scope exactly as
|
|
42
42
|
* rule-created items do (Phase 3 contract section 3).
|
|
43
43
|
*/
|
|
44
44
|
export const forceCreateWorkItemCommandSchema = z.strictObject({
|
package/dist/submission.d.ts
CHANGED
|
@@ -75,7 +75,7 @@ export type SubmissionBaseDenialReason = "base-revision-mismatch" | "base-hash-m
|
|
|
75
75
|
* (contract section 4). Revision is checked before hash so the commoner
|
|
76
76
|
* staleness cause surfaces first. Hash comparison here is not secret
|
|
77
77
|
* material (both values are content hashes the client already holds), so a
|
|
78
|
-
* plain compare is correct
|
|
78
|
+
* plain compare is correct - constant-time treatment is for lease tokens.
|
|
79
79
|
*/
|
|
80
80
|
export declare function checkSubmissionBase(bundle: {
|
|
81
81
|
readonly baseRevision: number;
|
package/dist/submission.js
CHANGED
|
@@ -70,7 +70,7 @@ export const contentHashSchema = z
|
|
|
70
70
|
.regex(CONTENT_HASH_REGEX, "must be 'sha256:' followed by 64 lowercase hex characters");
|
|
71
71
|
/**
|
|
72
72
|
* Replacement content: CRLF folded to LF (matching chapter storage) but NOT
|
|
73
|
-
* trimmed
|
|
73
|
+
* trimmed - leading/trailing whitespace is meaningful in a range
|
|
74
74
|
* replacement. Emptiness is a per-type rule handled in the command schema:
|
|
75
75
|
* an empty `range_replacement` is a deletion and legal; block and chapter
|
|
76
76
|
* replacements must be non-empty.
|
|
@@ -118,7 +118,7 @@ export const submitWorkCommandSchema = z
|
|
|
118
118
|
* (contract section 4). Revision is checked before hash so the commoner
|
|
119
119
|
* staleness cause surfaces first. Hash comparison here is not secret
|
|
120
120
|
* material (both values are content hashes the client already holds), so a
|
|
121
|
-
* plain compare is correct
|
|
121
|
+
* plain compare is correct - constant-time treatment is for lease tokens.
|
|
122
122
|
*/
|
|
123
123
|
export function checkSubmissionBase(bundle, submission) {
|
|
124
124
|
if (submission.baseRevision !== bundle.baseRevision) {
|
package/dist/token.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export type AgentTokenParseResult = {
|
|
|
22
22
|
};
|
|
23
23
|
/**
|
|
24
24
|
* Shape-check a presented credential and split off the secret part (which the
|
|
25
|
-
* API layer hashes for lookup). Failure results carry a reason only
|
|
25
|
+
* API layer hashes for lookup). Failure results carry a reason only - never
|
|
26
26
|
* any fragment of the presented value.
|
|
27
27
|
*/
|
|
28
28
|
export declare function parseAgentToken(value: string): AgentTokenParseResult;
|
package/dist/token.js
CHANGED
|
@@ -19,7 +19,7 @@ export function isAgentTokenFormat(value) {
|
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
21
|
* Shape-check a presented credential and split off the secret part (which the
|
|
22
|
-
* API layer hashes for lookup). Failure results carry a reason only
|
|
22
|
+
* API layer hashes for lookup). Failure results carry a reason only - never
|
|
23
23
|
* any fragment of the presented value.
|
|
24
24
|
*/
|
|
25
25
|
export function parseAgentToken(value) {
|
package/dist/vote.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export declare const voteValueSchema: z.ZodEnum<{
|
|
|
15
15
|
abstain: "abstain";
|
|
16
16
|
}>;
|
|
17
17
|
export type VoteValue = z.infer<typeof voteValueSchema>;
|
|
18
|
-
/** `PUT .../annotations/{annotationId}/vote`
|
|
18
|
+
/** `PUT .../annotations/{annotationId}/vote` - route param + body merged. */
|
|
19
19
|
export declare const castVoteCommandSchema: z.ZodObject<{
|
|
20
20
|
annotationId: z.ZodString;
|
|
21
21
|
value: z.ZodEnum<{
|
|
@@ -25,7 +25,7 @@ export declare const castVoteCommandSchema: z.ZodObject<{
|
|
|
25
25
|
}>;
|
|
26
26
|
}, z.core.$strict>;
|
|
27
27
|
export type CastVoteCommand = z.infer<typeof castVoteCommandSchema>;
|
|
28
|
-
/** `DELETE .../annotations/{annotationId}/vote`
|
|
28
|
+
/** `DELETE .../annotations/{annotationId}/vote` - the command is the route param. */
|
|
29
29
|
export declare const clearVoteCommandSchema: z.ZodObject<{
|
|
30
30
|
annotationId: z.ZodString;
|
|
31
31
|
}, z.core.$strict>;
|
|
@@ -33,8 +33,8 @@ export type ClearVoteCommand = z.infer<typeof clearVoteCommandSchema>;
|
|
|
33
33
|
export type VoteDenialReason = "not-a-suggestion";
|
|
34
34
|
/**
|
|
35
35
|
* Suggestion-only guard (contract section 2: votes on comments → 422). Votes
|
|
36
|
-
* stay legal after `open`
|
|
37
|
-
* `work_item_created` annotations (contract section 4)
|
|
36
|
+
* stay legal after `open` - sticky decisions require tracking vote changes on
|
|
37
|
+
* `work_item_created` annotations (contract section 4) - so annotation status
|
|
38
38
|
* is deliberately not checked here; `votes:write` scope enforcement is the
|
|
39
39
|
* API layer's (`requireScope`).
|
|
40
40
|
*/
|
package/dist/vote.js
CHANGED
|
@@ -10,19 +10,19 @@ import { ALLOWED, denied } from "./decision.js";
|
|
|
10
10
|
/** Vote values (contract section 2; mirrors `authorbot.instance/v1` `votes.values`). */
|
|
11
11
|
export const VOTE_VALUES = ["approve", "reject", "abstain"];
|
|
12
12
|
export const voteValueSchema = z.enum(VOTE_VALUES);
|
|
13
|
-
/** `PUT .../annotations/{annotationId}/vote`
|
|
13
|
+
/** `PUT .../annotations/{annotationId}/vote` - route param + body merged. */
|
|
14
14
|
export const castVoteCommandSchema = z.strictObject({
|
|
15
15
|
annotationId: uuidv7Schema,
|
|
16
16
|
value: voteValueSchema,
|
|
17
17
|
});
|
|
18
|
-
/** `DELETE .../annotations/{annotationId}/vote`
|
|
18
|
+
/** `DELETE .../annotations/{annotationId}/vote` - the command is the route param. */
|
|
19
19
|
export const clearVoteCommandSchema = z.strictObject({
|
|
20
20
|
annotationId: uuidv7Schema,
|
|
21
21
|
});
|
|
22
22
|
/**
|
|
23
23
|
* Suggestion-only guard (contract section 2: votes on comments → 422). Votes
|
|
24
|
-
* stay legal after `open`
|
|
25
|
-
* `work_item_created` annotations (contract section 4)
|
|
24
|
+
* stay legal after `open` - sticky decisions require tracking vote changes on
|
|
25
|
+
* `work_item_created` annotations (contract section 4) - so annotation status
|
|
26
26
|
* is deliberately not checked here; `votes:write` scope enforcement is the
|
|
27
27
|
* API layer's (`requireScope`).
|
|
28
28
|
*/
|
|
@@ -5,7 +5,7 @@ import { type Decision, type Denied } from "./decision.js";
|
|
|
5
5
|
* Phase 3 gate lifted (Phase 4 contract sections 2, 4, 5). The graph itself
|
|
6
6
|
* has been declared since Phase 3 (`WORK_ITEM_TRANSITIONS`); this module
|
|
7
7
|
* adds the executable, trigger-labelled form. `transitionWorkItem` (the
|
|
8
|
-
* Phase 3-gated function) is left untouched for compatibility
|
|
8
|
+
* Phase 3-gated function) is left untouched for compatibility - Phase 4
|
|
9
9
|
* call sites use `transitionWorkItemPhase4` / `applyWorkItemTrigger`.
|
|
10
10
|
*/
|
|
11
11
|
/**
|
|
@@ -6,7 +6,7 @@ import { WORK_ITEM_TRANSITIONS, canTransitionWorkItem } from "./work-item-state.
|
|
|
6
6
|
* Phase 3 gate lifted (Phase 4 contract sections 2, 4, 5). The graph itself
|
|
7
7
|
* has been declared since Phase 3 (`WORK_ITEM_TRANSITIONS`); this module
|
|
8
8
|
* adds the executable, trigger-labelled form. `transitionWorkItem` (the
|
|
9
|
-
* Phase 3-gated function) is left untouched for compatibility
|
|
9
|
+
* Phase 3-gated function) is left untouched for compatibility - Phase 4
|
|
10
10
|
* call sites use `transitionWorkItemPhase4` / `applyWorkItemTrigger`.
|
|
11
11
|
*/
|
|
12
12
|
/**
|
|
@@ -5,7 +5,7 @@ export type { WorkItemStatus };
|
|
|
5
5
|
/**
|
|
6
6
|
* Work-item state machine (design section 9.5). The full transition graph is
|
|
7
7
|
* declared so Phase 4 is additive data, but Phase 3 stops at `ready` (Phase 3
|
|
8
|
-
* contract section 1: claims/leases/submissions are out of scope)
|
|
8
|
+
* contract section 1: claims/leases/submissions are out of scope) - the only
|
|
9
9
|
* transition that may actually execute is `ready -> cancelled` (maintainer
|
|
10
10
|
* cancel). Every other graph edge is phase-gated: legal in the design, denied
|
|
11
11
|
* at runtime with `phase-not-enabled` until Phase 4 lifts the gate.
|
package/dist/work-item-state.js
CHANGED
|
@@ -4,7 +4,7 @@ export { WORK_ITEM_STATUSES };
|
|
|
4
4
|
/**
|
|
5
5
|
* Work-item state machine (design section 9.5). The full transition graph is
|
|
6
6
|
* declared so Phase 4 is additive data, but Phase 3 stops at `ready` (Phase 3
|
|
7
|
-
* contract section 1: claims/leases/submissions are out of scope)
|
|
7
|
+
* contract section 1: claims/leases/submissions are out of scope) - the only
|
|
8
8
|
* transition that may actually execute is `ready -> cancelled` (maintainer
|
|
9
9
|
* cancel). Every other graph edge is phase-gated: legal in the design, denied
|
|
10
10
|
* at runtime with `phase-not-enabled` until Phase 4 lifts the gate.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@authorbot/domain",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.27",
|
|
4
4
|
"description": "Pure domain logic for Authorbot: role/scope authorization, annotation and Git-operation state machines, command validators, and token/session value rules (Phase 2 contract section 3)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"authorbot",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"zod": "^4.0.0",
|
|
43
|
-
"@authorbot/schemas": "0.1.
|
|
43
|
+
"@authorbot/schemas": "0.1.27"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/node": "^22.0.0",
|