@whittlelabs/sifter 0.9.0 → 0.10.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 +120 -10
  2. package/bin.js.map +4 -4
  3. 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) {
@@ -20551,7 +20635,9 @@ var require_shuttle = __commonJS({
20551
20635
  "use strict";
20552
20636
  Object.defineProperty(exports2, "__esModule", { value: true });
20553
20637
  exports2.Shuttle = void 0;
20638
+ var os_1 = require("os");
20554
20639
  var jobs_1 = require_dist2();
20640
+ var self_update_1 = require_self_update();
20555
20641
  var loom_1 = require_dist3();
20556
20642
  var chain_1 = require_chain();
20557
20643
  var keep_1 = require_dist4();
@@ -20691,6 +20777,13 @@ var require_shuttle = __commonJS({
20691
20777
  return { status: "completed", outputs };
20692
20778
  };
20693
20779
  const pools = this.config.pools.map((p) => p.id ? { id: p.id } : { name: p.name });
20780
+ const subscribeLogger = {
20781
+ debug: (msg, meta) => logger.debug(msg, meta),
20782
+ info: (msg, meta) => logger.info(msg, meta),
20783
+ warn: (msg, meta) => logger.warn(msg, meta),
20784
+ error: (msg, meta) => logger.error(msg, meta)
20785
+ };
20786
+ const attemptedUpgrades = /* @__PURE__ */ new Set();
20694
20787
  this.subscription = (0, jobs_1.subscribe)({
20695
20788
  jobsClient,
20696
20789
  pools,
@@ -20699,15 +20792,32 @@ var require_shuttle = __commonJS({
20699
20792
  identityId: this.config.agent.identityId,
20700
20793
  intelligence: "digital",
20701
20794
  displayName: this.config.agent.displayName,
20702
- metadata: this.config.agent.metadata
20795
+ // Self-reported build facts, refreshed on every registration.
20796
+ // Products read these off the pool-member row (Sift's settings
20797
+ // page shows the version and offers the upgrade action).
20798
+ metadata: {
20799
+ ...this.config.agent.metadata,
20800
+ client_version: this.brand.product.version,
20801
+ hostname: (0, os_1.hostname)()
20802
+ }
20703
20803
  },
20704
20804
  onJob,
20705
- logger: {
20706
- debug: (msg, meta) => logger.debug(msg, meta),
20707
- info: (msg, meta) => logger.info(msg, meta),
20708
- warn: (msg, meta) => logger.warn(msg, meta),
20709
- error: (msg, meta) => logger.error(msg, meta)
20805
+ onDirectives: async (directives) => {
20806
+ const directive = (0, self_update_1.readUpgradeDirective)(directives, this.brand.product.version, attemptedUpgrades);
20807
+ if (!directive)
20808
+ return;
20809
+ attemptedUpgrades.add(directive.requested_version);
20810
+ await (0, self_update_1.performSelfUpdate)({
20811
+ packageName: this.brand.product.packageName,
20812
+ directive,
20813
+ logger: subscribeLogger,
20814
+ hooks: {
20815
+ stopLoop: () => this.subscription?.stop() ?? Promise.resolve(),
20816
+ restartLoop: () => this.subscription?.start() ?? Promise.resolve()
20817
+ }
20818
+ });
20710
20819
  },
20820
+ logger: subscribeLogger,
20711
20821
  pollIntervalMs: this.config.polling.intervalMs,
20712
20822
  maxConcurrency: this.config.concurrency.maxJobs
20713
20823
  });
@@ -21304,7 +21414,7 @@ var import_shuttle = __toESM(require_dist5());
21304
21414
  // package.json
21305
21415
  var package_default = {
21306
21416
  name: "@whittlelabs/sifter",
21307
- version: "0.9.0",
21417
+ version: "0.10.0",
21308
21418
  description: "Whittle Sifter: paired AI reviewer for Whittle Sift job pools.",
21309
21419
  bin: {
21310
21420
  "whittle-sifter": "./dist/bin.js"