plures 1.15.0 → 1.16.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
@@ -44,10 +44,12 @@ if (event.type === "task.completed" && event.data.result?.agreement === 1) {
44
44
 
45
45
  ## API
46
46
 
47
+ - `plures.check(id, data, overrides?)`: run a check from your app's map, one line before the action it guards: `const check = await plures.check("refunds", { order_total, reason }); if (check.answer !== "Approve") return`. The check saved on Plures supplies the question, options, which fields people see (the rest come back in `kept_private`), who decides, how often, its conditions and what happens on a timeout, so you change them on Plures, not in code. `checked` says whether a person looked; `skipped_because` says why not. Overrides: `question`, `options`, `verifiers`, `team`, `route`, `sample`, `timeout`, `always`.
48
+ - `npx plures check add <id> --app <app>`: Claude Code puts that line before the action on a new branch. On GitHub (the dashboard's **Add it to my code**) Plures then opens a pull request.
47
49
  - `plures.tasks.create(params, { idempotencyKey? })`: send a task. Params: `question`, `options` (2 to 8, strings or `{ id, label }`), `context`, `image_url`, `audio_url` or `video_url` with `media_seconds` (a clip up to 180 seconds that people play through before answering), `sensitive`, `instructions`, `verifiers` (1, 3, 5, 7 or 9), `max_verifiers`, `presence_check` (default true), `webhook_url`, `metadata`, `expires_in`, `route` (`"team"` sends it straight to your own people, $0.05 per internal vote live), `category` (matches your routing rules) and `team` (one of your named teams), `team_votes` and `team_unanimous` (internal consensus: how many of your team vote, and whether they must all agree; a split goes to the team's lead).
48
50
  - `plures.tasks.retrieve(id)`, `plures.tasks.list({ status?, limit?, starting_after?, app? })`, `plures.tasks.cancel(id)`
49
51
  - `new Plures(key, { app: "support-agent" })` or `PLURES_APP`: send everything to one of your apps. `plures.apps.list()`, `.create({ name, id? })`, `.retrieve(id)`, `.update(id, { name?, id?, default? })`, `.del(id)`. Each app keeps its own tasks, ledger view, map and quality.
50
- - `plures.maps.guide()`, `.retrieve(app)`, `.upload(app, map)`, `.setCheckpoint(app, id, status)`: the agent map, where your agent needs a person. Or run `npx plures map` in your repo: your own coding agent reads the code and only the map is sent.
52
+ - `plures.maps.guide()`, `.retrieve(app)`, `.upload(app, map, { branch? })` (a branch other than main gets its own map, compared with main and noted on its pull request), `.setCheckpoint(app, id, status)`: the agent map, where your agent needs a person. Or run `npx plures map` in your repo: your own coding agent reads the code and only the map is sent.
51
53
  - `plures.maps.createKey(app, { label? })`, `.keys(app)`, `.revokeKey(app, id)`: map keys for CI, which can only read and upload that app's map. `.workflow(app, branch?)` returns the GitHub Action that maps on every push; `npx plures map workflow` writes it to `.github/workflows/plures-map.yml`. Or use **Map with GitHub** on the app's map page and Plures opens the pull request for you, then **Turn on mapping** merges it. `plures.maps.startRun(app)` and `.runs(app)`: in CI with no Claude key, `npx plures map` starts a run where Plures runs Claude (first map free, then Claude's cost plus 30%, at most $5).
52
54
  - In your terminal, `npx plures map` opens your map page so you can watch it build (`--no-open` to skip), keeps one live line of what it's reading, and ends by drawing the map's flows with the checks Plures suggests. On GitHub and other CI it prints a plain log.
53
55
  - `npx plures map` shows each file as Claude Code reads it and sends the file names (never their contents) to Plures, so the map page shows the reading live and the map builds itself when it lands. `plures.maps.progress(app, { session, phase, events })` is the call behind it.
@@ -1,5 +1,5 @@
1
1
  // src/index.ts
2
- var VERSION = "1.15.0";
2
+ var VERSION = "1.16.0";
3
3
  var PluresError = class extends Error {
4
4
  constructor(message, status, type) {
5
5
  super(message);
@@ -100,7 +100,8 @@ var Plures = class {
100
100
  },
101
101
  retrieve: (app) => this.req("GET", `/api/v1/apps/${encodeURIComponent(app)}/map`),
102
102
  /** Uploads a new version. Checks you already added or dismissed keep that. */
103
- upload: (app, map) => this.req("PUT", `/api/v1/apps/${encodeURIComponent(app)}/map`, map),
103
+ /** A branch other than the main one gets its own map, compared with main, and noted on its pull request. */
104
+ upload: (app, map, opts = {}) => this.req("PUT", `/api/v1/apps/${encodeURIComponent(app)}/map`, map, opts.branch ? { "plures-branch": opts.branch } : {}),
104
105
  setCheckpoint: (app, id, status) => this.req("PATCH", `/api/v1/apps/${encodeURIComponent(app)}/map/checkpoints/${encodeURIComponent(id)}`, { status }),
105
106
  /** A key that can only read and upload this app's map, for CI. The key is in the response once. */
106
107
  createKey: (app, opts = {}) => this.req("POST", `/api/v1/apps/${encodeURIComponent(app)}/map_keys`, opts),
@@ -111,6 +112,8 @@ var Plures = class {
111
112
  runs: (app) => this.req("GET", `/api/v1/apps/${encodeURIComponent(app)}/map_runs`),
112
113
  /** While mapping, which files the coding agent is reading, shown live on the map page. File names only. npx plures map does this. */
113
114
  progress: (app, p) => this.req("POST", `/api/v1/apps/${encodeURIComponent(app)}/map/progress`, p),
115
+ /** After npx plures check add pushed a branch with the check in it: Plures opens the pull request. Pass error instead if adding it failed. */
116
+ checkPr: (app, id, p) => this.req("POST", `/api/v1/apps/${encodeURIComponent(app)}/checks/${encodeURIComponent(id)}/pr`, p),
114
117
  /** The GitHub Actions workflow that maps a repo on every push to its main branch. */
115
118
  workflow: async (app, branch = "main") => {
116
119
  const r = await fetch(`${this.base}/api/v1/map_workflow?app=${encodeURIComponent(app)}&branch=${encodeURIComponent(branch)}`);
@@ -168,6 +171,32 @@ var Plures = class {
168
171
  };
169
172
  /** Your prepaid credit. A live task that could cost more than available_cents is refused with a 402 insufficient_credits error. */
170
173
  balance = () => this.req("GET", "/api/v1/balance");
174
+ /**
175
+ * Runs a check from your app's map and waits for the decision. Send the data by name; the check
176
+ * saved on Plures supplies the question, options, guidance, which fields people see (the rest
177
+ * never leave Plures), who decides, how often and what happens on a timeout. Any of those can be
178
+ * overridden for this call. `answer` is the option to act on: what people chose, the first option
179
+ * when the check wasn't needed (a sample or a condition) or timed out set to go ahead, and null
180
+ * when it timed out set to hold.
181
+ */
182
+ async check(id, data = {}, overrides = {}, opts = {}) {
183
+ const t = await this.req("POST", `/api/v1/checks/${encodeURIComponent(id)}`, { data, ...overrides }, opts.idempotencyKey ? { "idempotency-key": opts.idempotencyKey } : {});
184
+ const final = t.status === "pending" ? await this.tasks.waitFor(t.id, { timeoutMs: opts.timeoutMs }) : t;
185
+ const opt = (k) => final.options.find((o) => o.id === k)?.label ?? k ?? null;
186
+ const first = final.options[0]?.label ?? null;
187
+ const timedOut = final.status === "expired" || final.status === "pending";
188
+ const answer = final.status === "completed" ? opt(final.result?.answer) : final.status === "skipped" ? first : timedOut && t.on_timeout === "proceed" ? first : null;
189
+ return {
190
+ ...final,
191
+ check: t.check,
192
+ on_timeout: t.on_timeout,
193
+ kept_private: t.kept_private ?? [],
194
+ skipped_because: t.skipped_because ?? null,
195
+ answer,
196
+ checked: final.status !== "skipped",
197
+ timed_out: timedOut
198
+ };
199
+ }
171
200
  /** Creates a task and waits for people to answer it. */
172
201
  async verify(params, opts = {}) {
173
202
  const t = await this.tasks.create(params, { idempotencyKey: opts.idempotencyKey });
package/dist/cli.cjs CHANGED
@@ -30,7 +30,7 @@ var import_node_path = require("path");
30
30
  var import_node_fs = require("fs");
31
31
 
32
32
  // src/index.ts
33
- var VERSION = "1.15.0";
33
+ var VERSION = "1.16.0";
34
34
  var PluresError = class extends Error {
35
35
  constructor(message, status, type) {
36
36
  super(message);
@@ -131,7 +131,8 @@ var Plures = class {
131
131
  },
132
132
  retrieve: (app2) => this.req("GET", `/api/v1/apps/${encodeURIComponent(app2)}/map`),
133
133
  /** Uploads a new version. Checks you already added or dismissed keep that. */
134
- upload: (app2, map2) => this.req("PUT", `/api/v1/apps/${encodeURIComponent(app2)}/map`, map2),
134
+ /** A branch other than the main one gets its own map, compared with main, and noted on its pull request. */
135
+ upload: (app2, map2, opts = {}) => this.req("PUT", `/api/v1/apps/${encodeURIComponent(app2)}/map`, map2, opts.branch ? { "plures-branch": opts.branch } : {}),
135
136
  setCheckpoint: (app2, id, status) => this.req("PATCH", `/api/v1/apps/${encodeURIComponent(app2)}/map/checkpoints/${encodeURIComponent(id)}`, { status }),
136
137
  /** A key that can only read and upload this app's map, for CI. The key is in the response once. */
137
138
  createKey: (app2, opts = {}) => this.req("POST", `/api/v1/apps/${encodeURIComponent(app2)}/map_keys`, opts),
@@ -142,6 +143,8 @@ var Plures = class {
142
143
  runs: (app2) => this.req("GET", `/api/v1/apps/${encodeURIComponent(app2)}/map_runs`),
143
144
  /** While mapping, which files the coding agent is reading, shown live on the map page. File names only. npx plures map does this. */
144
145
  progress: (app2, p) => this.req("POST", `/api/v1/apps/${encodeURIComponent(app2)}/map/progress`, p),
146
+ /** After npx plures check add pushed a branch with the check in it: Plures opens the pull request. Pass error instead if adding it failed. */
147
+ checkPr: (app2, id, p) => this.req("POST", `/api/v1/apps/${encodeURIComponent(app2)}/checks/${encodeURIComponent(id)}/pr`, p),
145
148
  /** The GitHub Actions workflow that maps a repo on every push to its main branch. */
146
149
  workflow: async (app2, branch2 = "main") => {
147
150
  const r = await fetch(`${this.base}/api/v1/map_workflow?app=${encodeURIComponent(app2)}&branch=${encodeURIComponent(branch2)}`);
@@ -199,6 +202,32 @@ var Plures = class {
199
202
  };
200
203
  /** Your prepaid credit. A live task that could cost more than available_cents is refused with a 402 insufficient_credits error. */
201
204
  balance = () => this.req("GET", "/api/v1/balance");
205
+ /**
206
+ * Runs a check from your app's map and waits for the decision. Send the data by name; the check
207
+ * saved on Plures supplies the question, options, guidance, which fields people see (the rest
208
+ * never leave Plures), who decides, how often and what happens on a timeout. Any of those can be
209
+ * overridden for this call. `answer` is the option to act on: what people chose, the first option
210
+ * when the check wasn't needed (a sample or a condition) or timed out set to go ahead, and null
211
+ * when it timed out set to hold.
212
+ */
213
+ async check(id, data = {}, overrides = {}, opts = {}) {
214
+ const t = await this.req("POST", `/api/v1/checks/${encodeURIComponent(id)}`, { data, ...overrides }, opts.idempotencyKey ? { "idempotency-key": opts.idempotencyKey } : {});
215
+ const final = t.status === "pending" ? await this.tasks.waitFor(t.id, { timeoutMs: opts.timeoutMs }) : t;
216
+ const opt = (k) => final.options.find((o) => o.id === k)?.label ?? k ?? null;
217
+ const first = final.options[0]?.label ?? null;
218
+ const timedOut = final.status === "expired" || final.status === "pending";
219
+ const answer = final.status === "completed" ? opt(final.result?.answer) : final.status === "skipped" ? first : timedOut && t.on_timeout === "proceed" ? first : null;
220
+ return {
221
+ ...final,
222
+ check: t.check,
223
+ on_timeout: t.on_timeout,
224
+ kept_private: t.kept_private ?? [],
225
+ skipped_because: t.skipped_because ?? null,
226
+ answer,
227
+ checked: final.status !== "skipped",
228
+ timed_out: timedOut
229
+ };
230
+ }
202
231
  /** Creates a task and waits for people to answer it. */
203
232
  async verify(params, opts = {}) {
204
233
  const t = await this.tasks.create(params, { idempotencyKey: opts.idempotencyKey });
@@ -446,11 +475,19 @@ async function upload(file) {
446
475
  }
447
476
  if (!fancy) console.log(dim(`Sending the map to Plures. No source code is sent.`));
448
477
  let m;
478
+ const gitBranch = (0, import_node_child_process.spawnSync)("git", ["rev-parse", "--abbrev-ref", "HEAD"], { encoding: "utf8" }).stdout?.trim();
479
+ const branchName = process.env.PLURES_BRANCH || process.env.GITHUB_HEAD_REF || process.env.GITHUB_REF_NAME || (gitBranch && gitBranch !== "HEAD" ? gitBranch : "");
449
480
  try {
450
- m = await client().maps.upload(app, map2);
481
+ m = await client().maps.upload(app, map2, branchName ? { branch: branchName } : {});
451
482
  } catch (e) {
452
483
  die(e instanceof PluresError ? `Plures said: ${e.message}` : String(e));
453
484
  }
485
+ if (m.branch) console.log(`${bold(`Branch ${m.branch}`)}: compared with the main map${m.main_version ? ` (version ${m.main_version})` : ""}, not replacing it.${m.pull_request ? ` Noted on ${m.pull_request}` : ""}`);
486
+ if (m.changes && (m.changes.added.length || m.changes.removed.length || m.changes.renamed.length || m.changes.risky.length)) {
487
+ const c2 = m.changes;
488
+ console.log(`${dim("Changes:")} ${[c2.added.length ? `${c2.added.length} new` : "", c2.renamed.length ? `${c2.renamed.length} renamed, checks kept` : "", c2.removed.length ? `${c2.removed.length} removed` : ""].filter(Boolean).join(", ") || "no new actions"}`);
489
+ for (const r of c2.risky) console.log(` ${coral("no check")} ${r.label} ${dim(`score ${r.score}: ${r.why.join("; ")}`)}`);
490
+ }
454
491
  if (fancy) drawMap(m, m.url ?? `${base}/dashboard/apps/${m.app}/map`);
455
492
  else report(m);
456
493
  }
@@ -669,8 +706,87 @@ It adds one workflow file. Review it, then turn mapping on with ${cyan("npx plur
669
706
  throw e;
670
707
  }
671
708
  }
709
+ async function checkAdd(id) {
710
+ if (!id) die("npx plures check add <check id> [--app <app>]");
711
+ const cl = client();
712
+ const report2 = async (p) => {
713
+ if (process.env.GITHUB_ACTIONS) await cl.maps.checkPr(app, id, p).catch(() => {
714
+ });
715
+ };
716
+ const fail = async (msg) => {
717
+ await report2({ error: msg });
718
+ die(msg);
719
+ };
720
+ let m;
721
+ try {
722
+ m = await cl.maps.retrieve(app);
723
+ } catch (e) {
724
+ return fail(e instanceof PluresError ? e.message : String(e));
725
+ }
726
+ const cp0 = m.checkpoints.find((x) => x.id === id || x.category === id);
727
+ const cp = cp0;
728
+ if (!cp0) return fail(`No check called ${id} on ${app}'s map.`);
729
+ const action = m.nodes.find((n) => n.id === cp.at);
730
+ const cid = cp.id ?? id;
731
+ if (!cp.code) return fail(`The check ${cid} has no drafted question yet. Edit it on Plures first.`);
732
+ if (!hasClaude()) return fail("Claude Code isn't installed here, so nothing could add the line. Copy it from the check's page instead.");
733
+ const git = (...a) => (0, import_node_child_process.spawnSync)("git", a, { encoding: "utf8" });
734
+ if (git("status", "--porcelain").stdout.trim()) return fail("This repo has changes that aren't committed. Commit or stash them first.");
735
+ const childEnv = { ...process.env };
736
+ const ownClaude = Boolean(process.env.ANTHROPIC_API_KEY || process.env.CLAUDE_CODE_OAUTH_TOKEN || process.env.ANTHROPIC_AUTH_TOKEN);
737
+ if (!ownClaude && process.env.CI) {
738
+ try {
739
+ const run = await cl.maps.startRun(app);
740
+ childEnv.ANTHROPIC_BASE_URL = run.base_url;
741
+ childEnv.ANTHROPIC_API_KEY = run.token;
742
+ } catch (e) {
743
+ return fail(e instanceof PluresError ? e.message : String(e));
744
+ }
745
+ }
746
+ const where = action?.file ? `${action.file}${action.line ? ` near line ${action.line}` : ""}` : "the code";
747
+ console.log(`Adding the check ${bold(cid)} before ${bold(action?.label ?? cp.at)}, in ${where}.`);
748
+ const prompt = `Add one Plures human check to this codebase. Change as little as possible.
749
+
750
+ Where: just before the step "${action?.label ?? cp.at}"${action?.via ? ` (it goes through ${action.via})` : ""}, in ${where}. Find the exact place; the line may have moved.
751
+
752
+ What to add, adapted to the file's language and style (for Python: \`check = plures.check("${cid}", fields)\` and \`check.answer\`):
753
+
754
+ ${cp.code}
755
+
756
+ - fields: an object with the values a person needs to decide, taken from variables already in scope at that point${cp.draft?.show?.length ? `. Use these field names: ${cp.draft.show.join(", ")}` : ""}. Never pass secrets, card numbers or passwords.
757
+ - If the answer isn't the first option, the agent must not do the step: return, skip, or raise, whichever fits the code around it.
758
+ - If the file has no Plures client yet, add one: JavaScript or TypeScript \`import { Plures } from "plures"\` and \`const plures = new Plures(process.env.PLURES_API_KEY${app !== "default" ? `, { app: "${app}" }` : ""})\`; Python \`from plures import Plures\` and \`plures = Plures(os.environ["PLURES_API_KEY"]${app !== "default" ? `, app="${app}"` : ""})\`. Keep to how the project sets up other clients.
759
+ - If the package isn't a dependency yet, add "plures" to package.json dependencies, or plures to requirements.txt or pyproject.toml, whichever the project uses. Don't run installers.
760
+ - Don't change anything else, don't reformat, don't add tests, and don't run commands.`;
761
+ const code = await new Promise((resolve) => {
762
+ const p = (0, import_node_child_process.spawn)("claude", ["-p", prompt, "--allowedTools", "Read,Grep,Glob,Edit,Write"], { stdio: ["ignore", "inherit", "inherit"], env: childEnv });
763
+ p.on("close", (n) => resolve(n ?? 1));
764
+ p.on("error", () => resolve(1));
765
+ });
766
+ const changed = git("status", "--porcelain").stdout.trim();
767
+ if (code !== 0 || !changed) return fail("Claude Code didn't change any files, so there's nothing to review. Copy the line from the check's page instead.");
768
+ const br = `plures/check-${cid.replace(/[^a-z0-9_-]+/gi, "-")}-${Date.now().toString(36)}`;
769
+ for (const a of [["checkout", "-b", br], ["add", "-A"], ["commit", "-m", `Add the Plures check ${cid} before ${(action?.label ?? cp.at).toLowerCase()}`]]) {
770
+ const r = git(...a);
771
+ if (r.status !== 0) return fail(`git ${a[0]} failed: ${(r.stderr || r.stdout).trim().slice(0, 200)}`);
772
+ }
773
+ if (!process.env.GITHUB_ACTIONS) {
774
+ console.log(`
775
+ ${cyan("\u2713")} The check is on the branch ${bold(br)}. Review it with ${cyan("git show")}, then push it and open a pull request.`);
776
+ return;
777
+ }
778
+ const push = git("push", "-u", "origin", br);
779
+ if (push.status !== 0) return fail(`Pushing the branch failed: ${(push.stderr || push.stdout).trim().slice(0, 200)}`);
780
+ try {
781
+ const r = await cl.maps.checkPr(app, cid, { branch: br });
782
+ console.log(`${cyan("\u2713")} Pull request: ${r.pull_request ?? "opened"}`);
783
+ } catch (e) {
784
+ die(e instanceof PluresError ? e.message : String(e));
785
+ }
786
+ }
672
787
  async function main() {
673
788
  const [cmd, sub, arg] = argv;
789
+ if (cmd === "check" && sub === "add") return checkAdd(arg);
674
790
  if (cmd !== "map") {
675
791
  console.log(`Plures
676
792
 
@@ -681,6 +797,7 @@ async function main() {
681
797
  npx plures map github connect let Plures add that Action by pull request
682
798
  npx plures map github on merge it, which turns mapping on
683
799
  npx plures map github run map now on GitHub, and watch it build
800
+ npx plures check add <id> put a check into your code, on a new branch
684
801
 
685
802
  Docs: https://plures.si/docs`);
686
803
  return;
package/dist/cli.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  Plures,
4
4
  PluresError,
5
5
  VERSION
6
- } from "./chunk-JSR4MDEK.js";
6
+ } from "./chunk-Z75ZTXHZ.js";
7
7
 
8
8
  // src/cli.ts
9
9
  import { spawnSync, spawn } from "child_process";
@@ -228,11 +228,19 @@ async function upload(file) {
228
228
  }
229
229
  if (!fancy) console.log(dim(`Sending the map to Plures. No source code is sent.`));
230
230
  let m;
231
+ const gitBranch = spawnSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], { encoding: "utf8" }).stdout?.trim();
232
+ const branchName = process.env.PLURES_BRANCH || process.env.GITHUB_HEAD_REF || process.env.GITHUB_REF_NAME || (gitBranch && gitBranch !== "HEAD" ? gitBranch : "");
231
233
  try {
232
- m = await client().maps.upload(app, map2);
234
+ m = await client().maps.upload(app, map2, branchName ? { branch: branchName } : {});
233
235
  } catch (e) {
234
236
  die(e instanceof PluresError ? `Plures said: ${e.message}` : String(e));
235
237
  }
238
+ if (m.branch) console.log(`${bold(`Branch ${m.branch}`)}: compared with the main map${m.main_version ? ` (version ${m.main_version})` : ""}, not replacing it.${m.pull_request ? ` Noted on ${m.pull_request}` : ""}`);
239
+ if (m.changes && (m.changes.added.length || m.changes.removed.length || m.changes.renamed.length || m.changes.risky.length)) {
240
+ const c2 = m.changes;
241
+ console.log(`${dim("Changes:")} ${[c2.added.length ? `${c2.added.length} new` : "", c2.renamed.length ? `${c2.renamed.length} renamed, checks kept` : "", c2.removed.length ? `${c2.removed.length} removed` : ""].filter(Boolean).join(", ") || "no new actions"}`);
242
+ for (const r of c2.risky) console.log(` ${coral("no check")} ${r.label} ${dim(`score ${r.score}: ${r.why.join("; ")}`)}`);
243
+ }
236
244
  if (fancy) drawMap(m, m.url ?? `${base}/dashboard/apps/${m.app}/map`);
237
245
  else report(m);
238
246
  }
@@ -451,8 +459,87 @@ It adds one workflow file. Review it, then turn mapping on with ${cyan("npx plur
451
459
  throw e;
452
460
  }
453
461
  }
462
+ async function checkAdd(id) {
463
+ if (!id) die("npx plures check add <check id> [--app <app>]");
464
+ const cl = client();
465
+ const report2 = async (p) => {
466
+ if (process.env.GITHUB_ACTIONS) await cl.maps.checkPr(app, id, p).catch(() => {
467
+ });
468
+ };
469
+ const fail = async (msg) => {
470
+ await report2({ error: msg });
471
+ die(msg);
472
+ };
473
+ let m;
474
+ try {
475
+ m = await cl.maps.retrieve(app);
476
+ } catch (e) {
477
+ return fail(e instanceof PluresError ? e.message : String(e));
478
+ }
479
+ const cp0 = m.checkpoints.find((x) => x.id === id || x.category === id);
480
+ const cp = cp0;
481
+ if (!cp0) return fail(`No check called ${id} on ${app}'s map.`);
482
+ const action = m.nodes.find((n) => n.id === cp.at);
483
+ const cid = cp.id ?? id;
484
+ if (!cp.code) return fail(`The check ${cid} has no drafted question yet. Edit it on Plures first.`);
485
+ if (!hasClaude()) return fail("Claude Code isn't installed here, so nothing could add the line. Copy it from the check's page instead.");
486
+ const git = (...a) => spawnSync("git", a, { encoding: "utf8" });
487
+ if (git("status", "--porcelain").stdout.trim()) return fail("This repo has changes that aren't committed. Commit or stash them first.");
488
+ const childEnv = { ...process.env };
489
+ const ownClaude = Boolean(process.env.ANTHROPIC_API_KEY || process.env.CLAUDE_CODE_OAUTH_TOKEN || process.env.ANTHROPIC_AUTH_TOKEN);
490
+ if (!ownClaude && process.env.CI) {
491
+ try {
492
+ const run = await cl.maps.startRun(app);
493
+ childEnv.ANTHROPIC_BASE_URL = run.base_url;
494
+ childEnv.ANTHROPIC_API_KEY = run.token;
495
+ } catch (e) {
496
+ return fail(e instanceof PluresError ? e.message : String(e));
497
+ }
498
+ }
499
+ const where = action?.file ? `${action.file}${action.line ? ` near line ${action.line}` : ""}` : "the code";
500
+ console.log(`Adding the check ${bold(cid)} before ${bold(action?.label ?? cp.at)}, in ${where}.`);
501
+ const prompt = `Add one Plures human check to this codebase. Change as little as possible.
502
+
503
+ Where: just before the step "${action?.label ?? cp.at}"${action?.via ? ` (it goes through ${action.via})` : ""}, in ${where}. Find the exact place; the line may have moved.
504
+
505
+ What to add, adapted to the file's language and style (for Python: \`check = plures.check("${cid}", fields)\` and \`check.answer\`):
506
+
507
+ ${cp.code}
508
+
509
+ - fields: an object with the values a person needs to decide, taken from variables already in scope at that point${cp.draft?.show?.length ? `. Use these field names: ${cp.draft.show.join(", ")}` : ""}. Never pass secrets, card numbers or passwords.
510
+ - If the answer isn't the first option, the agent must not do the step: return, skip, or raise, whichever fits the code around it.
511
+ - If the file has no Plures client yet, add one: JavaScript or TypeScript \`import { Plures } from "plures"\` and \`const plures = new Plures(process.env.PLURES_API_KEY${app !== "default" ? `, { app: "${app}" }` : ""})\`; Python \`from plures import Plures\` and \`plures = Plures(os.environ["PLURES_API_KEY"]${app !== "default" ? `, app="${app}"` : ""})\`. Keep to how the project sets up other clients.
512
+ - If the package isn't a dependency yet, add "plures" to package.json dependencies, or plures to requirements.txt or pyproject.toml, whichever the project uses. Don't run installers.
513
+ - Don't change anything else, don't reformat, don't add tests, and don't run commands.`;
514
+ const code = await new Promise((resolve) => {
515
+ const p = spawn("claude", ["-p", prompt, "--allowedTools", "Read,Grep,Glob,Edit,Write"], { stdio: ["ignore", "inherit", "inherit"], env: childEnv });
516
+ p.on("close", (n) => resolve(n ?? 1));
517
+ p.on("error", () => resolve(1));
518
+ });
519
+ const changed = git("status", "--porcelain").stdout.trim();
520
+ if (code !== 0 || !changed) return fail("Claude Code didn't change any files, so there's nothing to review. Copy the line from the check's page instead.");
521
+ const br = `plures/check-${cid.replace(/[^a-z0-9_-]+/gi, "-")}-${Date.now().toString(36)}`;
522
+ for (const a of [["checkout", "-b", br], ["add", "-A"], ["commit", "-m", `Add the Plures check ${cid} before ${(action?.label ?? cp.at).toLowerCase()}`]]) {
523
+ const r = git(...a);
524
+ if (r.status !== 0) return fail(`git ${a[0]} failed: ${(r.stderr || r.stdout).trim().slice(0, 200)}`);
525
+ }
526
+ if (!process.env.GITHUB_ACTIONS) {
527
+ console.log(`
528
+ ${cyan("\u2713")} The check is on the branch ${bold(br)}. Review it with ${cyan("git show")}, then push it and open a pull request.`);
529
+ return;
530
+ }
531
+ const push = git("push", "-u", "origin", br);
532
+ if (push.status !== 0) return fail(`Pushing the branch failed: ${(push.stderr || push.stdout).trim().slice(0, 200)}`);
533
+ try {
534
+ const r = await cl.maps.checkPr(app, cid, { branch: br });
535
+ console.log(`${cyan("\u2713")} Pull request: ${r.pull_request ?? "opened"}`);
536
+ } catch (e) {
537
+ die(e instanceof PluresError ? e.message : String(e));
538
+ }
539
+ }
454
540
  async function main() {
455
541
  const [cmd, sub, arg] = argv;
542
+ if (cmd === "check" && sub === "add") return checkAdd(arg);
456
543
  if (cmd !== "map") {
457
544
  console.log(`Plures
458
545
 
@@ -463,6 +550,7 @@ async function main() {
463
550
  npx plures map github connect let Plures add that Action by pull request
464
551
  npx plures map github on merge it, which turns mapping on
465
552
  npx plures map github run map now on GitHub, and watch it build
553
+ npx plures check add <id> put a check into your code, on a new branch
466
554
 
467
555
  Docs: https://plures.si/docs`);
468
556
  return;
package/dist/index.cjs CHANGED
@@ -26,7 +26,7 @@ __export(index_exports, {
26
26
  default: () => index_default
27
27
  });
28
28
  module.exports = __toCommonJS(index_exports);
29
- var VERSION = "1.15.0";
29
+ var VERSION = "1.16.0";
30
30
  var PluresError = class extends Error {
31
31
  constructor(message, status, type) {
32
32
  super(message);
@@ -127,7 +127,8 @@ var Plures = class {
127
127
  },
128
128
  retrieve: (app) => this.req("GET", `/api/v1/apps/${encodeURIComponent(app)}/map`),
129
129
  /** Uploads a new version. Checks you already added or dismissed keep that. */
130
- upload: (app, map) => this.req("PUT", `/api/v1/apps/${encodeURIComponent(app)}/map`, map),
130
+ /** A branch other than the main one gets its own map, compared with main, and noted on its pull request. */
131
+ upload: (app, map, opts = {}) => this.req("PUT", `/api/v1/apps/${encodeURIComponent(app)}/map`, map, opts.branch ? { "plures-branch": opts.branch } : {}),
131
132
  setCheckpoint: (app, id, status) => this.req("PATCH", `/api/v1/apps/${encodeURIComponent(app)}/map/checkpoints/${encodeURIComponent(id)}`, { status }),
132
133
  /** A key that can only read and upload this app's map, for CI. The key is in the response once. */
133
134
  createKey: (app, opts = {}) => this.req("POST", `/api/v1/apps/${encodeURIComponent(app)}/map_keys`, opts),
@@ -138,6 +139,8 @@ var Plures = class {
138
139
  runs: (app) => this.req("GET", `/api/v1/apps/${encodeURIComponent(app)}/map_runs`),
139
140
  /** While mapping, which files the coding agent is reading, shown live on the map page. File names only. npx plures map does this. */
140
141
  progress: (app, p) => this.req("POST", `/api/v1/apps/${encodeURIComponent(app)}/map/progress`, p),
142
+ /** After npx plures check add pushed a branch with the check in it: Plures opens the pull request. Pass error instead if adding it failed. */
143
+ checkPr: (app, id, p) => this.req("POST", `/api/v1/apps/${encodeURIComponent(app)}/checks/${encodeURIComponent(id)}/pr`, p),
141
144
  /** The GitHub Actions workflow that maps a repo on every push to its main branch. */
142
145
  workflow: async (app, branch = "main") => {
143
146
  const r = await fetch(`${this.base}/api/v1/map_workflow?app=${encodeURIComponent(app)}&branch=${encodeURIComponent(branch)}`);
@@ -195,6 +198,32 @@ var Plures = class {
195
198
  };
196
199
  /** Your prepaid credit. A live task that could cost more than available_cents is refused with a 402 insufficient_credits error. */
197
200
  balance = () => this.req("GET", "/api/v1/balance");
201
+ /**
202
+ * Runs a check from your app's map and waits for the decision. Send the data by name; the check
203
+ * saved on Plures supplies the question, options, guidance, which fields people see (the rest
204
+ * never leave Plures), who decides, how often and what happens on a timeout. Any of those can be
205
+ * overridden for this call. `answer` is the option to act on: what people chose, the first option
206
+ * when the check wasn't needed (a sample or a condition) or timed out set to go ahead, and null
207
+ * when it timed out set to hold.
208
+ */
209
+ async check(id, data = {}, overrides = {}, opts = {}) {
210
+ const t = await this.req("POST", `/api/v1/checks/${encodeURIComponent(id)}`, { data, ...overrides }, opts.idempotencyKey ? { "idempotency-key": opts.idempotencyKey } : {});
211
+ const final = t.status === "pending" ? await this.tasks.waitFor(t.id, { timeoutMs: opts.timeoutMs }) : t;
212
+ const opt = (k) => final.options.find((o) => o.id === k)?.label ?? k ?? null;
213
+ const first = final.options[0]?.label ?? null;
214
+ const timedOut = final.status === "expired" || final.status === "pending";
215
+ const answer = final.status === "completed" ? opt(final.result?.answer) : final.status === "skipped" ? first : timedOut && t.on_timeout === "proceed" ? first : null;
216
+ return {
217
+ ...final,
218
+ check: t.check,
219
+ on_timeout: t.on_timeout,
220
+ kept_private: t.kept_private ?? [],
221
+ skipped_because: t.skipped_because ?? null,
222
+ answer,
223
+ checked: final.status !== "skipped",
224
+ timed_out: timedOut
225
+ };
226
+ }
198
227
  /** Creates a task and waits for people to answer it. */
199
228
  async verify(params, opts = {}) {
200
229
  const t = await this.tasks.create(params, { idempotencyKey: opts.idempotencyKey });
package/dist/index.d.cts CHANGED
@@ -4,6 +4,32 @@ type Option = {
4
4
  };
5
5
  /** "verifiers" asks ID verified people first; "team" goes straight to your own people ($0.05 per internal vote live). */
6
6
  type Route = "verifiers" | "team";
7
+ type CheckOverrides = {
8
+ question?: string;
9
+ options?: string[];
10
+ instructions?: string;
11
+ verifiers?: number;
12
+ team?: string;
13
+ route?: "verifiers" | "team";
14
+ /** Check this one even if the sample or a condition would skip it. */ always?: boolean;
15
+ /** Share of calls people check, 0 to 1, for this call. */ sample?: number;
16
+ /** Seconds people have to answer. */ timeout?: number;
17
+ metadata?: Record<string, unknown>;
18
+ webhook_url?: string;
19
+ };
20
+ type CheckExtra = {
21
+ check: string;
22
+ on_timeout: "proceed" | "hold";
23
+ kept_private?: string[];
24
+ skipped_because?: string;
25
+ };
26
+ type CheckResult = Task & Omit<CheckExtra, "kept_private" | "skipped_because"> & {
27
+ /** The option to act on, by label. */ answer: string | null;
28
+ /** false when the check wasn't needed this time (a sample or a condition). */ checked: boolean;
29
+ timed_out: boolean;
30
+ kept_private: string[];
31
+ skipped_because: string | null;
32
+ };
7
33
  type TaskStatus = "pending" | "completed" | "expired" | "canceled" | "skipped";
8
34
  type Result = {
9
35
  answer: string | null;
@@ -253,6 +279,30 @@ type MapKey = {
253
279
  created_at: string;
254
280
  last_used_at: string | null;
255
281
  };
282
+ type MapChanges = {
283
+ since: number | null;
284
+ added: {
285
+ id: string;
286
+ label: string;
287
+ score: number | null;
288
+ checked: boolean;
289
+ }[];
290
+ removed: {
291
+ id: string;
292
+ label: string;
293
+ }[];
294
+ renamed: {
295
+ from: string;
296
+ to: string;
297
+ label: string;
298
+ }[];
299
+ risky: {
300
+ id: string;
301
+ label: string;
302
+ score: number;
303
+ why: string[];
304
+ }[];
305
+ };
256
306
  type StoredAgentMap = AgentMap & {
257
307
  object: "agent_map";
258
308
  app: string;
@@ -260,6 +310,23 @@ type StoredAgentMap = AgentMap & {
260
310
  created_at?: string;
261
311
  via?: string;
262
312
  url?: string;
313
+ /** Set for a branch map: the branch, the main map version it's compared with, and its pull request. */
314
+ branch?: string;
315
+ main_version?: number | null;
316
+ pull_request?: string | null;
317
+ changes?: MapChanges;
318
+ engine?: {
319
+ version: string;
320
+ actions: Record<string, {
321
+ score: number;
322
+ factors: string[];
323
+ oversight: {
324
+ mode: string;
325
+ rate: number | null;
326
+ verifiers: number;
327
+ };
328
+ }>;
329
+ };
263
330
  };
264
331
  type Rubric = {
265
332
  object: "rubric";
@@ -352,7 +419,7 @@ type WebhookEvent = {
352
419
  created_at: string;
353
420
  data: Task;
354
421
  };
355
- declare const VERSION = "1.15.0";
422
+ declare const VERSION = "1.16.0";
356
423
  type GitHubLink = {
357
424
  object: "github_link";
358
425
  app: string;
@@ -469,7 +536,10 @@ declare class Plures {
469
536
  guide: () => Promise<string>;
470
537
  retrieve: (app: string) => Promise<StoredAgentMap>;
471
538
  /** Uploads a new version. Checks you already added or dismissed keep that. */
472
- upload: (app: string, map: AgentMap) => Promise<StoredAgentMap>;
539
+ /** A branch other than the main one gets its own map, compared with main, and noted on its pull request. */
540
+ upload: (app: string, map: AgentMap, opts?: {
541
+ branch?: string;
542
+ }) => Promise<StoredAgentMap>;
473
543
  setCheckpoint: (app: string, id: string, status: "added" | "dismissed" | "suggested") => Promise<StoredAgentMap>;
474
544
  /** A key that can only read and upload this app's map, for CI. The key is in the response once. */
475
545
  createKey: (app: string, opts?: {
@@ -525,6 +595,17 @@ declare class Plures {
525
595
  phase: string;
526
596
  received: number;
527
597
  }>;
598
+ /** After npx plures check add pushed a branch with the check in it: Plures opens the pull request. Pass error instead if adding it failed. */
599
+ checkPr: (app: string, id: string, p: {
600
+ branch: string;
601
+ } | {
602
+ error: string;
603
+ }) => Promise<{
604
+ object: "check_pr";
605
+ check: string;
606
+ opened: boolean;
607
+ pull_request?: string;
608
+ }>;
528
609
  /** The GitHub Actions workflow that maps a repo on every push to its main branch. */
529
610
  workflow: (app: string, branch?: string) => Promise<string>;
530
611
  };
@@ -654,6 +735,18 @@ declare class Plures {
654
735
  };
655
736
  /** Your prepaid credit. A live task that could cost more than available_cents is refused with a 402 insufficient_credits error. */
656
737
  balance: () => Promise<Balance>;
738
+ /**
739
+ * Runs a check from your app's map and waits for the decision. Send the data by name; the check
740
+ * saved on Plures supplies the question, options, guidance, which fields people see (the rest
741
+ * never leave Plures), who decides, how often and what happens on a timeout. Any of those can be
742
+ * overridden for this call. `answer` is the option to act on: what people chose, the first option
743
+ * when the check wasn't needed (a sample or a condition) or timed out set to go ahead, and null
744
+ * when it timed out set to hold.
745
+ */
746
+ check(id: string, data?: Record<string, unknown>, overrides?: CheckOverrides, opts?: {
747
+ timeoutMs?: number;
748
+ idempotencyKey?: string;
749
+ }): Promise<CheckResult>;
657
750
  /** Creates a task and waits for people to answer it. */
658
751
  verify(params: CreateTask, opts?: {
659
752
  timeoutMs?: number;
@@ -667,4 +760,4 @@ declare class Plures {
667
760
  static verifyWebhook(rawBody: string, signatureHeader: string | null, secret: string, toleranceSec?: number): Promise<WebhookEvent>;
668
761
  }
669
762
 
670
- export { type AgentMap, type App, type Balance, type Consensus, type CreateTask, type Escalation, type GitHubLink, type MapCheckpoint, type MapDraft, type MapKey, type MapNode, type Mix, type Option, Plures, PluresError, type Release, type Result, type Route, type Routing, type RoutingRule, type RoutingUpdate, type Rubric, type RubricParams, type Sample, type StoredAgentMap, type Task, type TaskStatus, type TeamTally, type TeamVote, type TestMix, VERSION, type WebhookEvent, Plures as default };
763
+ export { type AgentMap, type App, type Balance, type CheckOverrides, type CheckResult, type Consensus, type CreateTask, type Escalation, type GitHubLink, type MapChanges, type MapCheckpoint, type MapDraft, type MapKey, type MapNode, type Mix, type Option, Plures, PluresError, type Release, type Result, type Route, type Routing, type RoutingRule, type RoutingUpdate, type Rubric, type RubricParams, type Sample, type StoredAgentMap, type Task, type TaskStatus, type TeamTally, type TeamVote, type TestMix, VERSION, type WebhookEvent, Plures as default };
package/dist/index.d.ts CHANGED
@@ -4,6 +4,32 @@ type Option = {
4
4
  };
5
5
  /** "verifiers" asks ID verified people first; "team" goes straight to your own people ($0.05 per internal vote live). */
6
6
  type Route = "verifiers" | "team";
7
+ type CheckOverrides = {
8
+ question?: string;
9
+ options?: string[];
10
+ instructions?: string;
11
+ verifiers?: number;
12
+ team?: string;
13
+ route?: "verifiers" | "team";
14
+ /** Check this one even if the sample or a condition would skip it. */ always?: boolean;
15
+ /** Share of calls people check, 0 to 1, for this call. */ sample?: number;
16
+ /** Seconds people have to answer. */ timeout?: number;
17
+ metadata?: Record<string, unknown>;
18
+ webhook_url?: string;
19
+ };
20
+ type CheckExtra = {
21
+ check: string;
22
+ on_timeout: "proceed" | "hold";
23
+ kept_private?: string[];
24
+ skipped_because?: string;
25
+ };
26
+ type CheckResult = Task & Omit<CheckExtra, "kept_private" | "skipped_because"> & {
27
+ /** The option to act on, by label. */ answer: string | null;
28
+ /** false when the check wasn't needed this time (a sample or a condition). */ checked: boolean;
29
+ timed_out: boolean;
30
+ kept_private: string[];
31
+ skipped_because: string | null;
32
+ };
7
33
  type TaskStatus = "pending" | "completed" | "expired" | "canceled" | "skipped";
8
34
  type Result = {
9
35
  answer: string | null;
@@ -253,6 +279,30 @@ type MapKey = {
253
279
  created_at: string;
254
280
  last_used_at: string | null;
255
281
  };
282
+ type MapChanges = {
283
+ since: number | null;
284
+ added: {
285
+ id: string;
286
+ label: string;
287
+ score: number | null;
288
+ checked: boolean;
289
+ }[];
290
+ removed: {
291
+ id: string;
292
+ label: string;
293
+ }[];
294
+ renamed: {
295
+ from: string;
296
+ to: string;
297
+ label: string;
298
+ }[];
299
+ risky: {
300
+ id: string;
301
+ label: string;
302
+ score: number;
303
+ why: string[];
304
+ }[];
305
+ };
256
306
  type StoredAgentMap = AgentMap & {
257
307
  object: "agent_map";
258
308
  app: string;
@@ -260,6 +310,23 @@ type StoredAgentMap = AgentMap & {
260
310
  created_at?: string;
261
311
  via?: string;
262
312
  url?: string;
313
+ /** Set for a branch map: the branch, the main map version it's compared with, and its pull request. */
314
+ branch?: string;
315
+ main_version?: number | null;
316
+ pull_request?: string | null;
317
+ changes?: MapChanges;
318
+ engine?: {
319
+ version: string;
320
+ actions: Record<string, {
321
+ score: number;
322
+ factors: string[];
323
+ oversight: {
324
+ mode: string;
325
+ rate: number | null;
326
+ verifiers: number;
327
+ };
328
+ }>;
329
+ };
263
330
  };
264
331
  type Rubric = {
265
332
  object: "rubric";
@@ -352,7 +419,7 @@ type WebhookEvent = {
352
419
  created_at: string;
353
420
  data: Task;
354
421
  };
355
- declare const VERSION = "1.15.0";
422
+ declare const VERSION = "1.16.0";
356
423
  type GitHubLink = {
357
424
  object: "github_link";
358
425
  app: string;
@@ -469,7 +536,10 @@ declare class Plures {
469
536
  guide: () => Promise<string>;
470
537
  retrieve: (app: string) => Promise<StoredAgentMap>;
471
538
  /** Uploads a new version. Checks you already added or dismissed keep that. */
472
- upload: (app: string, map: AgentMap) => Promise<StoredAgentMap>;
539
+ /** A branch other than the main one gets its own map, compared with main, and noted on its pull request. */
540
+ upload: (app: string, map: AgentMap, opts?: {
541
+ branch?: string;
542
+ }) => Promise<StoredAgentMap>;
473
543
  setCheckpoint: (app: string, id: string, status: "added" | "dismissed" | "suggested") => Promise<StoredAgentMap>;
474
544
  /** A key that can only read and upload this app's map, for CI. The key is in the response once. */
475
545
  createKey: (app: string, opts?: {
@@ -525,6 +595,17 @@ declare class Plures {
525
595
  phase: string;
526
596
  received: number;
527
597
  }>;
598
+ /** After npx plures check add pushed a branch with the check in it: Plures opens the pull request. Pass error instead if adding it failed. */
599
+ checkPr: (app: string, id: string, p: {
600
+ branch: string;
601
+ } | {
602
+ error: string;
603
+ }) => Promise<{
604
+ object: "check_pr";
605
+ check: string;
606
+ opened: boolean;
607
+ pull_request?: string;
608
+ }>;
528
609
  /** The GitHub Actions workflow that maps a repo on every push to its main branch. */
529
610
  workflow: (app: string, branch?: string) => Promise<string>;
530
611
  };
@@ -654,6 +735,18 @@ declare class Plures {
654
735
  };
655
736
  /** Your prepaid credit. A live task that could cost more than available_cents is refused with a 402 insufficient_credits error. */
656
737
  balance: () => Promise<Balance>;
738
+ /**
739
+ * Runs a check from your app's map and waits for the decision. Send the data by name; the check
740
+ * saved on Plures supplies the question, options, guidance, which fields people see (the rest
741
+ * never leave Plures), who decides, how often and what happens on a timeout. Any of those can be
742
+ * overridden for this call. `answer` is the option to act on: what people chose, the first option
743
+ * when the check wasn't needed (a sample or a condition) or timed out set to go ahead, and null
744
+ * when it timed out set to hold.
745
+ */
746
+ check(id: string, data?: Record<string, unknown>, overrides?: CheckOverrides, opts?: {
747
+ timeoutMs?: number;
748
+ idempotencyKey?: string;
749
+ }): Promise<CheckResult>;
657
750
  /** Creates a task and waits for people to answer it. */
658
751
  verify(params: CreateTask, opts?: {
659
752
  timeoutMs?: number;
@@ -667,4 +760,4 @@ declare class Plures {
667
760
  static verifyWebhook(rawBody: string, signatureHeader: string | null, secret: string, toleranceSec?: number): Promise<WebhookEvent>;
668
761
  }
669
762
 
670
- export { type AgentMap, type App, type Balance, type Consensus, type CreateTask, type Escalation, type GitHubLink, type MapCheckpoint, type MapDraft, type MapKey, type MapNode, type Mix, type Option, Plures, PluresError, type Release, type Result, type Route, type Routing, type RoutingRule, type RoutingUpdate, type Rubric, type RubricParams, type Sample, type StoredAgentMap, type Task, type TaskStatus, type TeamTally, type TeamVote, type TestMix, VERSION, type WebhookEvent, Plures as default };
763
+ export { type AgentMap, type App, type Balance, type CheckOverrides, type CheckResult, type Consensus, type CreateTask, type Escalation, type GitHubLink, type MapChanges, type MapCheckpoint, type MapDraft, type MapKey, type MapNode, type Mix, type Option, Plures, PluresError, type Release, type Result, type Route, type Routing, type RoutingRule, type RoutingUpdate, type Rubric, type RubricParams, type Sample, type StoredAgentMap, type Task, type TaskStatus, type TeamTally, type TeamVote, type TestMix, VERSION, type WebhookEvent, Plures as default };
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  PluresError,
4
4
  VERSION,
5
5
  index_default
6
- } from "./chunk-JSR4MDEK.js";
6
+ } from "./chunk-Z75ZTXHZ.js";
7
7
  export {
8
8
  Plures,
9
9
  PluresError,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plures",
3
- "version": "1.15.0",
3
+ "version": "1.16.0",
4
4
  "description": "Human judgment as an API for AI agents. Send a decision to ID verified people and get their consensus back.",
5
5
  "keywords": [
6
6
  "human-in-the-loop",