@whittlelabs/sifter 0.22.3 → 0.24.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/README.md +2 -2
- package/bin.js +72 -6
- package/bin.js.map +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,8 +4,8 @@ The Whittle Sifter is a paired AI reviewer for [Whittle Sift](https://sift.whitt
|
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
|
-
`@whittlelabs/sifter` is published publicly to npmjs.com (released by
|
|
8
|
-
|
|
7
|
+
`@whittlelabs/sifter` is published publicly to npmjs.com (released by the
|
|
8
|
+
delivery pipeline on a version bump):
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
11
|
npm install -g @whittlelabs/sifter
|
package/bin.js
CHANGED
|
@@ -18983,11 +18983,36 @@ var require_client2 = __commonJS({
|
|
|
18983
18983
|
return this.request("POST", "/api/actor-tokens", { actor });
|
|
18984
18984
|
}
|
|
18985
18985
|
// ── Identity ────────────────────────────────────────────────────
|
|
18986
|
+
/**
|
|
18987
|
+
* Sign up. This NEVER returns an account or a session: Keep answers 201 with
|
|
18988
|
+
* an email-verification challenge, which is answered at
|
|
18989
|
+
* POST /api/challenges/:token/response to mint a session.
|
|
18990
|
+
*/
|
|
18986
18991
|
async createAccount(email, password, name) {
|
|
18987
|
-
|
|
18992
|
+
const body = await this.envelope("POST", "/api/accounts", { email, password, name });
|
|
18993
|
+
if (!body.challenge) {
|
|
18994
|
+
throw new Error("sign-up returned no challenge; the contract expects one");
|
|
18995
|
+
}
|
|
18996
|
+
return body.challenge;
|
|
18988
18997
|
}
|
|
18998
|
+
/**
|
|
18999
|
+
* Sign in. Two legitimate outcomes, neither an error: a session, or a
|
|
19000
|
+
* challenge (MFA, unverified email). Both arrive on HTTP 200.
|
|
19001
|
+
*/
|
|
18989
19002
|
async createSession(email, password) {
|
|
18990
|
-
|
|
19003
|
+
const body = await this.envelope("POST", "/api/sessions", { email, password });
|
|
19004
|
+
if (body.challenge) {
|
|
19005
|
+
return { kind: "challenge", challenge: body.challenge };
|
|
19006
|
+
}
|
|
19007
|
+
const data = body.data;
|
|
19008
|
+
if (!data?.session) {
|
|
19009
|
+
throw new Error("sign-in returned neither a session nor a challenge");
|
|
19010
|
+
}
|
|
19011
|
+
return { kind: "session", user: data.user, session: data.session };
|
|
19012
|
+
}
|
|
19013
|
+
/** Answer a challenge and obtain the session it was standing in for. */
|
|
19014
|
+
async respondToChallenge(challengeToken, type, response) {
|
|
19015
|
+
return this.request("POST", `/api/challenges/${encodeURIComponent(challengeToken)}/response`, { type, response });
|
|
18991
19016
|
}
|
|
18992
19017
|
async destroySession(refreshToken) {
|
|
18993
19018
|
await this.request("DELETE", "/api/sessions", refreshToken ? { refreshToken } : void 0);
|
|
@@ -19133,6 +19158,28 @@ var require_client2 = __commonJS({
|
|
|
19133
19158
|
return this.request("GET", `/api/users/${encodeURIComponent(userId)}/github-token`);
|
|
19134
19159
|
}
|
|
19135
19160
|
// ── HTTP ────────────────────────────────────────────────────────
|
|
19161
|
+
/**
|
|
19162
|
+
* Reads the response envelope WITHOUT treating `success: false` as a
|
|
19163
|
+
* failure. Sign-in and sign-up use it because a challenge arrives on a 2xx
|
|
19164
|
+
* with success:false and no error object — `request` would raise a
|
|
19165
|
+
* misleading "Request failed with status 200" and give the caller no way to
|
|
19166
|
+
* tell MFA from a bad password (whittlelabs#530). A real error still throws.
|
|
19167
|
+
*/
|
|
19168
|
+
async envelope(method, path, body) {
|
|
19169
|
+
const response = await fetch(`${this.baseUrl}${path}`, {
|
|
19170
|
+
method,
|
|
19171
|
+
headers: this.headers,
|
|
19172
|
+
body: body ? JSON.stringify(body) : void 0
|
|
19173
|
+
});
|
|
19174
|
+
const json = await response.json();
|
|
19175
|
+
if (!response.ok || !json.success && !json.challenge) {
|
|
19176
|
+
const error = new Error(json.error?.message ?? `Request failed with status ${response.status}`);
|
|
19177
|
+
error.code = json.error?.code;
|
|
19178
|
+
error.statusCode = response.status;
|
|
19179
|
+
throw error;
|
|
19180
|
+
}
|
|
19181
|
+
return json;
|
|
19182
|
+
}
|
|
19136
19183
|
async request(method, path, body) {
|
|
19137
19184
|
const url = `${this.baseUrl}${path}`;
|
|
19138
19185
|
const response = await fetch(url, {
|
|
@@ -19873,6 +19920,15 @@ var require_claude_code = __commonJS({
|
|
|
19873
19920
|
var progress_1 = require_progress();
|
|
19874
19921
|
var apply_1 = require_apply();
|
|
19875
19922
|
var DEFAULT_TIMEOUT = 6e5;
|
|
19923
|
+
function describeClaudeFailure(meta, fallback) {
|
|
19924
|
+
if (!meta)
|
|
19925
|
+
return fallback;
|
|
19926
|
+
const status = meta.apiErrorStatus !== null ? ` (provider HTTP ${meta.apiErrorStatus})` : "";
|
|
19927
|
+
if (meta.detail)
|
|
19928
|
+
return `${meta.detail}${status}`;
|
|
19929
|
+
const subtype = meta.subtype && meta.subtype !== "success" ? `: ${meta.subtype}` : "";
|
|
19930
|
+
return `${fallback}${subtype}${status}`;
|
|
19931
|
+
}
|
|
19876
19932
|
var ClaudeCodeExecutor = class {
|
|
19877
19933
|
capability;
|
|
19878
19934
|
strategies = [loom_1.PROMPT_EXECUTION_STRATEGY];
|
|
@@ -20100,7 +20156,7 @@ var require_claude_code = __commonJS({
|
|
|
20100
20156
|
try {
|
|
20101
20157
|
const stream = parseStreamJson(stdout);
|
|
20102
20158
|
if (stream.resultMeta?.isError) {
|
|
20103
|
-
throw new Error(
|
|
20159
|
+
throw new Error(describeClaudeFailure(stream.resultMeta, "Claude Code reported a failure"));
|
|
20104
20160
|
}
|
|
20105
20161
|
const answerText = stream.finalText ?? stdout;
|
|
20106
20162
|
const parsed = stream.structuredOutput ?? extractJsonObject(answerText);
|
|
@@ -20137,7 +20193,12 @@ var require_claude_code = __commonJS({
|
|
|
20137
20193
|
settle(() => reject(err instanceof Error ? err : new Error(String(err))));
|
|
20138
20194
|
}
|
|
20139
20195
|
} else {
|
|
20140
|
-
|
|
20196
|
+
let meta = null;
|
|
20197
|
+
try {
|
|
20198
|
+
meta = parseStreamJson(stdout).resultMeta;
|
|
20199
|
+
} catch {
|
|
20200
|
+
}
|
|
20201
|
+
settle(() => reject(new Error(describeClaudeFailure(meta, `Claude Code exited with code ${code}`))));
|
|
20141
20202
|
}
|
|
20142
20203
|
});
|
|
20143
20204
|
});
|
|
@@ -20232,7 +20293,12 @@ var require_claude_code = __commonJS({
|
|
|
20232
20293
|
}
|
|
20233
20294
|
resultMeta = {
|
|
20234
20295
|
subtype: typeof event.subtype === "string" ? event.subtype : null,
|
|
20235
|
-
isError: event.is_error === true
|
|
20296
|
+
isError: event.is_error === true,
|
|
20297
|
+
// On a failure the CLI puts a human-readable reason in `result` — the
|
|
20298
|
+
// model was unavailable, spend limit hit, and so on. It is the only
|
|
20299
|
+
// place that reason exists, so keep it for the failure message.
|
|
20300
|
+
detail: typeof event.result === "string" && event.result.trim().length > 0 ? event.result.trim() : null,
|
|
20301
|
+
apiErrorStatus: typeof event.api_error_status === "number" ? event.api_error_status : null
|
|
20236
20302
|
};
|
|
20237
20303
|
const so = event.structured_output;
|
|
20238
20304
|
if (so && typeof so === "object" && !Array.isArray(so)) {
|
|
@@ -22302,7 +22368,7 @@ var import_path = require("path");
|
|
|
22302
22368
|
var import_promises = require("fs/promises");
|
|
22303
22369
|
var import_yaml = __toESM(require_dist());
|
|
22304
22370
|
var import_shuttle = __toESM(require_dist5());
|
|
22305
|
-
var buildVersion = true ? "0.
|
|
22371
|
+
var buildVersion = true ? "0.24.0" : pkg.version;
|
|
22306
22372
|
var sifterBrand = {
|
|
22307
22373
|
product: {
|
|
22308
22374
|
id: "sifter",
|