@whittlelabs/sifter 0.9.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.
- package/bin.js +198 -18
- package/bin.js.map +4 -4
- package/package.json +1 -1
package/bin.js
CHANGED
|
@@ -15450,10 +15450,11 @@ var require_client = __commonJS({
|
|
|
15450
15450
|
if (options?.sort)
|
|
15451
15451
|
params.set("sort", options.sort);
|
|
15452
15452
|
const qs = params.toString();
|
|
15453
|
-
const { jobs, total } = await this.request("GET", `/api/my/jobs${qs ? `?${qs}` : ""}`);
|
|
15453
|
+
const { jobs, total, directives } = await this.request("GET", `/api/my/jobs${qs ? `?${qs}` : ""}`);
|
|
15454
15454
|
return {
|
|
15455
15455
|
data: jobs,
|
|
15456
|
-
pagination: { total, limit: options?.limit ?? 25, offset: options?.offset ?? 0 }
|
|
15456
|
+
pagination: { total, limit: options?.limit ?? 25, offset: options?.offset ?? 0 },
|
|
15457
|
+
directives: directives ?? null
|
|
15457
15458
|
};
|
|
15458
15459
|
}
|
|
15459
15460
|
// ── HTTP plumbing ────────────────────────────────────────────────
|
|
@@ -15547,11 +15548,22 @@ var require_subscribe = __commonJS({
|
|
|
15547
15548
|
return;
|
|
15548
15549
|
}
|
|
15549
15550
|
try {
|
|
15550
|
-
const { data } = await opts.jobsClient.listDispatchableJobs({
|
|
15551
|
+
const { data, directives } = await opts.jobsClient.listDispatchableJobs({
|
|
15551
15552
|
pools: resolvedPoolIds,
|
|
15552
15553
|
limit: maxConcurrency - inflight,
|
|
15553
15554
|
sort: "priority:desc,queued_at:asc"
|
|
15554
15555
|
});
|
|
15556
|
+
if (directives && Object.keys(directives).length > 0 && opts.onDirectives) {
|
|
15557
|
+
try {
|
|
15558
|
+
await opts.onDirectives(directives);
|
|
15559
|
+
} catch (err) {
|
|
15560
|
+
logger.error("onDirectives handler failed", {
|
|
15561
|
+
error: err instanceof Error ? err.message : String(err)
|
|
15562
|
+
});
|
|
15563
|
+
}
|
|
15564
|
+
}
|
|
15565
|
+
if (stopped)
|
|
15566
|
+
return;
|
|
15555
15567
|
for (const job of data) {
|
|
15556
15568
|
if (inflight >= maxConcurrency)
|
|
15557
15569
|
break;
|
|
@@ -15644,6 +15656,78 @@ var require_dist2 = __commonJS({
|
|
|
15644
15656
|
}
|
|
15645
15657
|
});
|
|
15646
15658
|
|
|
15659
|
+
// ../../packages/shuttle/dist/lifecycle/self-update.js
|
|
15660
|
+
var require_self_update = __commonJS({
|
|
15661
|
+
"../../packages/shuttle/dist/lifecycle/self-update.js"(exports2) {
|
|
15662
|
+
"use strict";
|
|
15663
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
15664
|
+
exports2.readUpgradeDirective = readUpgradeDirective;
|
|
15665
|
+
exports2.performSelfUpdate = performSelfUpdate;
|
|
15666
|
+
var child_process_1 = require("child_process");
|
|
15667
|
+
var version_check_1 = require_version_check();
|
|
15668
|
+
function readUpgradeDirective(directives, currentVersion, attemptedVersions) {
|
|
15669
|
+
const raw = directives.upgrade;
|
|
15670
|
+
if (!raw || typeof raw !== "object")
|
|
15671
|
+
return null;
|
|
15672
|
+
const requested = raw.requested_version;
|
|
15673
|
+
if (typeof requested !== "string" || requested.length === 0)
|
|
15674
|
+
return null;
|
|
15675
|
+
if (attemptedVersions.has(requested))
|
|
15676
|
+
return null;
|
|
15677
|
+
if ((0, version_check_1.compareSemver)(currentVersion, requested) >= 0)
|
|
15678
|
+
return null;
|
|
15679
|
+
return {
|
|
15680
|
+
requested_version: requested,
|
|
15681
|
+
requested_at: raw.requested_at
|
|
15682
|
+
};
|
|
15683
|
+
}
|
|
15684
|
+
async function performSelfUpdate(opts) {
|
|
15685
|
+
const { packageName, directive, logger, hooks } = opts;
|
|
15686
|
+
const spec = `${packageName}@${directive.requested_version}`;
|
|
15687
|
+
const install = hooks.install ?? defaultInstall;
|
|
15688
|
+
const respawn = hooks.respawn ?? defaultRespawn;
|
|
15689
|
+
logger.info("upgrade directive received; draining claim loop", {
|
|
15690
|
+
requestedVersion: directive.requested_version
|
|
15691
|
+
});
|
|
15692
|
+
await hooks.stopLoop();
|
|
15693
|
+
try {
|
|
15694
|
+
await install(spec);
|
|
15695
|
+
} catch (err) {
|
|
15696
|
+
logger.error("self-update install failed; resuming on the current version", {
|
|
15697
|
+
packageSpec: spec,
|
|
15698
|
+
error: err instanceof Error ? err.message : String(err)
|
|
15699
|
+
});
|
|
15700
|
+
await hooks.restartLoop();
|
|
15701
|
+
return false;
|
|
15702
|
+
}
|
|
15703
|
+
logger.info("self-update installed; restarting", { packageSpec: spec });
|
|
15704
|
+
respawn();
|
|
15705
|
+
return true;
|
|
15706
|
+
}
|
|
15707
|
+
function defaultInstall(packageSpec) {
|
|
15708
|
+
return new Promise((resolve, reject) => {
|
|
15709
|
+
const child = (0, child_process_1.spawn)("npm", ["install", "-g", packageSpec], {
|
|
15710
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
15711
|
+
});
|
|
15712
|
+
let output = "";
|
|
15713
|
+
child.stdout.on("data", (chunk) => output += chunk.toString());
|
|
15714
|
+
child.stderr.on("data", (chunk) => output += chunk.toString());
|
|
15715
|
+
child.on("error", reject);
|
|
15716
|
+
child.on("exit", (code) => {
|
|
15717
|
+
if (code === 0)
|
|
15718
|
+
resolve();
|
|
15719
|
+
else
|
|
15720
|
+
reject(new Error(`npm install -g exited ${code}: ${output.trim().slice(-500)}`));
|
|
15721
|
+
});
|
|
15722
|
+
});
|
|
15723
|
+
}
|
|
15724
|
+
function defaultRespawn() {
|
|
15725
|
+
const child = (0, child_process_1.spawn)(process.execPath, process.argv.slice(1), { stdio: "inherit" });
|
|
15726
|
+
child.on("exit", (code) => process.exit(code ?? 0));
|
|
15727
|
+
}
|
|
15728
|
+
}
|
|
15729
|
+
});
|
|
15730
|
+
|
|
15647
15731
|
// ../../packages/loom/dist/runtime/prompt-execution.js
|
|
15648
15732
|
var require_prompt_execution = __commonJS({
|
|
15649
15733
|
"../../packages/loom/dist/runtime/prompt-execution.js"(exports2) {
|
|
@@ -19172,6 +19256,8 @@ var require_claude_code = __commonJS({
|
|
|
19172
19256
|
};
|
|
19173
19257
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
19174
19258
|
exports2.createClaudeCodeExecutor = createClaudeCodeExecutor;
|
|
19259
|
+
exports2.parseStreamJson = parseStreamJson;
|
|
19260
|
+
exports2.relativeWorkspaceReads = relativeWorkspaceReads;
|
|
19175
19261
|
exports2.extractJsonObject = extractJsonObject;
|
|
19176
19262
|
var child_process_1 = require("child_process");
|
|
19177
19263
|
var fs_1 = require("fs");
|
|
@@ -19239,8 +19325,13 @@ var require_claude_code = __commonJS({
|
|
|
19239
19325
|
const childEnv = buildChildEnv(credentials, configDir);
|
|
19240
19326
|
const claudeHints = (0, loom_1.pickProviderHints)(spec, "claude-code");
|
|
19241
19327
|
const hintedModel = typeof claudeHints.model === "string" && claudeHints.model.length > 0 ? claudeHints.model : void 0;
|
|
19242
|
-
const
|
|
19328
|
+
const runCwd = workspace?.cwd ?? this.config.cwd;
|
|
19329
|
+
const { response, readPaths } = await this.runClaude(prompt, spec, runCwd, childEnv, signal, hintedModel);
|
|
19243
19330
|
if (workspace) {
|
|
19331
|
+
response.outputs.push({
|
|
19332
|
+
label: "workspace_reads",
|
|
19333
|
+
content: { paths: relativeWorkspaceReads(readPaths, runCwd) }
|
|
19334
|
+
});
|
|
19244
19335
|
response.outputs.push({
|
|
19245
19336
|
label: "workspace",
|
|
19246
19337
|
content: {
|
|
@@ -19266,9 +19357,9 @@ var require_claude_code = __commonJS({
|
|
|
19266
19357
|
}
|
|
19267
19358
|
runClaude(prompt, spec, cwd, childEnv, signal, modelOverride) {
|
|
19268
19359
|
const outputLabel = spec.outputLabel;
|
|
19360
|
+
const model = modelOverride ?? this.config.model;
|
|
19269
19361
|
return new Promise((resolve, reject) => {
|
|
19270
|
-
const args = ["--print"];
|
|
19271
|
-
const model = modelOverride ?? this.config.model;
|
|
19362
|
+
const args = ["--print", "--output-format", "stream-json", "--verbose"];
|
|
19272
19363
|
if (model)
|
|
19273
19364
|
args.push("--model", model);
|
|
19274
19365
|
if (this.config.maxTurns !== void 0)
|
|
@@ -19327,13 +19418,22 @@ var require_claude_code = __commonJS({
|
|
|
19327
19418
|
const stdout = Buffer.concat(stdoutChunks).toString("utf-8");
|
|
19328
19419
|
if (code === 0) {
|
|
19329
19420
|
try {
|
|
19330
|
-
const
|
|
19421
|
+
const stream = parseStreamJson(stdout);
|
|
19422
|
+
const answerText = stream.finalText ?? stdout;
|
|
19423
|
+
const parsed = extractJsonObject(answerText);
|
|
19331
19424
|
(0, validate_output_1.assertOutputValid)(spec, parsed);
|
|
19332
19425
|
settle(() => resolve({
|
|
19333
|
-
|
|
19334
|
-
|
|
19335
|
-
|
|
19336
|
-
|
|
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
|
|
19337
19437
|
}));
|
|
19338
19438
|
} catch (err) {
|
|
19339
19439
|
settle(() => reject(err instanceof Error ? err : new Error(String(err))));
|
|
@@ -19423,6 +19523,60 @@ var require_claude_code = __commonJS({
|
|
|
19423
19523
|
return credentials;
|
|
19424
19524
|
};
|
|
19425
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
|
+
}
|
|
19426
19580
|
function extractJsonObject(s) {
|
|
19427
19581
|
const exact = tryParseObject(s);
|
|
19428
19582
|
if (exact)
|
|
@@ -20551,7 +20705,9 @@ var require_shuttle = __commonJS({
|
|
|
20551
20705
|
"use strict";
|
|
20552
20706
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
20553
20707
|
exports2.Shuttle = void 0;
|
|
20708
|
+
var os_1 = require("os");
|
|
20554
20709
|
var jobs_1 = require_dist2();
|
|
20710
|
+
var self_update_1 = require_self_update();
|
|
20555
20711
|
var loom_1 = require_dist3();
|
|
20556
20712
|
var chain_1 = require_chain();
|
|
20557
20713
|
var keep_1 = require_dist4();
|
|
@@ -20691,6 +20847,13 @@ var require_shuttle = __commonJS({
|
|
|
20691
20847
|
return { status: "completed", outputs };
|
|
20692
20848
|
};
|
|
20693
20849
|
const pools = this.config.pools.map((p) => p.id ? { id: p.id } : { name: p.name });
|
|
20850
|
+
const subscribeLogger = {
|
|
20851
|
+
debug: (msg, meta) => logger.debug(msg, meta),
|
|
20852
|
+
info: (msg, meta) => logger.info(msg, meta),
|
|
20853
|
+
warn: (msg, meta) => logger.warn(msg, meta),
|
|
20854
|
+
error: (msg, meta) => logger.error(msg, meta)
|
|
20855
|
+
};
|
|
20856
|
+
const attemptedUpgrades = /* @__PURE__ */ new Set();
|
|
20694
20857
|
this.subscription = (0, jobs_1.subscribe)({
|
|
20695
20858
|
jobsClient,
|
|
20696
20859
|
pools,
|
|
@@ -20699,15 +20862,32 @@ var require_shuttle = __commonJS({
|
|
|
20699
20862
|
identityId: this.config.agent.identityId,
|
|
20700
20863
|
intelligence: "digital",
|
|
20701
20864
|
displayName: this.config.agent.displayName,
|
|
20702
|
-
|
|
20865
|
+
// Self-reported build facts, refreshed on every registration.
|
|
20866
|
+
// Products read these off the pool-member row (Sift's settings
|
|
20867
|
+
// page shows the version and offers the upgrade action).
|
|
20868
|
+
metadata: {
|
|
20869
|
+
...this.config.agent.metadata,
|
|
20870
|
+
client_version: this.brand.product.version,
|
|
20871
|
+
hostname: (0, os_1.hostname)()
|
|
20872
|
+
}
|
|
20703
20873
|
},
|
|
20704
20874
|
onJob,
|
|
20705
|
-
|
|
20706
|
-
|
|
20707
|
-
|
|
20708
|
-
|
|
20709
|
-
|
|
20875
|
+
onDirectives: async (directives) => {
|
|
20876
|
+
const directive = (0, self_update_1.readUpgradeDirective)(directives, this.brand.product.version, attemptedUpgrades);
|
|
20877
|
+
if (!directive)
|
|
20878
|
+
return;
|
|
20879
|
+
attemptedUpgrades.add(directive.requested_version);
|
|
20880
|
+
await (0, self_update_1.performSelfUpdate)({
|
|
20881
|
+
packageName: this.brand.product.packageName,
|
|
20882
|
+
directive,
|
|
20883
|
+
logger: subscribeLogger,
|
|
20884
|
+
hooks: {
|
|
20885
|
+
stopLoop: () => this.subscription?.stop() ?? Promise.resolve(),
|
|
20886
|
+
restartLoop: () => this.subscription?.start() ?? Promise.resolve()
|
|
20887
|
+
}
|
|
20888
|
+
});
|
|
20710
20889
|
},
|
|
20890
|
+
logger: subscribeLogger,
|
|
20711
20891
|
pollIntervalMs: this.config.polling.intervalMs,
|
|
20712
20892
|
maxConcurrency: this.config.concurrency.maxJobs
|
|
20713
20893
|
});
|
|
@@ -21304,7 +21484,7 @@ var import_shuttle = __toESM(require_dist5());
|
|
|
21304
21484
|
// package.json
|
|
21305
21485
|
var package_default = {
|
|
21306
21486
|
name: "@whittlelabs/sifter",
|
|
21307
|
-
version: "0.
|
|
21487
|
+
version: "0.11.0",
|
|
21308
21488
|
description: "Whittle Sifter: paired AI reviewer for Whittle Sift job pools.",
|
|
21309
21489
|
bin: {
|
|
21310
21490
|
"whittle-sifter": "./dist/bin.js"
|