synartesis 0.2.4 → 0.3.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/CHANGELOG.md +43 -0
- package/README.md +44 -1
- package/SECURITY.md +70 -0
- package/dist/{chunk-GD6PRYZZ.js → chunk-FIIKQECN.js} +74 -3
- package/dist/chunk-FIIKQECN.js.map +1 -0
- package/dist/cli.js +108 -8
- package/dist/cli.js.map +1 -1
- package/dist/proxy.js +1 -1
- package/package.json +2 -1
- package/dist/chunk-GD6PRYZZ.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
toPayload,
|
|
25
25
|
verifyAgainstServers,
|
|
26
26
|
wasRefused
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-FIIKQECN.js";
|
|
28
28
|
import {
|
|
29
29
|
DriftConflict,
|
|
30
30
|
ManifestError,
|
|
@@ -35,8 +35,9 @@ import {
|
|
|
35
35
|
} from "./chunk-K3QIPVBY.js";
|
|
36
36
|
|
|
37
37
|
// src/cli.ts
|
|
38
|
-
import { existsSync as existsSync4, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
39
|
-
import { dirname, resolve } from "path";
|
|
38
|
+
import { existsSync as existsSync4, mkdirSync, readFileSync as readFileSync2, statSync, writeFileSync } from "fs";
|
|
39
|
+
import { dirname, join, resolve } from "path";
|
|
40
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
40
41
|
|
|
41
42
|
// src/init/draft.ts
|
|
42
43
|
import { z } from "zod";
|
|
@@ -1255,6 +1256,7 @@ var COMMANDS = `
|
|
|
1255
1256
|
synartesis show <runId> [--journal <path>]
|
|
1256
1257
|
synartesis gates [--journal <path>]
|
|
1257
1258
|
synartesis close [runId] [--journal <path>]
|
|
1259
|
+
synartesis prune [--older-than <days>] [--dry-run] [--journal <path>]
|
|
1258
1260
|
synartesis proxy --manifest <path> [--journal <path>] what your agent runs
|
|
1259
1261
|
[--http <port> --token <secret>] for a client that
|
|
1260
1262
|
cannot start one
|
|
@@ -1267,6 +1269,10 @@ var COMMANDS = `
|
|
|
1267
1269
|
close ends a run left active by a proxy that was killed; nothing guesses at
|
|
1268
1270
|
that, since several proxies can share one journal.
|
|
1269
1271
|
|
|
1272
|
+
prune reclaims space. Putting a file back means keeping what was in it, so a
|
|
1273
|
+
journal grows at several times what an agent writes and never shrinks by
|
|
1274
|
+
itself. Nothing still active or still waiting on a person is ever pruned.
|
|
1275
|
+
|
|
1270
1276
|
Ids may be shortened to any unambiguous prefix. show and undo default to the
|
|
1271
1277
|
most recent run; approve and deny default to the only request waiting. init
|
|
1272
1278
|
adds to an existing manifest rather than replacing it.
|
|
@@ -1284,6 +1290,8 @@ and a and d answer it without a second terminal or an id to copy.
|
|
|
1284
1290
|
--dry-run read current state and print the plan without changing anything
|
|
1285
1291
|
--replan rebuild each undo from the current manifest, for a run recorded
|
|
1286
1292
|
under a policy that turned out to be wrong
|
|
1293
|
+
--older-than days of history prune keeps; defaults to 30
|
|
1294
|
+
--version print the version and exit
|
|
1287
1295
|
|
|
1288
1296
|
Neither path usually needs giving. A policy that belongs to a project sits in
|
|
1289
1297
|
it and is found from any directory inside it, the way a version control tool
|
|
@@ -1306,7 +1314,7 @@ function flag(argv, name) {
|
|
|
1306
1314
|
return value;
|
|
1307
1315
|
}
|
|
1308
1316
|
function positional(argv) {
|
|
1309
|
-
const skip = /* @__PURE__ */ new Set(["--manifest", "--journal", "--to", "--by", "--reason", "--gate-timeout"]);
|
|
1317
|
+
const skip = /* @__PURE__ */ new Set(["--manifest", "--journal", "--to", "--by", "--reason", "--gate-timeout", "--older-than"]);
|
|
1310
1318
|
const values = [];
|
|
1311
1319
|
const end = argv.indexOf("--");
|
|
1312
1320
|
const ours = end === -1 ? argv : argv.slice(0, end);
|
|
@@ -1386,7 +1394,7 @@ async function runInit(argv) {
|
|
|
1386
1394
|
...present ? { existing: readFileSync2(path, "utf8") } : {}
|
|
1387
1395
|
});
|
|
1388
1396
|
parseManifest(draft.yaml, path);
|
|
1389
|
-
mkdirSync(dirname(resolve(path)), { recursive: true });
|
|
1397
|
+
mkdirSync(dirname(resolve(path)), { recursive: true, mode: 448 });
|
|
1390
1398
|
writeFileSync(path, draft.yaml);
|
|
1391
1399
|
out("");
|
|
1392
1400
|
out(` ${style.label(present ? "extended" : "wrote")} ${style.strong(path)}`);
|
|
@@ -1450,7 +1458,7 @@ function out(line2) {
|
|
|
1450
1458
|
process.stdout.write(`${line2}
|
|
1451
1459
|
`);
|
|
1452
1460
|
}
|
|
1453
|
-
function runList(journal, asJson) {
|
|
1461
|
+
function runList(journal, asJson, journalPath) {
|
|
1454
1462
|
const runs = [...journal.listRuns()].reverse();
|
|
1455
1463
|
if (asJson) {
|
|
1456
1464
|
out(JSON.stringify(runs.map((run) => ({ ...run, actions: journal.getActions(run.id).length }))));
|
|
@@ -1483,6 +1491,10 @@ function runList(journal, asJson) {
|
|
|
1483
1491
|
);
|
|
1484
1492
|
}
|
|
1485
1493
|
out("");
|
|
1494
|
+
if (bytesOf(journalPath) > PRUNE_NAG_BYTES) {
|
|
1495
|
+
out(` ${style.quiet(`This journal is ${sizeOf(journalPath)}; synartesis prune reclaims what is old enough to lose.`)}`);
|
|
1496
|
+
out("");
|
|
1497
|
+
}
|
|
1486
1498
|
return 0;
|
|
1487
1499
|
}
|
|
1488
1500
|
function runShow(argv, journal, asJson) {
|
|
@@ -1589,6 +1601,74 @@ function summarise2(actions) {
|
|
|
1589
1601
|
return `${String(actions.length)} actions: ${parts.join(", ")} | ${String(undoable)} with a recorded undo`;
|
|
1590
1602
|
}
|
|
1591
1603
|
var journalArg = "";
|
|
1604
|
+
var PRUNE_NAG_BYTES = 100 * 1024 * 1024;
|
|
1605
|
+
function bytesOf(path) {
|
|
1606
|
+
try {
|
|
1607
|
+
return statSync(path).size;
|
|
1608
|
+
} catch {
|
|
1609
|
+
return 0;
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
function sizeOf(path) {
|
|
1613
|
+
try {
|
|
1614
|
+
const bytes = bytesOf(path);
|
|
1615
|
+
if (bytes < 1024 * 1024) {
|
|
1616
|
+
return `${String(Math.max(1, Math.round(bytes / 1024)))} kB`;
|
|
1617
|
+
}
|
|
1618
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
1619
|
+
} catch {
|
|
1620
|
+
return "unknown";
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
var PRUNE_DEFAULT_DAYS = 30;
|
|
1624
|
+
function runPrune(argv, journal, journalPath) {
|
|
1625
|
+
const given = flag(argv, "--older-than");
|
|
1626
|
+
const days = given === void 0 ? PRUNE_DEFAULT_DAYS : Number(given);
|
|
1627
|
+
if (!Number.isFinite(days) || days < 0) {
|
|
1628
|
+
throw new UsageError(`--older-than takes a number of days, not ${given ?? ""}`);
|
|
1629
|
+
}
|
|
1630
|
+
const before = new Date(Date.now() - days * 24 * 60 * 60 * 1e3).toISOString();
|
|
1631
|
+
const stale = journal.prunableRuns(before);
|
|
1632
|
+
const planned = argv.includes("--dry-run");
|
|
1633
|
+
const sizeBefore = sizeOf(journalPath);
|
|
1634
|
+
out("");
|
|
1635
|
+
out(` ${style.label(planned ? "would prune" : "prune")} ${style.quiet(`older than ${String(days)} days`)}`);
|
|
1636
|
+
out(` ${rule(54)}`);
|
|
1637
|
+
out("");
|
|
1638
|
+
out(` ${style.quiet(journalPath)}`);
|
|
1639
|
+
out("");
|
|
1640
|
+
if (stale.length === 0) {
|
|
1641
|
+
out(` ${style.quiet(`Nothing is older than ${String(days)} days and finished with.`)}`);
|
|
1642
|
+
out("");
|
|
1643
|
+
out(` ${style.quiet(`The journal is ${sizeBefore}. Runs still active, and any`)}`);
|
|
1644
|
+
out(` ${style.quiet("holding a call that is waiting or in flight, are never pruned.")}`);
|
|
1645
|
+
out("");
|
|
1646
|
+
return 0;
|
|
1647
|
+
}
|
|
1648
|
+
let actions = 0;
|
|
1649
|
+
for (const run of stale) {
|
|
1650
|
+
actions += run.actions;
|
|
1651
|
+
out(
|
|
1652
|
+
` ${style.strong((run.label ?? "an agent").padEnd(24))} ${style.quiet(run.at.slice(0, 19).replace("T", " "))} ${style.quiet(run.status.padEnd(11))} ${style.quiet(`${String(run.actions)} actions`)}`
|
|
1653
|
+
);
|
|
1654
|
+
}
|
|
1655
|
+
out("");
|
|
1656
|
+
if (planned) {
|
|
1657
|
+
out(
|
|
1658
|
+
` ${style.accent(`${String(stale.length)} runs`)} ${style.quiet(`and ${String(actions)} actions would go. Nothing was changed.`)}`
|
|
1659
|
+
);
|
|
1660
|
+
out("");
|
|
1661
|
+
return 0;
|
|
1662
|
+
}
|
|
1663
|
+
const removed = journal.deleteRuns(stale.map((run) => run.id));
|
|
1664
|
+
journal.vacuum();
|
|
1665
|
+
out(
|
|
1666
|
+
` ${style.accent(`${String(removed.runs)} runs`)} ${style.quiet(`and ${String(removed.actions)} actions removed.`)}`
|
|
1667
|
+
);
|
|
1668
|
+
out(` ${style.quiet(`Journal ${sizeBefore} \u2192 ${sizeOf(journalPath)}.`)}`);
|
|
1669
|
+
out("");
|
|
1670
|
+
return 0;
|
|
1671
|
+
}
|
|
1592
1672
|
function runClose(argv, journal) {
|
|
1593
1673
|
const active = journal.listRuns().filter((candidate) => candidate.status === "active");
|
|
1594
1674
|
const run = pick([...active].reverse(), positional(argv)[1], RUN, true);
|
|
@@ -1783,9 +1863,22 @@ var FLAGS = /* @__PURE__ */ new Set([
|
|
|
1783
1863
|
"--replan",
|
|
1784
1864
|
"--reason",
|
|
1785
1865
|
"--force",
|
|
1866
|
+
"--older-than",
|
|
1786
1867
|
"--help",
|
|
1787
|
-
"-h"
|
|
1868
|
+
"-h",
|
|
1869
|
+
"--version",
|
|
1870
|
+
"-V"
|
|
1788
1871
|
]);
|
|
1872
|
+
function version() {
|
|
1873
|
+
try {
|
|
1874
|
+
const root = dirname(fileURLToPath2(import.meta.url));
|
|
1875
|
+
const parsed = JSON.parse(readFileSync2(join(root, "..", "package.json"), "utf8"));
|
|
1876
|
+
const found = typeof parsed === "object" && parsed !== null ? parsed.version : void 0;
|
|
1877
|
+
return typeof found === "string" ? found : "unknown";
|
|
1878
|
+
} catch {
|
|
1879
|
+
return "unknown";
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1789
1882
|
function rejectUnknownFlags(argv) {
|
|
1790
1883
|
for (const token of argv) {
|
|
1791
1884
|
if (token === "--") {
|
|
@@ -1815,6 +1908,11 @@ async function main(argv) {
|
|
|
1815
1908
|
${COMMANDS}`);
|
|
1816
1909
|
return 0;
|
|
1817
1910
|
}
|
|
1911
|
+
if (argv.includes("--version") || argv.includes("-V")) {
|
|
1912
|
+
process.stdout.write(`${version()}
|
|
1913
|
+
`);
|
|
1914
|
+
return 0;
|
|
1915
|
+
}
|
|
1818
1916
|
rejectUnknownFlags(argv);
|
|
1819
1917
|
if (command === void 0) {
|
|
1820
1918
|
const manifestPath = findManifest(flag(argv, "--manifest"));
|
|
@@ -1874,11 +1972,13 @@ ${COMMANDS}`);
|
|
|
1874
1972
|
try {
|
|
1875
1973
|
switch (command) {
|
|
1876
1974
|
case "list":
|
|
1877
|
-
return runList(journal, asJson);
|
|
1975
|
+
return runList(journal, asJson, journalPath);
|
|
1878
1976
|
case "show":
|
|
1879
1977
|
return runShow(argv, journal, asJson);
|
|
1880
1978
|
case "close":
|
|
1881
1979
|
return runClose(argv, journal);
|
|
1980
|
+
case "prune":
|
|
1981
|
+
return runPrune(argv, journal, journalPath);
|
|
1882
1982
|
case "gates":
|
|
1883
1983
|
return runGates(journal, asJson);
|
|
1884
1984
|
case "approve":
|