@extrovert.dev/sdk 0.1.0-pre.7 → 0.1.0-pre.8
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/README.md +4 -4
- package/dist/index.cjs +42 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +33 -6
- package/dist/index.d.ts +33 -6
- package/dist/index.js +42 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ for a stable release:
|
|
|
30
30
|
npm install @extrovert.dev/sdk@next
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
Pin `@extrovert.dev/sdk@0.1.0-pre.
|
|
33
|
+
Pin `@extrovert.dev/sdk@0.1.0-pre.8` when a dogfood test needs a reproducible contract snapshot.
|
|
34
34
|
Requires Node 18+ for global `fetch` and Web Crypto.
|
|
35
35
|
|
|
36
36
|
## Build and use from source
|
|
@@ -529,7 +529,7 @@ a wire protocol (there is no `/v1/contract` endpoint).
|
|
|
529
529
|
```ts
|
|
530
530
|
import { CONTRACT_VERSION, CONTRACT_MANIFEST } from "@extrovert.dev/sdk";
|
|
531
531
|
|
|
532
|
-
CONTRACT_VERSION; // "0.1.0-pre.
|
|
532
|
+
CONTRACT_VERSION; // "0.1.0-pre.8": provisional, pre-1.0; pin it
|
|
533
533
|
CONTRACT_MANIFEST.stability; // "provisional"
|
|
534
534
|
CONTRACT_MANIFEST.core_shapes; // ["ReviewIntent","ReviewFeedback","DiffJson","Rule","ReviewEvent"]
|
|
535
535
|
```
|
|
@@ -550,7 +550,7 @@ page and the agent skills (`extrovert-send-email`, `extrovert-writing-rules`).
|
|
|
550
550
|
The Review-Loop shapes are an **open, documented contract: versioned *with* this SDK** (not a wire
|
|
551
551
|
protocol; there is no `/v1/contract` endpoint). Three guarantees:
|
|
552
552
|
|
|
553
|
-
- **One version, everywhere.** `CONTRACT_VERSION` is **`0.1.0-pre.
|
|
553
|
+
- **One version, everywhere.** `CONTRACT_VERSION` is **`0.1.0-pre.8`**, reconciled across the SDK package
|
|
554
554
|
version, the MCP server, and the OpenAPI `info.version`. Pin it; pin `CONTRACT_MANIFEST` for the
|
|
555
555
|
exact shape set you built against.
|
|
556
556
|
- **Named, documented types.** The five canonical shapes: `ReviewIntent`, `ReviewFeedback`,
|
|
@@ -581,7 +581,7 @@ EXTROVERT_API_BASE_URL=mock npx tsx examples/wait-for-otp.ts
|
|
|
581
581
|
|
|
582
582
|
## Status
|
|
583
583
|
|
|
584
|
-
> **Note.** This source SDK tracks the `/v1` contract at `CONTRACT_VERSION` `0.1.0-pre.
|
|
584
|
+
> **Note.** This source SDK tracks the `/v1` contract at `CONTRACT_VERSION` `0.1.0-pre.8`: a
|
|
585
585
|
> deliberate **prerelease**, pre-1.0, expect additive change. The offline `mock` transport models the
|
|
586
586
|
> live server closely enough to reproduce a 422 `intent_required` and a queued review, so build and
|
|
587
587
|
> test against it before you have a key. Install from the `next` tag until a stable release is cut.
|
package/dist/index.cjs
CHANGED
|
@@ -268,7 +268,7 @@ var CURRENT_API_VERSION = "2026-06-23";
|
|
|
268
268
|
var API_VERSION_HEADER = "Extrovert-Version";
|
|
269
269
|
|
|
270
270
|
// src/http.ts
|
|
271
|
-
var SDK_VERSION = "0.1.0-pre.
|
|
271
|
+
var SDK_VERSION = "0.1.0-pre.8";
|
|
272
272
|
function buildUrl(baseUrl, path, query) {
|
|
273
273
|
const base = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
274
274
|
const rel = path.startsWith("/") ? path : `/${path}`;
|
|
@@ -938,6 +938,8 @@ ${parent.text}`;
|
|
|
938
938
|
var MockBackend = class {
|
|
939
939
|
constructor() {
|
|
940
940
|
this.state = freshState();
|
|
941
|
+
/** Save / edit a rule (mock) - append-only by supersession (D11). */
|
|
942
|
+
this.learnedRules = /* @__PURE__ */ new Map();
|
|
941
943
|
}
|
|
942
944
|
reset() {
|
|
943
945
|
this.state = freshState();
|
|
@@ -2042,7 +2044,27 @@ var MockBackend = class {
|
|
|
2042
2044
|
composition_token_expires_at: params.scope ? void 0 : new Date(Date.now() + 6e5).toISOString()
|
|
2043
2045
|
};
|
|
2044
2046
|
}
|
|
2045
|
-
|
|
2047
|
+
learnReviewRule(reviewId, req) {
|
|
2048
|
+
const fingerprint = JSON.stringify({ reviewId, req });
|
|
2049
|
+
const prior = this.learnedRules.get(req.client_id);
|
|
2050
|
+
if (prior) {
|
|
2051
|
+
if (prior.fingerprint !== fingerprint) throw new ValidationError({ status: 409, code: "conflict", message: "learning retry identity changed" });
|
|
2052
|
+
return structuredClone(prior.result);
|
|
2053
|
+
}
|
|
2054
|
+
const turn = (this.state.reviewTurns.get(reviewId) ?? []).find((t) => t.id === req.source_turn_id);
|
|
2055
|
+
if (!turn || turn.actor_kind !== "human" || !turn.actor_id) throw new ValidationError({ status: 403, code: "forbidden_scope", message: "learning requires authenticated human feedback" });
|
|
2056
|
+
const rule = this.saveRule({ ...req, scope: req.target === "category" ? "category" : "general", source_review_id: reviewId, source_turn_id: turn.id });
|
|
2057
|
+
rule.source_turn_id = turn.id;
|
|
2058
|
+
rule.rule_layer = req.target === "org_house" ? "org" : "project";
|
|
2059
|
+
if (req.target === "org_house") delete rule.project_id;
|
|
2060
|
+
rule.source_review_id = reviewId;
|
|
2061
|
+
rule.source_turn_id = turn.id;
|
|
2062
|
+
const audit = [...this.state.ruleAudit.values()].find((entry) => entry.entity_id === rule.id);
|
|
2063
|
+
audit.after_json = ruleSnapshotJSON(rule);
|
|
2064
|
+
const result = { rule, source_review_id: reviewId, source_turn_id: turn.id, human_id: turn.actor_id, audit_id: audit.id, propagation: "queued" };
|
|
2065
|
+
this.learnedRules.set(req.client_id, { fingerprint, result: structuredClone(result) });
|
|
2066
|
+
return result;
|
|
2067
|
+
}
|
|
2046
2068
|
saveRule(req) {
|
|
2047
2069
|
const text = req.rule_text.trim();
|
|
2048
2070
|
if (!text) {
|
|
@@ -3683,6 +3705,7 @@ var HttpTransport = class {
|
|
|
3683
3705
|
state: Array.isArray(params.state) ? params.state.join(",") : params.state,
|
|
3684
3706
|
category_id: params.category_id,
|
|
3685
3707
|
inbox: params.inbox,
|
|
3708
|
+
composer: params.composer,
|
|
3686
3709
|
limit: params.limit,
|
|
3687
3710
|
page: params.page
|
|
3688
3711
|
};
|
|
@@ -3765,10 +3788,12 @@ var HttpTransport = class {
|
|
|
3765
3788
|
});
|
|
3766
3789
|
}
|
|
3767
3790
|
waitForReviewEvent(params, signal) {
|
|
3791
|
+
const waitSeconds = Math.min(55, Math.max(1, params.wait_seconds ?? 55));
|
|
3768
3792
|
return this.call({
|
|
3769
3793
|
method: "GET",
|
|
3770
3794
|
path: "/v1/reviews/events/wait",
|
|
3771
|
-
query: { review_id: params.review_id, limit: params.limit, wait_seconds:
|
|
3795
|
+
query: { review_id: params.review_id, limit: params.limit, wait_seconds: waitSeconds },
|
|
3796
|
+
timeoutMs: (waitSeconds + 10) * 1e3,
|
|
3772
3797
|
signal
|
|
3773
3798
|
});
|
|
3774
3799
|
}
|
|
@@ -3837,6 +3862,9 @@ var HttpTransport = class {
|
|
|
3837
3862
|
signal
|
|
3838
3863
|
});
|
|
3839
3864
|
}
|
|
3865
|
+
learnReviewRule(reviewId, req, signal) {
|
|
3866
|
+
return this.call({ method: "POST", path: `/v1/reviews/${encodeURIComponent(reviewId)}/learned-rules`, body: req, signal });
|
|
3867
|
+
}
|
|
3840
3868
|
saveRule(req, signal) {
|
|
3841
3869
|
return this.call({
|
|
3842
3870
|
method: "PUT",
|
|
@@ -4244,6 +4272,9 @@ var MockTransport = class {
|
|
|
4244
4272
|
async getRules(params) {
|
|
4245
4273
|
return this.backend.getRules(params);
|
|
4246
4274
|
}
|
|
4275
|
+
async learnReviewRule(reviewId, req) {
|
|
4276
|
+
return this.backend.learnReviewRule(reviewId, req);
|
|
4277
|
+
}
|
|
4247
4278
|
async saveRule(req) {
|
|
4248
4279
|
return this.backend.saveRule(req);
|
|
4249
4280
|
}
|
|
@@ -5273,6 +5304,10 @@ var Rules = class {
|
|
|
5273
5304
|
constructor(ctx) {
|
|
5274
5305
|
this.ctx = ctx;
|
|
5275
5306
|
}
|
|
5307
|
+
/** Learn category or organization house rules from verified human review feedback. */
|
|
5308
|
+
learnFromReview(reviewId, req, signal) {
|
|
5309
|
+
return this.ctx.transport.learnReviewRule(reviewId, req, signal);
|
|
5310
|
+
}
|
|
5276
5311
|
/** Get the ORDERED active rule set (precedence ladder applied; NO LLM). */
|
|
5277
5312
|
get(params = {}, signal) {
|
|
5278
5313
|
return this.ctx.transport.getRules(params, signal);
|
|
@@ -5280,7 +5315,7 @@ var Rules = class {
|
|
|
5280
5315
|
/**
|
|
5281
5316
|
* Save / edit a rule (append-only by supersession; D11). An agent-plane save is
|
|
5282
5317
|
* ALWAYS project-layer: the saved rule's `rule_layer` is `project`, bound to the
|
|
5283
|
-
* key's project.
|
|
5318
|
+
* key's project. For org-layer house rules use learnFromReview with an authenticated human source; this method cannot author (`rule_layer:"org"`)
|
|
5284
5319
|
* rules in v1: that is a console/admin action.
|
|
5285
5320
|
*/
|
|
5286
5321
|
save(req, signal) {
|
|
@@ -5558,7 +5593,7 @@ async function signWebhook(secret, body, timestampSeconds) {
|
|
|
5558
5593
|
}
|
|
5559
5594
|
|
|
5560
5595
|
// src/contract.ts
|
|
5561
|
-
var CONTRACT_VERSION = "0.1.0-pre.
|
|
5596
|
+
var CONTRACT_VERSION = "0.1.0-pre.8";
|
|
5562
5597
|
var CONTRACT_MANIFEST = {
|
|
5563
5598
|
name: "extrovert.review-loop",
|
|
5564
5599
|
version: CONTRACT_VERSION,
|
|
@@ -5589,6 +5624,8 @@ var CONTRACT_MANIFEST = {
|
|
|
5589
5624
|
// realtime (M3)
|
|
5590
5625
|
"ReviewEventReason",
|
|
5591
5626
|
"ReviewEventsResult",
|
|
5627
|
+
"LearnReviewRuleRequest",
|
|
5628
|
+
"LearnedReviewRule",
|
|
5592
5629
|
"ReviewEventCursor",
|
|
5593
5630
|
// chat / revision / restamp (M5/M7)
|
|
5594
5631
|
"PostReviewChatRequest",
|