@whittlelabs/sifter 0.5.0 → 0.6.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 CHANGED
@@ -1,16 +1,13 @@
1
1
  # @whittlelabs/sifter
2
2
 
3
- The Whittle Sifter is a paired AI reviewer for [Whittle Sift](https://sift.staging.whittlelabs.com). It runs on your machine, executes review prompts against your own AI credentials (Claude Code, Anthropic API key, etc.), and submits the results back to Sift. Token spend stays on your account.
3
+ The Whittle Sifter is a paired AI reviewer for [Whittle Sift](https://sift.stage.whittlelabs.com). It runs on your machine, executes review prompts against your own AI credentials (Claude Code, Anthropic API key, etc.), and submits the results back to Sift. Token spend stays on your account.
4
4
 
5
5
  ## Install
6
6
 
7
- `@whittlelabs/sifter` is published to the private Whittle Labs GitHub Packages registry. You'll need a GitHub personal access token with `read:packages` scope and access to the `whittlelabs` org.
7
+ `@whittlelabs/sifter` is published publicly to npmjs.com (released by
8
+ `sifter-release.yml` on a version bump):
8
9
 
9
10
  ```bash
10
- # One-time: tell npm where to find @whittlelabs packages
11
- echo "@whittlelabs:registry=https://npm.pkg.github.com" >> ~/.npmrc
12
- echo "//npm.pkg.github.com/:_authToken=YOUR_GITHUB_TOKEN" >> ~/.npmrc
13
-
14
11
  npm install -g @whittlelabs/sifter
15
12
  ```
16
13
 
@@ -24,11 +21,11 @@ Visit Sift's **Settings → Pair a Sifter**. Sift will display a pairing code an
24
21
  whittle-sifter init --pairing-code=ABCD-1234
25
22
  ```
26
23
 
27
- The Sifter defaults to the staging Keep instance (`https://keep.staging.whittlelabs.com`). To pair against a different environment, pass `--keep-url`:
24
+ The Sifter defaults to the stage Keep instance (`https://keep.stage.whittlelabs.com`). To pair against a different environment, pass `--keep-url`:
28
25
 
29
26
  ```bash
30
27
  whittle-sifter init \
31
- --keep-url=https://keep.testing.whittlelabs.com \
28
+ --keep-url=https://keep.test.whittlelabs.com \
32
29
  --pairing-code=ABCD-1234
33
30
  ```
34
31
 
package/bin.js CHANGED
@@ -15340,7 +15340,8 @@ var require_client = __commonJS({
15340
15340
  if (filters?.name)
15341
15341
  params.set("name", filters.name);
15342
15342
  const qs = params.toString();
15343
- return this.request("GET", `/api/job-pools${qs ? `?${qs}` : ""}`);
15343
+ const { pools } = await this.request("GET", `/api/job-pools${qs ? `?${qs}` : ""}`);
15344
+ return pools;
15344
15345
  }
15345
15346
  async getJobPool(poolId) {
15346
15347
  return this.request("GET", `/api/job-pools/${poolId}`);
@@ -15362,7 +15363,8 @@ var require_client = __commonJS({
15362
15363
  // A subscriber joins a pool by registering as a member of it. These
15363
15364
  // map to the server's `/api/job-pools/:poolId/members` routes.
15364
15365
  async listMembers(poolId) {
15365
- return this.request("GET", `/api/job-pools/${poolId}/members`);
15366
+ const { members } = await this.request("GET", `/api/job-pools/${poolId}/members`);
15367
+ return members;
15366
15368
  }
15367
15369
  async registerMember(poolId, options) {
15368
15370
  return this.request("POST", `/api/job-pools/${poolId}/members`, options);
@@ -15401,7 +15403,15 @@ var require_client = __commonJS({
15401
15403
  }
15402
15404
  // ── Outputs ──────────────────────────────────────────────────────
15403
15405
  async listOutputs(jobId) {
15404
- return this.request("GET", `/api/jobs/${jobId}/output`);
15406
+ const all = [];
15407
+ const pageSize = 100;
15408
+ for (let offset = 0; ; offset += pageSize) {
15409
+ const { outputs, total } = await this.request("GET", `/api/jobs/${jobId}/output?limit=${pageSize}&offset=${offset}`);
15410
+ all.push(...outputs);
15411
+ if (outputs.length === 0 || all.length >= total)
15412
+ break;
15413
+ }
15414
+ return all;
15405
15415
  }
15406
15416
  async createOutput(jobId, options) {
15407
15417
  return this.request("POST", `/api/jobs/${jobId}/output`, options);
@@ -15436,7 +15446,11 @@ var require_client = __commonJS({
15436
15446
  if (options?.sort)
15437
15447
  params.set("sort", options.sort);
15438
15448
  const qs = params.toString();
15439
- return this.requestPaginated("GET", `/api/my/jobs${qs ? `?${qs}` : ""}`);
15449
+ const { jobs, total } = await this.request("GET", `/api/my/jobs${qs ? `?${qs}` : ""}`);
15450
+ return {
15451
+ data: jobs,
15452
+ pagination: { total, limit: options?.limit ?? 25, offset: options?.offset ?? 0 }
15453
+ };
15440
15454
  }
15441
15455
  // ── HTTP plumbing ────────────────────────────────────────────────
15442
15456
  async request(method, path, body) {
@@ -15452,19 +15466,6 @@ var require_client = __commonJS({
15452
15466
  }
15453
15467
  return json.data;
15454
15468
  }
15455
- async requestPaginated(method, path) {
15456
- const url = `${this.baseUrl}${path}`;
15457
- const response = await this.fetchWithAuthRetry(method, url);
15458
- const json = await response.json();
15459
- if (!response.ok || !json.success) {
15460
- const errorMessage = json.error?.message ?? `Request failed with status ${response.status}`;
15461
- const error = new Error(errorMessage);
15462
- error.code = json.error?.code;
15463
- error.statusCode = response.status;
15464
- throw error;
15465
- }
15466
- return { data: json.data, pagination: json.pagination };
15467
- }
15468
15469
  };
15469
15470
  exports2.JobsClient = JobsClient;
15470
15471
  }
@@ -17985,7 +17986,10 @@ var require_canonicalise = __commonJS({
17985
17986
  transitionResolver: options.transition.resolver,
17986
17987
  transitionContext: extractTransitionContext(options.transition)
17987
17988
  } : {},
17988
- ...options.qualityGates !== void 0 ? { qualityGates: serialiseQualityGates(options.qualityGates) } : {}
17989
+ ...options.qualityGates !== void 0 ? { qualityGates: serialiseQualityGates(options.qualityGates) } : {},
17990
+ // Normalise the emit spec: `true` → emit-all (`{}`); object → as-is;
17991
+ // `false`/omitted → not emitted (field absent).
17992
+ ...options.emitOutput === true ? { emitOutput: {} } : options.emitOutput && typeof options.emitOutput === "object" ? { emitOutput: options.emitOutput } : {}
17989
17993
  };
17990
17994
  }
17991
17995
  function interpolate(value, env) {
@@ -18310,7 +18314,8 @@ var require_client2 = __commonJS({
18310
18314
  }
18311
18315
  // ── Organizations ───────────────────────────────────────────────
18312
18316
  async listOrganizations() {
18313
- return this.request("GET", "/api/organizations");
18317
+ const { organizations } = await this.request("GET", "/api/organizations");
18318
+ return organizations;
18314
18319
  }
18315
18320
  async getOrganization(orgId) {
18316
18321
  return this.request("GET", `/api/organizations/${orgId}`);
@@ -18732,6 +18737,7 @@ var require_claude_code = __commonJS({
18732
18737
  var child_process_1 = require("child_process");
18733
18738
  var loom_1 = require_dist3();
18734
18739
  var validate_output_1 = require_validate_output();
18740
+ var apply_1 = require_apply();
18735
18741
  var DEFAULT_TIMEOUT = 6e5;
18736
18742
  var ClaudeCodeExecutor = class {
18737
18743
  capability;
@@ -18823,10 +18829,11 @@ var require_claude_code = __commonJS({
18823
18829
  }
18824
18830
  };
18825
18831
  function createClaudeCodeExecutor(config, capabilityId = "claude-code") {
18826
- const cwd = config.cwd;
18827
- if (typeof cwd !== "string" || cwd.length === 0) {
18832
+ const cwdRaw = config.cwd;
18833
+ if (typeof cwdRaw !== "string" || cwdRaw.length === 0) {
18828
18834
  throw new Error('ClaudeCodeExecutor requires a non-empty "cwd" string in config');
18829
18835
  }
18836
+ const cwd = (0, apply_1.expandHome)(cwdRaw);
18830
18837
  const validated = { cwd, capabilityId };
18831
18838
  if (config.model !== void 0) {
18832
18839
  if (typeof config.model !== "string")
@@ -20710,7 +20717,7 @@ var import_shuttle = __toESM(require_dist5());
20710
20717
  // package.json
20711
20718
  var package_default = {
20712
20719
  name: "@whittlelabs/sifter",
20713
- version: "0.5.0",
20720
+ version: "0.6.0",
20714
20721
  description: "Whittle Sifter: paired AI reviewer for Whittle Sift job pools.",
20715
20722
  bin: {
20716
20723
  "whittle-sifter": "./dist/bin.js"