@whittlelabs/sifter 0.10.0 → 0.11.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.
Files changed (3) hide show
  1. package/bin.js +79 -9
  2. package/bin.js.map +2 -2
  3. package/package.json +1 -1
package/bin.js CHANGED
@@ -19256,6 +19256,8 @@ var require_claude_code = __commonJS({
19256
19256
  };
19257
19257
  Object.defineProperty(exports2, "__esModule", { value: true });
19258
19258
  exports2.createClaudeCodeExecutor = createClaudeCodeExecutor;
19259
+ exports2.parseStreamJson = parseStreamJson;
19260
+ exports2.relativeWorkspaceReads = relativeWorkspaceReads;
19259
19261
  exports2.extractJsonObject = extractJsonObject;
19260
19262
  var child_process_1 = require("child_process");
19261
19263
  var fs_1 = require("fs");
@@ -19323,8 +19325,13 @@ var require_claude_code = __commonJS({
19323
19325
  const childEnv = buildChildEnv(credentials, configDir);
19324
19326
  const claudeHints = (0, loom_1.pickProviderHints)(spec, "claude-code");
19325
19327
  const hintedModel = typeof claudeHints.model === "string" && claudeHints.model.length > 0 ? claudeHints.model : void 0;
19326
- const response = await this.runClaude(prompt, spec, workspace?.cwd ?? this.config.cwd, childEnv, signal, hintedModel);
19328
+ const runCwd = workspace?.cwd ?? this.config.cwd;
19329
+ const { response, readPaths } = await this.runClaude(prompt, spec, runCwd, childEnv, signal, hintedModel);
19327
19330
  if (workspace) {
19331
+ response.outputs.push({
19332
+ label: "workspace_reads",
19333
+ content: { paths: relativeWorkspaceReads(readPaths, runCwd) }
19334
+ });
19328
19335
  response.outputs.push({
19329
19336
  label: "workspace",
19330
19337
  content: {
@@ -19350,9 +19357,9 @@ var require_claude_code = __commonJS({
19350
19357
  }
19351
19358
  runClaude(prompt, spec, cwd, childEnv, signal, modelOverride) {
19352
19359
  const outputLabel = spec.outputLabel;
19360
+ const model = modelOverride ?? this.config.model;
19353
19361
  return new Promise((resolve, reject) => {
19354
- const args = ["--print"];
19355
- const model = modelOverride ?? this.config.model;
19362
+ const args = ["--print", "--output-format", "stream-json", "--verbose"];
19356
19363
  if (model)
19357
19364
  args.push("--model", model);
19358
19365
  if (this.config.maxTurns !== void 0)
@@ -19411,13 +19418,22 @@ var require_claude_code = __commonJS({
19411
19418
  const stdout = Buffer.concat(stdoutChunks).toString("utf-8");
19412
19419
  if (code === 0) {
19413
19420
  try {
19414
- const parsed = extractJsonObject(stdout);
19421
+ const stream = parseStreamJson(stdout);
19422
+ const answerText = stream.finalText ?? stdout;
19423
+ const parsed = extractJsonObject(answerText);
19415
19424
  (0, validate_output_1.assertOutputValid)(spec, parsed);
19416
19425
  settle(() => resolve({
19417
- outputs: [{ label: outputLabel, content: parsed ?? { raw: stdout } }],
19418
- rawText: stdout,
19419
- parsed,
19420
- usage: this.config.model ? { aiProvider: "claude-code", aiModel: this.config.model } : void 0
19426
+ response: {
19427
+ outputs: [{ label: outputLabel, content: parsed ?? { raw: answerText } }],
19428
+ rawText: answerText,
19429
+ parsed,
19430
+ usage: {
19431
+ aiProvider: "claude-code",
19432
+ ...model ? { aiModel: model } : {},
19433
+ ...stream.usage ?? {}
19434
+ }
19435
+ },
19436
+ readPaths: stream.readPaths
19421
19437
  }));
19422
19438
  } catch (err) {
19423
19439
  settle(() => reject(err instanceof Error ? err : new Error(String(err))));
@@ -19507,6 +19523,60 @@ var require_claude_code = __commonJS({
19507
19523
  return credentials;
19508
19524
  };
19509
19525
  }
19526
+ function parseStreamJson(stdout) {
19527
+ let finalText = null;
19528
+ const readPaths = [];
19529
+ let usage = null;
19530
+ for (const line of stdout.split("\n")) {
19531
+ const trimmed = line.trim();
19532
+ if (!trimmed.startsWith("{"))
19533
+ continue;
19534
+ let event;
19535
+ try {
19536
+ event = JSON.parse(trimmed);
19537
+ } catch {
19538
+ continue;
19539
+ }
19540
+ if (event.type === "assistant") {
19541
+ const content = event.message?.content;
19542
+ if (!Array.isArray(content))
19543
+ continue;
19544
+ for (const block of content) {
19545
+ const b = block;
19546
+ if (b?.type === "tool_use" && b.name === "Read" && typeof b.input?.file_path === "string") {
19547
+ readPaths.push(b.input.file_path);
19548
+ }
19549
+ }
19550
+ } else if (event.type === "result") {
19551
+ if (typeof event.result === "string")
19552
+ finalText = event.result;
19553
+ const u = event.usage;
19554
+ const cost = event.total_cost_usd;
19555
+ usage = {
19556
+ ...typeof u?.input_tokens === "number" ? { inputTokens: u.input_tokens } : {},
19557
+ ...typeof u?.output_tokens === "number" ? { outputTokens: u.output_tokens } : {},
19558
+ ...typeof cost === "number" ? { costUsd: cost } : {}
19559
+ };
19560
+ }
19561
+ }
19562
+ return { finalText, readPaths, usage };
19563
+ }
19564
+ var MAX_REPORTED_READS = 2e3;
19565
+ function relativeWorkspaceReads(readPaths, cwd) {
19566
+ const root = path_1.default.resolve(cwd);
19567
+ const out = /* @__PURE__ */ new Set();
19568
+ for (const p of readPaths) {
19569
+ const resolved = path_1.default.resolve(root, p);
19570
+ if (resolved === root)
19571
+ continue;
19572
+ if (!resolved.startsWith(root + path_1.default.sep))
19573
+ continue;
19574
+ out.add(resolved.slice(root.length + 1));
19575
+ if (out.size >= MAX_REPORTED_READS)
19576
+ break;
19577
+ }
19578
+ return [...out].sort();
19579
+ }
19510
19580
  function extractJsonObject(s) {
19511
19581
  const exact = tryParseObject(s);
19512
19582
  if (exact)
@@ -21414,7 +21484,7 @@ var import_shuttle = __toESM(require_dist5());
21414
21484
  // package.json
21415
21485
  var package_default = {
21416
21486
  name: "@whittlelabs/sifter",
21417
- version: "0.10.0",
21487
+ version: "0.11.0",
21418
21488
  description: "Whittle Sifter: paired AI reviewer for Whittle Sift job pools.",
21419
21489
  bin: {
21420
21490
  "whittle-sifter": "./dist/bin.js"