plures 1.13.0 → 1.15.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/dist/{chunk-GIOZT6FB.js → chunk-JSR4MDEK.js} +1 -1
- package/dist/cli.cjs +17 -8
- package/dist/cli.js +17 -8
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
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.
|
|
33
|
+
var VERSION = "1.15.0";
|
|
34
34
|
var PluresError = class extends Error {
|
|
35
35
|
constructor(message, status, type) {
|
|
36
36
|
super(message);
|
|
@@ -327,7 +327,9 @@ function drawMap(m, url) {
|
|
|
327
327
|
const chip = (id) => {
|
|
328
328
|
const n = nodes.get(id), c2 = cps.get(id);
|
|
329
329
|
const label = cut(n.label, 34);
|
|
330
|
-
const
|
|
330
|
+
const rate = c2?.draft?.sample;
|
|
331
|
+
const often = rate ? `, 1 in ${Math.round(1 / rate)}` : "";
|
|
332
|
+
const tag = !c2 ? "" : c2.status === "added" ? ` ${C.cyan(`\u2713 checked${often}`)}` : ` ${C.violet(`\u25CC check suggested${often}`)}`;
|
|
331
333
|
if (n.kind === "action") {
|
|
332
334
|
if (c2?.status === "added") return `${C.cyan(ICON.action)} ${C.text(label)}${tag}`;
|
|
333
335
|
const risky = n.risk === "high" || n.risk === "medium";
|
|
@@ -379,6 +381,9 @@ function drawMap(m, url) {
|
|
|
379
381
|
const on = actions.filter((a) => cps.get(a.id)?.status === "added").length;
|
|
380
382
|
const sugg = m.checkpoints.filter((c2) => c2.status === "suggested").length;
|
|
381
383
|
out.write(` ${LANES.map((c2) => c2("\u2501")).join("")} ${C.bold(C.text(sugg ? `Plures found ${sugg} ${sugg === 1 ? "place" : "places"} a person should check.` : "Your map is ready."))}
|
|
384
|
+
`);
|
|
385
|
+
const scored = m.engine?.version;
|
|
386
|
+
if (scored) out.write(` ${C.dim(`Scored by the Plures oversight engine ${scored}: how risky each action is, and how often people check it.`)}
|
|
382
387
|
`);
|
|
383
388
|
out.write(` ${C.mute(`${on} of ${actions.length} ${actions.length === 1 ? "action" : "actions"} with consequences ${on === 1 ? "has" : "have"} a human check.`)}
|
|
384
389
|
|
|
@@ -499,14 +504,15 @@ With plures-mcp connected, just ask: ${cyan("Map this app for Plures")}`);
|
|
|
499
504
|
}
|
|
500
505
|
const pageUrl = `${base}/dashboard/apps/${encodeURIComponent(app)}/map`;
|
|
501
506
|
if (fancy) {
|
|
502
|
-
banner(app, "
|
|
507
|
+
banner(app, "Claude Code reads this repo on your machine for the Plures oversight engine. Only file names and the map go to Plures.");
|
|
503
508
|
if (key && !noOpen && await openBrowser(pageUrl)) console.log(` ${dim("Watch it live in your browser:")} ${cyan(pageUrl)}
|
|
504
509
|
`);
|
|
505
510
|
} else console.log(`Reading this repo ${process.env.CI ? "on this runner" : "on your machine"} with Claude Code. ${dim("Only the map is sent to Plures.")}
|
|
506
511
|
`);
|
|
507
512
|
const prompt = `${guide}
|
|
508
513
|
|
|
509
|
-
Write the map to ${FILE} in the current directory now. Read the code; don't run it or change anything else.`;
|
|
514
|
+
Write the map to ${FILE} in the current directory now, as JSON, with the Write tool. Read the code; don't run it or change anything else. Don't write a script to generate the map: you can't run scripts or other commands here, so write the JSON itself.`;
|
|
515
|
+
const nudge = `${FILE} doesn't exist yet. Write it now with the Write tool: the complete map as JSON, directly. You can't run scripts or commands here, so don't write one. Use what you've already read.`;
|
|
510
516
|
const live = key ? client() : null;
|
|
511
517
|
const session = (0, import_node_crypto.randomBytes)(12).toString("base64url");
|
|
512
518
|
const source = process.env.GITHUB_ACTIONS ? "github" : "cli";
|
|
@@ -532,8 +538,8 @@ Write the map to ${FILE} in the current directory now. Read the code; don't run
|
|
|
532
538
|
let result = "";
|
|
533
539
|
const ticker = fancy ? liveLine() : null;
|
|
534
540
|
ticker?.start();
|
|
535
|
-
const
|
|
536
|
-
const p = (0, import_node_child_process.spawn)("claude", [
|
|
541
|
+
const runClaude = (args) => new Promise((resolve) => {
|
|
542
|
+
const p = (0, import_node_child_process.spawn)("claude", [...args, "--output-format", "stream-json", "--verbose", "--allowedTools", "Read,Grep,Glob,Write,Bash(git rev-parse:*),Bash(git remote:*)"], { stdio: ["ignore", "pipe", "inherit"], env: childEnv });
|
|
537
543
|
let buf = "";
|
|
538
544
|
p.stdout.on("data", (chunk) => {
|
|
539
545
|
buf += chunk.toString();
|
|
@@ -569,18 +575,21 @@ Write the map to ${FILE} in the current directory now. Read the code; don't run
|
|
|
569
575
|
p.on("close", (n) => resolve(n ?? 1));
|
|
570
576
|
p.on("error", () => resolve(1));
|
|
571
577
|
});
|
|
578
|
+
const wrote = () => (0, import_node_fs.existsSync)(FILE) && (0, import_node_fs.statSync)(FILE).mtimeMs !== before;
|
|
579
|
+
let code = await runClaude(["-p", prompt]);
|
|
580
|
+
if (!wrote()) code = await runClaude(["-p", nudge, "--continue"]);
|
|
572
581
|
clearInterval(tick);
|
|
573
582
|
ticker?.stop();
|
|
574
583
|
if (result && !fancy) console.log(`
|
|
575
584
|
${result.trim()}
|
|
576
585
|
`);
|
|
577
586
|
if (fancy) console.log(` ${cyan("\u2713")} ${reads} ${reads === 1 ? "file" : "files"} read. ${dim("Sending the map to Plures. No source code is sent.")}`);
|
|
578
|
-
const ok = code === 0 && (
|
|
587
|
+
const ok = code === 0 && wrote();
|
|
579
588
|
if (!ok) {
|
|
580
589
|
phase = "failed";
|
|
581
590
|
await flush();
|
|
582
591
|
} else await flush();
|
|
583
|
-
if (
|
|
592
|
+
if (!ok) die(`Claude Code didn't write ${FILE}${process.env.CI ? ". This run costs nothing." : `. Ask it directly, then run npx plures map upload.`}`);
|
|
584
593
|
await upload(FILE);
|
|
585
594
|
}
|
|
586
595
|
async function workflow() {
|
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
Plures,
|
|
4
4
|
PluresError,
|
|
5
5
|
VERSION
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-JSR4MDEK.js";
|
|
7
7
|
|
|
8
8
|
// src/cli.ts
|
|
9
9
|
import { spawnSync, spawn } from "child_process";
|
|
@@ -109,7 +109,9 @@ function drawMap(m, url) {
|
|
|
109
109
|
const chip = (id) => {
|
|
110
110
|
const n = nodes.get(id), c2 = cps.get(id);
|
|
111
111
|
const label = cut(n.label, 34);
|
|
112
|
-
const
|
|
112
|
+
const rate = c2?.draft?.sample;
|
|
113
|
+
const often = rate ? `, 1 in ${Math.round(1 / rate)}` : "";
|
|
114
|
+
const tag = !c2 ? "" : c2.status === "added" ? ` ${C.cyan(`\u2713 checked${often}`)}` : ` ${C.violet(`\u25CC check suggested${often}`)}`;
|
|
113
115
|
if (n.kind === "action") {
|
|
114
116
|
if (c2?.status === "added") return `${C.cyan(ICON.action)} ${C.text(label)}${tag}`;
|
|
115
117
|
const risky = n.risk === "high" || n.risk === "medium";
|
|
@@ -161,6 +163,9 @@ function drawMap(m, url) {
|
|
|
161
163
|
const on = actions.filter((a) => cps.get(a.id)?.status === "added").length;
|
|
162
164
|
const sugg = m.checkpoints.filter((c2) => c2.status === "suggested").length;
|
|
163
165
|
out.write(` ${LANES.map((c2) => c2("\u2501")).join("")} ${C.bold(C.text(sugg ? `Plures found ${sugg} ${sugg === 1 ? "place" : "places"} a person should check.` : "Your map is ready."))}
|
|
166
|
+
`);
|
|
167
|
+
const scored = m.engine?.version;
|
|
168
|
+
if (scored) out.write(` ${C.dim(`Scored by the Plures oversight engine ${scored}: how risky each action is, and how often people check it.`)}
|
|
164
169
|
`);
|
|
165
170
|
out.write(` ${C.mute(`${on} of ${actions.length} ${actions.length === 1 ? "action" : "actions"} with consequences ${on === 1 ? "has" : "have"} a human check.`)}
|
|
166
171
|
|
|
@@ -281,14 +286,15 @@ With plures-mcp connected, just ask: ${cyan("Map this app for Plures")}`);
|
|
|
281
286
|
}
|
|
282
287
|
const pageUrl = `${base}/dashboard/apps/${encodeURIComponent(app)}/map`;
|
|
283
288
|
if (fancy) {
|
|
284
|
-
banner(app, "
|
|
289
|
+
banner(app, "Claude Code reads this repo on your machine for the Plures oversight engine. Only file names and the map go to Plures.");
|
|
285
290
|
if (key && !noOpen && await openBrowser(pageUrl)) console.log(` ${dim("Watch it live in your browser:")} ${cyan(pageUrl)}
|
|
286
291
|
`);
|
|
287
292
|
} else console.log(`Reading this repo ${process.env.CI ? "on this runner" : "on your machine"} with Claude Code. ${dim("Only the map is sent to Plures.")}
|
|
288
293
|
`);
|
|
289
294
|
const prompt = `${guide}
|
|
290
295
|
|
|
291
|
-
Write the map to ${FILE} in the current directory now. Read the code; don't run it or change anything else.`;
|
|
296
|
+
Write the map to ${FILE} in the current directory now, as JSON, with the Write tool. Read the code; don't run it or change anything else. Don't write a script to generate the map: you can't run scripts or other commands here, so write the JSON itself.`;
|
|
297
|
+
const nudge = `${FILE} doesn't exist yet. Write it now with the Write tool: the complete map as JSON, directly. You can't run scripts or commands here, so don't write one. Use what you've already read.`;
|
|
292
298
|
const live = key ? client() : null;
|
|
293
299
|
const session = randomBytes(12).toString("base64url");
|
|
294
300
|
const source = process.env.GITHUB_ACTIONS ? "github" : "cli";
|
|
@@ -314,8 +320,8 @@ Write the map to ${FILE} in the current directory now. Read the code; don't run
|
|
|
314
320
|
let result = "";
|
|
315
321
|
const ticker = fancy ? liveLine() : null;
|
|
316
322
|
ticker?.start();
|
|
317
|
-
const
|
|
318
|
-
const p = spawn("claude", [
|
|
323
|
+
const runClaude = (args) => new Promise((resolve) => {
|
|
324
|
+
const p = spawn("claude", [...args, "--output-format", "stream-json", "--verbose", "--allowedTools", "Read,Grep,Glob,Write,Bash(git rev-parse:*),Bash(git remote:*)"], { stdio: ["ignore", "pipe", "inherit"], env: childEnv });
|
|
319
325
|
let buf = "";
|
|
320
326
|
p.stdout.on("data", (chunk) => {
|
|
321
327
|
buf += chunk.toString();
|
|
@@ -351,18 +357,21 @@ Write the map to ${FILE} in the current directory now. Read the code; don't run
|
|
|
351
357
|
p.on("close", (n) => resolve(n ?? 1));
|
|
352
358
|
p.on("error", () => resolve(1));
|
|
353
359
|
});
|
|
360
|
+
const wrote = () => existsSync(FILE) && statSync(FILE).mtimeMs !== before;
|
|
361
|
+
let code = await runClaude(["-p", prompt]);
|
|
362
|
+
if (!wrote()) code = await runClaude(["-p", nudge, "--continue"]);
|
|
354
363
|
clearInterval(tick);
|
|
355
364
|
ticker?.stop();
|
|
356
365
|
if (result && !fancy) console.log(`
|
|
357
366
|
${result.trim()}
|
|
358
367
|
`);
|
|
359
368
|
if (fancy) console.log(` ${cyan("\u2713")} ${reads} ${reads === 1 ? "file" : "files"} read. ${dim("Sending the map to Plures. No source code is sent.")}`);
|
|
360
|
-
const ok = code === 0 &&
|
|
369
|
+
const ok = code === 0 && wrote();
|
|
361
370
|
if (!ok) {
|
|
362
371
|
phase = "failed";
|
|
363
372
|
await flush();
|
|
364
373
|
} else await flush();
|
|
365
|
-
if (
|
|
374
|
+
if (!ok) die(`Claude Code didn't write ${FILE}${process.env.CI ? ". This run costs nothing." : `. Ask it directly, then run npx plures map upload.`}`);
|
|
366
375
|
await upload(FILE);
|
|
367
376
|
}
|
|
368
377
|
async function workflow() {
|
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.
|
|
29
|
+
var VERSION = "1.15.0";
|
|
30
30
|
var PluresError = class extends Error {
|
|
31
31
|
constructor(message, status, type) {
|
|
32
32
|
super(message);
|
package/dist/index.d.cts
CHANGED
|
@@ -4,7 +4,7 @@ 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 TaskStatus = "pending" | "completed" | "expired" | "canceled";
|
|
7
|
+
type TaskStatus = "pending" | "completed" | "expired" | "canceled" | "skipped";
|
|
8
8
|
type Result = {
|
|
9
9
|
answer: string | null;
|
|
10
10
|
label: string | null;
|
|
@@ -57,6 +57,8 @@ type Task = {
|
|
|
57
57
|
app?: string | null;
|
|
58
58
|
mode: "live" | "test";
|
|
59
59
|
status: TaskStatus;
|
|
60
|
+
/** false when a sampled check didn't pick this task: it wasn't sent to people, and result.answer is the first option. */
|
|
61
|
+
sampled?: boolean;
|
|
60
62
|
question: string;
|
|
61
63
|
context: string | null;
|
|
62
64
|
image_url: string | null;
|
|
@@ -350,7 +352,7 @@ type WebhookEvent = {
|
|
|
350
352
|
created_at: string;
|
|
351
353
|
data: Task;
|
|
352
354
|
};
|
|
353
|
-
declare const VERSION = "1.
|
|
355
|
+
declare const VERSION = "1.15.0";
|
|
354
356
|
type GitHubLink = {
|
|
355
357
|
object: "github_link";
|
|
356
358
|
app: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ 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 TaskStatus = "pending" | "completed" | "expired" | "canceled";
|
|
7
|
+
type TaskStatus = "pending" | "completed" | "expired" | "canceled" | "skipped";
|
|
8
8
|
type Result = {
|
|
9
9
|
answer: string | null;
|
|
10
10
|
label: string | null;
|
|
@@ -57,6 +57,8 @@ type Task = {
|
|
|
57
57
|
app?: string | null;
|
|
58
58
|
mode: "live" | "test";
|
|
59
59
|
status: TaskStatus;
|
|
60
|
+
/** false when a sampled check didn't pick this task: it wasn't sent to people, and result.answer is the first option. */
|
|
61
|
+
sampled?: boolean;
|
|
60
62
|
question: string;
|
|
61
63
|
context: string | null;
|
|
62
64
|
image_url: string | null;
|
|
@@ -350,7 +352,7 @@ type WebhookEvent = {
|
|
|
350
352
|
created_at: string;
|
|
351
353
|
data: Task;
|
|
352
354
|
};
|
|
353
|
-
declare const VERSION = "1.
|
|
355
|
+
declare const VERSION = "1.15.0";
|
|
354
356
|
type GitHubLink = {
|
|
355
357
|
object: "github_link";
|
|
356
358
|
app: string;
|
package/dist/index.js
CHANGED