@gjermundgaraba/upup 0.4.0 → 0.5.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/main.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as reason, t as
|
|
2
|
+
import { n as openFlags, r as reason, t as byName } from "./io-ns6xhFdF.mjs";
|
|
3
3
|
import { findPackageJSON } from "node:module";
|
|
4
4
|
import { NodeRuntime, NodeServices, NodeStdio } from "@effect/platform-node";
|
|
5
5
|
import { Cause, Clock, Config, Context, Data, Deferred, Duration, Effect, Equal, Exit, Fiber, FiberHandle, FiberSet, FileSystem, Layer, Option, Predicate, Queue, Ref, Result, Schedule, Schema, Semaphore, Stream, SubscriptionRef, identity } from "effect";
|
|
@@ -17,8 +17,7 @@ import { homedir, tmpdir } from "node:os";
|
|
|
17
17
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
18
18
|
import lockfile from "proper-lockfile";
|
|
19
19
|
import { BACKGROUND_CONTEXT, withAbortSignal } from "@earendil-works/chord/context";
|
|
20
|
-
import {
|
|
21
|
-
import { GenerationTask, Harness, ToolTask, createRegistry, defineDoc, defineExtension, defineTool, hook, section, watchEvents } from "@earendil-works/pi-durable";
|
|
20
|
+
import { GenerationTask, Harness, LiveDoc, ROOT_CONVERSATION_ID, ToolTask, createRegistry, defineDoc, defineExtension, defineTool, hook, section } from "@earendil-works/pi-durable";
|
|
22
21
|
import { openNodeSqliteStorage } from "@earendil-works/pi-durable/storage/sqlite/node";
|
|
23
22
|
import { ChildProcess, ChildProcessSpawner, CommandLine } from "effect/process";
|
|
24
23
|
import { Worker } from "node:worker_threads";
|
|
@@ -43,7 +42,7 @@ import * as ActionMcp from "@gjermundgaraba/effect-actions/ActionMcp";
|
|
|
43
42
|
import * as Action from "@gjermundgaraba/effect-actions/Action";
|
|
44
43
|
import { setup, types } from "xstate/fsm";
|
|
45
44
|
// package.json
|
|
46
|
-
var version$1 = "0.
|
|
45
|
+
var version$1 = "0.5.0";
|
|
47
46
|
// src/ai/Setup.ts
|
|
48
47
|
const Thinking = Schema.Literals([
|
|
49
48
|
"off",
|
|
@@ -427,12 +426,12 @@ const withTarget = (pkg, target) => ({
|
|
|
427
426
|
target
|
|
428
427
|
});
|
|
429
428
|
const isUnaudited = Schema.is(UnauditedEcosystem);
|
|
430
|
-
const isApp = Schema.is(AppEcosystem);
|
|
429
|
+
const isApp$1 = Schema.is(AppEcosystem);
|
|
431
430
|
const isRuntime = Schema.is(RuntimeEcosystem);
|
|
432
431
|
const isUnauditedUpdate = (pkg) => isUnaudited(pkg.ecosystem);
|
|
433
|
-
const isAppUpdate = (pkg) => isApp(pkg.ecosystem);
|
|
432
|
+
const isAppUpdate = (pkg) => isApp$1(pkg.ecosystem);
|
|
434
433
|
const unauditedKind = (pkg) => {
|
|
435
|
-
if (isApp(pkg.ecosystem)) return "app";
|
|
434
|
+
if (isApp$1(pkg.ecosystem)) return "app";
|
|
436
435
|
if (isRuntime(pkg.ecosystem)) return "runtime";
|
|
437
436
|
if (isUnaudited(pkg.ecosystem)) return "os";
|
|
438
437
|
};
|
|
@@ -753,15 +752,15 @@ const Severity = Schema.Literals([
|
|
|
753
752
|
const Finding = Schema.Struct({
|
|
754
753
|
severity: Severity,
|
|
755
754
|
title: Schema.String,
|
|
756
|
-
detail: Schema.String,
|
|
757
|
-
paths: Schema.Array(Schema.String)
|
|
755
|
+
detail: Schema.String.annotate({ description: "Markdown: the evidence and why it matters." }),
|
|
756
|
+
paths: Schema.Array(Schema.String).annotate({ description: "Workspace paths, with line ranges where useful." })
|
|
758
757
|
});
|
|
759
758
|
const Report = Schema.Struct({
|
|
760
759
|
verdict: Verdict,
|
|
761
|
-
rationale: Schema.String,
|
|
762
|
-
summary: Schema.String,
|
|
760
|
+
rationale: Schema.String.annotate({ description: "One concrete sentence justifying the verdict." }),
|
|
761
|
+
summary: Schema.String.annotate({ description: "Markdown: what the update changes that bears on the mandate, what you flagged and why you cleared or kept it." }),
|
|
763
762
|
findings: Schema.Array(Finding),
|
|
764
|
-
unverified: Schema.Array(Schema.String)
|
|
763
|
+
unverified: Schema.Array(Schema.String).annotate({ description: "Each thing you could not verify." })
|
|
765
764
|
});
|
|
766
765
|
Schema.Struct({
|
|
767
766
|
mode: Mode,
|
|
@@ -844,21 +843,23 @@ const descriptions = {
|
|
|
844
843
|
grep: "Find a JavaScript regular expression in UTF-8 regular files below a path. Each line is matched whole. Lines over 1 KiB show a bounded window around each match with its file byte offset; a file stops at a line over 16 MiB.",
|
|
845
844
|
list: "List workspace entries below a directory to a bounded depth."
|
|
846
845
|
};
|
|
847
|
-
const
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
},
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
}
|
|
846
|
+
const count$1 = (maximum) => Schema.Number.pipe(Schema.check(Schema.isInt(), Schema.isBetween({
|
|
847
|
+
minimum: 1,
|
|
848
|
+
maximum
|
|
849
|
+
})));
|
|
850
|
+
const ReadArgs = Schema.Struct({
|
|
851
|
+
path: Schema.String.annotate({ description: "Workspace-relative file path." }),
|
|
852
|
+
offset: Schema.Number.pipe(Schema.check(Schema.isInt(), Schema.isGreaterThanOrEqualTo(0))).annotate({ description: "Zero-based byte offset; must be >= 0." }),
|
|
853
|
+
limit: count$1(limits$1.readBytes).annotate({ description: `Maximum bytes to return; must be between 1 and ${limits$1.readBytes} inclusive.` })
|
|
854
|
+
});
|
|
855
|
+
const GrepArgs = Schema.Struct({
|
|
856
|
+
path: Schema.String.annotate({ description: "Workspace-relative file or directory path." }),
|
|
857
|
+
pattern: Schema.String.annotate({ description: "JavaScript regular expression." })
|
|
858
|
+
});
|
|
859
|
+
const ListArgs = Schema.Struct({
|
|
860
|
+
path: Schema.String.annotate({ description: "Workspace-relative directory path; use . for the root." }),
|
|
861
|
+
depth: count$1(limits$1.listDepth).annotate({ description: `Maximum directory depth; must be between 1 and ${limits$1.listDepth} inclusive.` })
|
|
862
|
+
});
|
|
862
863
|
var ToolError = class extends Error {
|
|
863
864
|
constructor(message) {
|
|
864
865
|
super(message);
|
|
@@ -915,10 +916,6 @@ const locate$4 = async (workspace, name, context) => {
|
|
|
915
916
|
return fail$1(`${context}: ${reason(error)}`);
|
|
916
917
|
}
|
|
917
918
|
};
|
|
918
|
-
const byName = (left, right) => {
|
|
919
|
-
if (left.name < right.name) return -1;
|
|
920
|
-
return left.name > right.name ? 1 : 0;
|
|
921
|
-
};
|
|
922
919
|
const suffixOf = (entry) => {
|
|
923
920
|
if (entry.isDirectory()) return "/";
|
|
924
921
|
return entry.isSymbolicLink() ? "@" : "";
|
|
@@ -1344,17 +1341,11 @@ const runDiff = (cwd, args, from, to, input) => Effect.callback((resume) => {
|
|
|
1344
1341
|
});
|
|
1345
1342
|
return Effect.sync(() => child.kill());
|
|
1346
1343
|
});
|
|
1347
|
-
const regularFiles =
|
|
1348
|
-
const
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
const info = await lstat(path.join(root, file));
|
|
1353
|
-
if (info.isDirectory()) found.push(...await regularFiles(root, file));
|
|
1354
|
-
else if (info.isFile()) found.push(file);
|
|
1355
|
-
}
|
|
1356
|
-
return found;
|
|
1357
|
-
};
|
|
1344
|
+
const regularFiles = (root, relative = "") => Effect.promise(async () => await readdir(path.join(root, relative), { withFileTypes: true }).catch(() => [])).pipe(Effect.flatMap((entries) => Effect.forEach(entries.toSorted(byName), (entry) => {
|
|
1345
|
+
const file = relative === "" ? entry.name : `${relative}/${entry.name}`;
|
|
1346
|
+
if (entry.isDirectory()) return regularFiles(root, file);
|
|
1347
|
+
return Effect.succeed(entry.isFile() ? [file] : []);
|
|
1348
|
+
}, { concurrency: "unbounded" })), Effect.map((found) => found.flat()));
|
|
1358
1349
|
const failure$1 = (from, to) => (cause) => new DiffFailed({
|
|
1359
1350
|
from,
|
|
1360
1351
|
to,
|
|
@@ -1372,15 +1363,25 @@ const plain$1 = (pair) => ({
|
|
|
1372
1363
|
paired: false,
|
|
1373
1364
|
rewritten: false
|
|
1374
1365
|
});
|
|
1375
|
-
const planTree =
|
|
1376
|
-
const
|
|
1366
|
+
const planTree = (workspace, from, to) => Effect.gen(function* () {
|
|
1367
|
+
const attempt = (run) => Effect.tryPromise({
|
|
1368
|
+
try: run,
|
|
1369
|
+
catch: failure$1(from, to)
|
|
1370
|
+
});
|
|
1371
|
+
const [before, after] = yield* Effect.all([regularFiles(path.join(workspace, from)), regularFiles(path.join(workspace, to))], { concurrency: "unbounded" });
|
|
1377
1372
|
const beforeSet = new Set(before);
|
|
1378
1373
|
const afterSet = new Set(after);
|
|
1379
1374
|
const fromOnly = before.filter((file) => !afterSet.has(file));
|
|
1380
1375
|
const toOnly = after.filter((file) => !beforeSet.has(file));
|
|
1381
|
-
const only =
|
|
1382
|
-
|
|
1383
|
-
|
|
1376
|
+
const only = new Map(yield* Effect.forEach([...fromOnly.map((file) => ({
|
|
1377
|
+
side: "from",
|
|
1378
|
+
root: from,
|
|
1379
|
+
file
|
|
1380
|
+
})), ...toOnly.map((file) => ({
|
|
1381
|
+
side: "to",
|
|
1382
|
+
root: to,
|
|
1383
|
+
file
|
|
1384
|
+
}))], ({ side, root, file }) => attempt(async () => [`${side}\0${file}`, await readFile(path.join(workspace, root, file))]), { concurrency: 8 }));
|
|
1384
1385
|
const pairs = matchRenames(fromOnly, toOnly, (side, file) => only.get(`${side}\0${file}`) ?? Buffer.alloc(0));
|
|
1385
1386
|
const renames = renamesOf(pairs);
|
|
1386
1387
|
const pairedFrom = new Set(pairs.map((pair) => pair.from));
|
|
@@ -1391,32 +1392,36 @@ const planTree = async (workspace, from, to) => {
|
|
|
1391
1392
|
from: file,
|
|
1392
1393
|
to: file
|
|
1393
1394
|
}))];
|
|
1394
|
-
|
|
1395
|
+
const classify = async (pair) => {
|
|
1395
1396
|
const oldPath = path.join(workspace, from, pair.from);
|
|
1396
1397
|
const nextPath = path.join(workspace, to, pair.to);
|
|
1397
1398
|
const paired = pair.from !== pair.to;
|
|
1398
|
-
if (!paired && renames.size === 0) {
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
}
|
|
1402
|
-
const old = only.get(`from\0${pair.from}`) ??
|
|
1403
|
-
|
|
1404
|
-
if (!paired && old.equals(next)) continue;
|
|
1399
|
+
if (!paired && renames.size === 0) return await identical(oldPath, nextPath) ? void 0 : {
|
|
1400
|
+
same: false,
|
|
1401
|
+
change: plain$1(pair)
|
|
1402
|
+
};
|
|
1403
|
+
const [old, next] = await Promise.all([only.get(`from\0${pair.from}`) ?? readFile(oldPath), only.get(`to\0${pair.to}`) ?? readFile(nextPath)]);
|
|
1404
|
+
if (!paired && old.equals(next)) return;
|
|
1405
1405
|
const text = isText(old) ? old.toString("latin1") : void 0;
|
|
1406
1406
|
const rewrittenText = text === void 0 ? void 0 : rewrite(text, renames);
|
|
1407
1407
|
const rewritten = rewrittenText !== void 0 && rewrittenText !== text;
|
|
1408
|
-
if (!paired && !rewritten) {
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
}
|
|
1408
|
+
if (!paired && !rewritten) return {
|
|
1409
|
+
same: false,
|
|
1410
|
+
change: plain$1(pair)
|
|
1411
|
+
};
|
|
1412
1412
|
const expected = rewrittenText === void 0 ? old : Buffer.from(rewrittenText, "latin1");
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1413
|
+
return {
|
|
1414
|
+
same: expected.equals(next),
|
|
1415
|
+
change: {
|
|
1416
|
+
...pair,
|
|
1417
|
+
expected,
|
|
1418
|
+
paired,
|
|
1419
|
+
rewritten
|
|
1420
|
+
}
|
|
1421
|
+
};
|
|
1422
|
+
};
|
|
1423
|
+
const planned = yield* Effect.forEach(candidates, (pair) => attempt(async () => await classify(pair)), { concurrency: 8 });
|
|
1424
|
+
for (const entry of planned) if (entry !== void 0) (entry.same ? same : changes).push(entry.change);
|
|
1420
1425
|
for (const file of fromOnly) if (!pairedFrom.has(file)) changes.push({
|
|
1421
1426
|
...plain$1({
|
|
1422
1427
|
from: file,
|
|
@@ -1438,7 +1443,7 @@ const planTree = async (workspace, from, to) => {
|
|
|
1438
1443
|
}),
|
|
1439
1444
|
same
|
|
1440
1445
|
};
|
|
1441
|
-
};
|
|
1446
|
+
});
|
|
1442
1447
|
const mebibytes = (bytes) => `${Math.round(bytes / 1024 / 1024)} MiB`;
|
|
1443
1448
|
const shownOmissions = 2e3;
|
|
1444
1449
|
const changeDiff = (workspace, from, to, change) => {
|
|
@@ -1470,10 +1475,7 @@ const partial = (what, omitted) => omitted === "" ? "" : `The ${what} diff is pa
|
|
|
1470
1475
|
const DiffBudget = Context.Reference("upup/DiffBudget", { defaultValue: () => () => maxDiffBytes });
|
|
1471
1476
|
const treeDiff = (workspace, from, to, limit) => Effect.gen(function* () {
|
|
1472
1477
|
const budget = limit ?? (yield* DiffBudget)(from);
|
|
1473
|
-
const { changes, same } = yield*
|
|
1474
|
-
try: async () => await planTree(workspace, from, to),
|
|
1475
|
-
catch: failure$1(from, to)
|
|
1476
|
-
});
|
|
1478
|
+
const { changes, same } = yield* planTree(workspace, from, to);
|
|
1477
1479
|
const parts = [];
|
|
1478
1480
|
const left = [];
|
|
1479
1481
|
let size = 0;
|
|
@@ -1807,12 +1809,16 @@ const majorsOf = (from, to) => {
|
|
|
1807
1809
|
};
|
|
1808
1810
|
const exists$1 = async (file) => await stat(file).then(() => true, () => false);
|
|
1809
1811
|
const emptyTree = async (directory) => await readdir(directory).then((entries) => entries.length === 0, () => false);
|
|
1810
|
-
const
|
|
1812
|
+
const majorsIn = async (workspace) => {
|
|
1813
|
+
const [from, to] = await Promise.all([listed$2(workspace, files.dependencyListFrom), listed$2(workspace, files.dependencyListTo)]);
|
|
1814
|
+
return majorsOf(from, to);
|
|
1815
|
+
};
|
|
1816
|
+
const readMajors = (workspace) => Effect.promise(async () => await majorsIn(workspace));
|
|
1811
1817
|
const read$1 = (workspace) => Effect.gen(function* () {
|
|
1812
1818
|
const meta = yield* readMeta(workspace);
|
|
1813
1819
|
return yield* Effect.tryPromise({
|
|
1814
1820
|
try: async () => {
|
|
1815
|
-
const diff = await readFile(path.join(workspace, files.diff));
|
|
1821
|
+
const [diff, majors] = await Promise.all([readFile(path.join(workspace, files.diff)), majorsIn(workspace)]);
|
|
1816
1822
|
const trees = [];
|
|
1817
1823
|
const titled = [];
|
|
1818
1824
|
const targets = /* @__PURE__ */ new Map();
|
|
@@ -1851,7 +1857,7 @@ const read$1 = (workspace) => Effect.gen(function* () {
|
|
|
1851
1857
|
trees,
|
|
1852
1858
|
files: titled,
|
|
1853
1859
|
sections,
|
|
1854
|
-
majors
|
|
1860
|
+
majors
|
|
1855
1861
|
};
|
|
1856
1862
|
},
|
|
1857
1863
|
catch: failed$1(workspace)
|
|
@@ -1921,28 +1927,18 @@ const BriefDoc = defineDoc({
|
|
|
1921
1927
|
initial: () => ({ brief: null }),
|
|
1922
1928
|
checkpointWhen: () => false
|
|
1923
1929
|
});
|
|
1924
|
-
const
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
Type.Literal("danger"),
|
|
1935
|
-
Type.Literal("no-verdict")
|
|
1936
|
-
]),
|
|
1937
|
-
rationale: Type.String({ description: "One concrete sentence justifying the verdict." }),
|
|
1938
|
-
summary: Type.String({ description: "Markdown: what the update changes that bears on the mandate, what you flagged and why you cleared or kept it." }),
|
|
1939
|
-
findings: Type.Array(Type.Object({
|
|
1940
|
-
severity,
|
|
1941
|
-
title: Type.String(),
|
|
1942
|
-
detail: Type.String({ description: "Markdown: the evidence and why it matters." }),
|
|
1943
|
-
paths: Type.Array(Type.String(), { description: "Workspace paths, with line ranges where useful." })
|
|
1930
|
+
const parameters = (schema) => Schema.toJsonSchemaDocument(schema).schema;
|
|
1931
|
+
const decodeRead = Schema.decodeUnknownSync(ReadArgs);
|
|
1932
|
+
const decodeGrep = Schema.decodeUnknownSync(GrepArgs);
|
|
1933
|
+
const decodeList = Schema.decodeUnknownSync(ListArgs);
|
|
1934
|
+
const decodeSubmitted = Schema.decodeUnknownSync(Report);
|
|
1935
|
+
const encodeReport = (submitted) => ({
|
|
1936
|
+
...submitted,
|
|
1937
|
+
findings: submitted.findings.map((finding) => ({
|
|
1938
|
+
...finding,
|
|
1939
|
+
paths: [...finding.paths]
|
|
1944
1940
|
})),
|
|
1945
|
-
unverified:
|
|
1941
|
+
unverified: [...submitted.unverified]
|
|
1946
1942
|
});
|
|
1947
1943
|
const ReportDoc = defineDoc({
|
|
1948
1944
|
kind: "upup.report",
|
|
@@ -1968,42 +1964,33 @@ const auditExtension = (workspace) => {
|
|
|
1968
1964
|
name: "read",
|
|
1969
1965
|
description: descriptions.read,
|
|
1970
1966
|
replay: "safe",
|
|
1971
|
-
parameters:
|
|
1972
|
-
|
|
1973
|
-
offset: Type.Integer({ description: parameters.read.offset }),
|
|
1974
|
-
limit: Type.Integer({ description: parameters.read.limit })
|
|
1975
|
-
}),
|
|
1976
|
-
execute: async (args, _api, invocation) => answer(await read$2(workspace, args, invocation.abortSignal))
|
|
1967
|
+
parameters: parameters(ReadArgs),
|
|
1968
|
+
execute: async (args, _api, invocation) => answer(await read$2(workspace, decodeRead(args), invocation.abortSignal))
|
|
1977
1969
|
});
|
|
1978
1970
|
const grep$1 = defineTool({
|
|
1979
1971
|
name: "grep",
|
|
1980
1972
|
description: descriptions.grep,
|
|
1981
1973
|
replay: "safe",
|
|
1982
|
-
parameters:
|
|
1983
|
-
|
|
1984
|
-
pattern: Type.String({ description: parameters.grep.pattern })
|
|
1985
|
-
}),
|
|
1986
|
-
execute: async (args, _api, invocation) => answer(await grep(workspace, args, invocation.abortSignal === void 0 ? {} : { signal: invocation.abortSignal }))
|
|
1974
|
+
parameters: parameters(GrepArgs),
|
|
1975
|
+
execute: async (args, _api, invocation) => answer(await grep(workspace, decodeGrep(args), invocation.abortSignal === void 0 ? {} : { signal: invocation.abortSignal }))
|
|
1987
1976
|
});
|
|
1988
1977
|
const list$1 = defineTool({
|
|
1989
1978
|
name: "list",
|
|
1990
1979
|
description: descriptions.list,
|
|
1991
1980
|
replay: "safe",
|
|
1992
|
-
parameters:
|
|
1993
|
-
|
|
1994
|
-
depth: Type.Integer({ description: parameters.list.depth })
|
|
1995
|
-
}),
|
|
1996
|
-
execute: async (args, _api, invocation) => answer(await list(workspace, args, invocation.abortSignal))
|
|
1981
|
+
parameters: parameters(ListArgs),
|
|
1982
|
+
execute: async (args, _api, invocation) => answer(await list(workspace, decodeList(args), invocation.abortSignal))
|
|
1997
1983
|
});
|
|
1998
1984
|
const submit = defineTool({
|
|
1999
1985
|
name: "submit_report",
|
|
2000
1986
|
description: "Submit the audit report. Call exactly once, when the investigation is done; the audit ends.",
|
|
2001
1987
|
replay: "safe",
|
|
2002
|
-
parameters:
|
|
1988
|
+
parameters: parameters(Report),
|
|
2003
1989
|
execute: async (args, api, invocation) => {
|
|
1990
|
+
const encoded = encodeReport(decodeSubmitted(args));
|
|
2004
1991
|
await api.commit(async (tx) => {
|
|
2005
1992
|
const doc = await tx.doc(ReportDoc, api.conversationId);
|
|
2006
|
-
doc.report =
|
|
1993
|
+
doc.report = encoded;
|
|
2007
1994
|
}, invocation);
|
|
2008
1995
|
return {
|
|
2009
1996
|
...text$2("Report submitted."),
|
|
@@ -2079,6 +2066,32 @@ const entriesOf$1 = (message) => {
|
|
|
2079
2066
|
}
|
|
2080
2067
|
return [];
|
|
2081
2068
|
};
|
|
2069
|
+
const TextBlock = Schema.Struct({
|
|
2070
|
+
type: Schema.Literal("text"),
|
|
2071
|
+
text: Schema.String
|
|
2072
|
+
});
|
|
2073
|
+
const ThinkingBlock = Schema.Struct({
|
|
2074
|
+
type: Schema.Literal("thinking"),
|
|
2075
|
+
thinking: Schema.String
|
|
2076
|
+
});
|
|
2077
|
+
const isTextBlock = Schema.is(TextBlock);
|
|
2078
|
+
const isThinkingBlock = Schema.is(ThinkingBlock);
|
|
2079
|
+
const decodeLive = Schema.decodeUnknownOption(Schema.Struct({ generation: Schema.optional(Schema.Struct({
|
|
2080
|
+
attempt: Schema.Finite,
|
|
2081
|
+
message: Schema.optional(Schema.Struct({ content: Schema.Array(Schema.Unknown) })),
|
|
2082
|
+
retry: Schema.optional(Schema.Struct({ error: Schema.String }))
|
|
2083
|
+
})) }));
|
|
2084
|
+
const streamed = (block) => {
|
|
2085
|
+
if (isThinkingBlock(block)) return block.thinking.trim() === "" ? [] : [{
|
|
2086
|
+
kind: "thinking",
|
|
2087
|
+
text: block.thinking
|
|
2088
|
+
}];
|
|
2089
|
+
if (isTextBlock(block)) return block.text.trim() === "" ? [] : [{
|
|
2090
|
+
kind: "text",
|
|
2091
|
+
text: block.text
|
|
2092
|
+
}];
|
|
2093
|
+
return [];
|
|
2094
|
+
};
|
|
2082
2095
|
var Transcript = class {
|
|
2083
2096
|
committed = /* @__PURE__ */ new Map();
|
|
2084
2097
|
live = [];
|
|
@@ -2086,41 +2099,20 @@ var Transcript = class {
|
|
|
2086
2099
|
add(entry) {
|
|
2087
2100
|
this.committed.set(entry.id, (entry.model ?? []).flatMap(entriesOf$1));
|
|
2088
2101
|
}
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
for (const change of event.changes) if (change.type === "text_delta" || change.type === "thinking_delta") {
|
|
2104
|
-
const kind = change.type === "text_delta" ? "text" : "thinking";
|
|
2105
|
-
const last = this.live.at(-1);
|
|
2106
|
-
if (last?.kind === kind) this.live[this.live.length - 1] = {
|
|
2107
|
-
kind,
|
|
2108
|
-
text: last.text + change.delta
|
|
2109
|
-
};
|
|
2110
|
-
else this.live.push({
|
|
2111
|
-
kind,
|
|
2112
|
-
text: change.delta
|
|
2113
|
-
});
|
|
2114
|
-
}
|
|
2115
|
-
break;
|
|
2116
|
-
case "auto_retry_start":
|
|
2117
|
-
this.retry = {
|
|
2118
|
-
kind: "retry",
|
|
2119
|
-
text: `retrying (attempt ${event.attempt}): ${event.errorMessage}`
|
|
2120
|
-
};
|
|
2121
|
-
break;
|
|
2122
|
-
case "auto_retry_end": this.retry = void 0;
|
|
2123
|
-
}
|
|
2102
|
+
view(view) {
|
|
2103
|
+
for (const entry of view.entries) this.add(entry);
|
|
2104
|
+
const generation = decodeLive(view.docs[LiveDoc.definition.kind]).pipe(Option.flatMapNullishOr((live) => live.generation));
|
|
2105
|
+
this.live = Option.match(generation, {
|
|
2106
|
+
onNone: () => [],
|
|
2107
|
+
onSome: ({ message }) => (message?.content ?? []).flatMap(streamed)
|
|
2108
|
+
});
|
|
2109
|
+
this.retry = Option.match(generation, {
|
|
2110
|
+
onNone: () => void 0,
|
|
2111
|
+
onSome: ({ attempt, retry }) => retry === void 0 ? void 0 : {
|
|
2112
|
+
kind: "retry",
|
|
2113
|
+
text: `retrying (attempt ${attempt}): ${retry.error}`
|
|
2114
|
+
}
|
|
2115
|
+
});
|
|
2124
2116
|
}
|
|
2125
2117
|
entries() {
|
|
2126
2118
|
return [
|
|
@@ -2135,16 +2127,24 @@ const attempt$1 = (evaluate) => Effect.tryPromise({
|
|
|
2135
2127
|
try: evaluate,
|
|
2136
2128
|
catch: failed
|
|
2137
2129
|
});
|
|
2130
|
+
const watched = (open, onValue) => Effect.acquireRelease(attempt$1(async () => {
|
|
2131
|
+
const watch = await open();
|
|
2132
|
+
watch.start(async (call) => {
|
|
2133
|
+
if (call.kind === "value") onValue(call.value);
|
|
2134
|
+
});
|
|
2135
|
+
return watch;
|
|
2136
|
+
}), (watch) => Effect.promise(async () => await watch.stop()).pipe(Effect.ignore));
|
|
2138
2137
|
const lastAssistant = (entries) => entries.flatMap((entry) => entry.model ?? []).findLast((message) => message.role === "assistant");
|
|
2139
|
-
const openHarness = (file,
|
|
2140
|
-
if (workspace ===
|
|
2141
|
-
const extension = auditExtension(workspace);
|
|
2138
|
+
const openHarness = (file, models, workspace) => Effect.acquireRelease(attempt$1(async () => {
|
|
2139
|
+
if (workspace === void 0 && !existsSync(file)) throw new Error(`no audit at ${file}`);
|
|
2140
|
+
const extension = auditExtension(workspace ?? "");
|
|
2142
2141
|
const registry = createRegistry();
|
|
2143
2142
|
registry.install(extension);
|
|
2144
2143
|
return await Harness.open(await openNodeSqliteStorage(file), {
|
|
2145
2144
|
models,
|
|
2146
2145
|
registry,
|
|
2147
|
-
settings: { extensions: [extension] }
|
|
2146
|
+
settings: { extensions: [extension] },
|
|
2147
|
+
readOnly: workspace === void 0
|
|
2148
2148
|
}, context);
|
|
2149
2149
|
}), (harness) => Effect.promise(async () => {
|
|
2150
2150
|
await harness.close(context);
|
|
@@ -2157,7 +2157,7 @@ const encodeBrief = (brief) => ({
|
|
|
2157
2157
|
artifacts: [...brief.artifacts]
|
|
2158
2158
|
});
|
|
2159
2159
|
const run$5 = (options) => Effect.scoped(Effect.gen(function* () {
|
|
2160
|
-
const harness = yield* openHarness(options.file, options.
|
|
2160
|
+
const harness = yield* openHarness(options.file, options.models, options.brief.workspace);
|
|
2161
2161
|
const root = yield* attempt$1(async () => await harness.root(context, {
|
|
2162
2162
|
agent: {
|
|
2163
2163
|
model: {
|
|
@@ -2172,13 +2172,12 @@ const run$5 = (options) => Effect.scoped(Effect.gen(function* () {
|
|
|
2172
2172
|
}
|
|
2173
2173
|
}));
|
|
2174
2174
|
const transcript = new Transcript();
|
|
2175
|
-
const
|
|
2176
|
-
|
|
2177
|
-
options.onTranscript(transcript.entries());
|
|
2178
|
-
events.start(async (batch) => {
|
|
2179
|
-
for (const event of batch) transcript.apply(event);
|
|
2175
|
+
const views = yield* watched(async () => await root.watch(context), (view) => {
|
|
2176
|
+
transcript.view(view);
|
|
2180
2177
|
options.onTranscript(transcript.entries());
|
|
2181
2178
|
});
|
|
2179
|
+
transcript.view(views.value);
|
|
2180
|
+
options.onTranscript(transcript.entries());
|
|
2182
2181
|
harness.resume();
|
|
2183
2182
|
const settled = yield* Effect.tryPromise({
|
|
2184
2183
|
try: async (signal) => {
|
|
@@ -2205,20 +2204,29 @@ const run$5 = (options) => Effect.scoped(Effect.gen(function* () {
|
|
|
2205
2204
|
_tag: "Reported",
|
|
2206
2205
|
report: decoded.value
|
|
2207
2206
|
};
|
|
2208
|
-
const final = yield* attempt$1(async () => await
|
|
2209
|
-
yield* attempt$1(async () => await final.stop());
|
|
2207
|
+
const final = yield* attempt$1(async () => await root.context(context));
|
|
2210
2208
|
if (settled.value.status === "unanswered") return {
|
|
2211
2209
|
_tag: "Failed",
|
|
2212
2210
|
issue: Predicate.isString(settled.value.detail) ? settled.value.detail : settled.value.reason
|
|
2213
2211
|
};
|
|
2214
2212
|
return {
|
|
2215
2213
|
_tag: "Failed",
|
|
2216
|
-
issue: lastAssistant(final.
|
|
2214
|
+
issue: lastAssistant(final.entries)?.errorMessage ?? "the model finished without submitting a report"
|
|
2217
2215
|
};
|
|
2218
2216
|
}));
|
|
2217
|
+
const storedRoot = (file, models) => Effect.gen(function* () {
|
|
2218
|
+
const harness = yield* openHarness(file, models);
|
|
2219
|
+
return {
|
|
2220
|
+
harness,
|
|
2221
|
+
root: yield* attempt$1(async () => await harness.conversation(ROOT_CONVERSATION_ID, context))
|
|
2222
|
+
};
|
|
2223
|
+
});
|
|
2219
2224
|
const stored = (file, models) => Effect.scoped(Effect.gen(function* () {
|
|
2220
|
-
const harness = yield*
|
|
2221
|
-
|
|
2225
|
+
const { harness, root } = yield* storedRoot(file, models);
|
|
2226
|
+
if (root === void 0) return {
|
|
2227
|
+
brief: Option.none(),
|
|
2228
|
+
report: Option.none()
|
|
2229
|
+
};
|
|
2222
2230
|
const brief = yield* attempt$1(async () => await harness.snapshot(BriefDoc, root.id, context));
|
|
2223
2231
|
const submitted = yield* attempt$1(async () => await harness.snapshot(ReportDoc, root.id, context));
|
|
2224
2232
|
return {
|
|
@@ -2227,12 +2235,12 @@ const stored = (file, models) => Effect.scoped(Effect.gen(function* () {
|
|
|
2227
2235
|
};
|
|
2228
2236
|
}));
|
|
2229
2237
|
const transcript = (file, models) => Effect.scoped(Effect.gen(function* () {
|
|
2230
|
-
const
|
|
2231
|
-
const root = yield* attempt$1(async () => await harness.root(context));
|
|
2232
|
-
const events = yield* attempt$1(async () => await watchEvents(harness, root.id, context));
|
|
2233
|
-
yield* attempt$1(async () => await events.stop());
|
|
2238
|
+
const { root } = yield* storedRoot(file, models);
|
|
2234
2239
|
const built = new Transcript();
|
|
2235
|
-
|
|
2240
|
+
if (root !== void 0) {
|
|
2241
|
+
const active = yield* attempt$1(async () => await root.context(context));
|
|
2242
|
+
for (const entry of active.entries) built.add(entry);
|
|
2243
|
+
}
|
|
2236
2244
|
return built.entries();
|
|
2237
2245
|
}));
|
|
2238
2246
|
// src/inventory/versions.ts
|
|
@@ -2339,7 +2347,7 @@ const escape = (path) => path.replaceAll(/[A-Z]/gu, (letter) => `!${letter.toLow
|
|
|
2339
2347
|
const deprecation = (mod) => Option.fromNullishOr(/^\/\/\s*Deprecated:\s*(?<reason>.+)$/mu.exec(mod)?.groups?.["reason"]?.trim());
|
|
2340
2348
|
const lookup$5 = Effect.fn("go.lookup")(function* (client, wanted) {
|
|
2341
2349
|
const base = `https://proxy.golang.org/${escape(wanted.name)}/@v`;
|
|
2342
|
-
const [latest, infos] = yield* Effect.all([getJson(client, `https://proxy.golang.org/${escape(wanted.name)}/@latest`, Info$2), Effect.forEach(wanted.versions, (version) => getJson(client, `${base}/${escape(version)}.info`, Info$2).pipe(Effect.option), { concurrency: 2 })], { concurrency:
|
|
2350
|
+
const [latest, infos] = yield* Effect.all([getJson(client, `https://proxy.golang.org/${escape(wanted.name)}/@latest`, Info$2), Effect.forEach(wanted.versions, (version) => getJson(client, `${base}/${escape(version)}.info`, Info$2).pipe(Effect.option), { concurrency: 2 })], { concurrency: "unbounded" });
|
|
2343
2351
|
const mod = yield* getText(client, `${base}/${escape(latest.Version)}.mod`);
|
|
2344
2352
|
const deprecated = deprecation(mod);
|
|
2345
2353
|
const found = infos.flatMap((info) => Option.isSome(info) ? [info.value] : []);
|
|
@@ -4850,30 +4858,36 @@ const resolveFormula = Effect.fn("brew.resolveFormula")(function* (client, sourc
|
|
|
4850
4858
|
digest: createHash("sha256").update(body).digest("hex")
|
|
4851
4859
|
};
|
|
4852
4860
|
});
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
if (complete()) break;
|
|
4861
|
+
const scanHistory = Effect.gen(function* () {
|
|
4862
|
+
let to;
|
|
4863
|
+
let from;
|
|
4864
|
+
let endpoint = `${githubApi}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/commits?${new URLSearchParams({
|
|
4865
|
+
path: source.rubySourcePath,
|
|
4866
|
+
per_page: `${historyPageSize}`
|
|
4867
|
+
}).toString()}`;
|
|
4868
|
+
let scanned = 0;
|
|
4869
|
+
const complete = () => from !== void 0 && to !== void 0;
|
|
4870
|
+
for (let page = 0; endpoint !== "" && page < maxHistoryPages && !complete(); page += 1) {
|
|
4871
|
+
const { body, link } = yield* githubGet(client, endpoint, token).pipe(Effect.mapError(prefixed("query brew formula history")));
|
|
4872
|
+
const commits = yield* commitsOf(body, endpoint);
|
|
4873
|
+
for (const commit of commits) {
|
|
4874
|
+
scanned += 1;
|
|
4875
|
+
const { snapshot: candidate } = yield* snapshot(commit.sha, commit.message);
|
|
4876
|
+
if (to === void 0 && matchesVersion(candidate.text, toVersion)) to = candidate;
|
|
4877
|
+
if (from === void 0 && matchesVersion(candidate.text, fromVersion)) from = candidate;
|
|
4878
|
+
if (complete()) break;
|
|
4879
|
+
}
|
|
4880
|
+
endpoint = complete() ? "" : nextPage(endpoint, link);
|
|
4874
4881
|
}
|
|
4875
|
-
|
|
4876
|
-
|
|
4882
|
+
return {
|
|
4883
|
+
from,
|
|
4884
|
+
to,
|
|
4885
|
+
scanned
|
|
4886
|
+
};
|
|
4887
|
+
});
|
|
4888
|
+
const [current, history] = yield* Effect.all([source.tapGitHead === "" ? Effect.succeedNone : Effect.option(snapshot(source.tapGitHead, "tap revision reported by brew info")), scanHistory], { concurrency: "unbounded" });
|
|
4889
|
+
const { from, scanned } = history;
|
|
4890
|
+
const to = current._tag === "Some" && matchesVersion(current.value.snapshot.text, toVersion) && (source.rubySourceChecksum === "" || source.rubySourceChecksum.toLowerCase() === current.value.digest) ? current.value.snapshot : history.to;
|
|
4877
4891
|
if (to === void 0) return yield* new EvidenceUnavailable({
|
|
4878
4892
|
source: "brew",
|
|
4879
4893
|
issue: `brew formula history has no snapshot for target version ${toVersion} within the newest ${scanned} commits`
|
|
@@ -5278,13 +5292,14 @@ const payloadDiff = Effect.fn("brew.payloadDiff")(function* (client, workspace,
|
|
|
5278
5292
|
const { name } = shortName(artifact);
|
|
5279
5293
|
const oldStrip = yield* strip(name, plan.old);
|
|
5280
5294
|
const newStrip = yield* strip(name, plan.new);
|
|
5281
|
-
const oldManifest = yield* payloadManifest(client, "installed", plan.old, oldStrip, path.join(workspace, files.payloadTreeFrom));
|
|
5295
|
+
const [oldManifest, newManifest] = yield* Effect.all([payloadManifest(client, "installed", plan.old, oldStrip, path.join(workspace, files.payloadTreeFrom)), payloadManifest(client, "target", plan.new, newStrip, path.join(workspace, files.payloadTreeTo))], { concurrency: "unbounded" });
|
|
5282
5296
|
if (oldManifest === void 0) return yield* unavailablePayload(workspace, "installed Homebrew payload archive format is unsupported");
|
|
5283
|
-
const newManifest = yield* payloadManifest(client, "target", plan.new, newStrip, path.join(workspace, files.payloadTreeTo));
|
|
5284
5297
|
if (newManifest === void 0) return yield* unavailablePayload(workspace, "target Homebrew payload archive format is unsupported");
|
|
5285
|
-
const manifests = yield*
|
|
5286
|
-
|
|
5287
|
-
|
|
5298
|
+
const [manifests, binaries, trees] = yield* Effect.all([
|
|
5299
|
+
writeFileDiff(workspace, files.payloadFrom, files.payloadTo, manifestJson(oldManifest), manifestJson(newManifest)),
|
|
5300
|
+
writeFileDiff(workspace, files.binaryFrom, files.binaryTo, json(binarySummaries(oldManifest)), json(binarySummaries(newManifest))),
|
|
5301
|
+
treeDiff(workspace, files.payloadTreeFrom, files.payloadTreeTo)
|
|
5302
|
+
], { concurrency: "unbounded" });
|
|
5288
5303
|
const contents = trees.diff;
|
|
5289
5304
|
const contentDetail = [" Extracted payload file contents are diffed.", partial("payload", trees.omitted)].filter((sentence) => sentence !== "").join(" ");
|
|
5290
5305
|
const origin = plan.old.origin === "" ? "" : ` (pinned by ${plan.old.origin})`;
|
|
@@ -5763,9 +5778,9 @@ const writeChanges = Effect.fn("git.writeChanges")(function* (from, to, destinat
|
|
|
5763
5778
|
modes
|
|
5764
5779
|
};
|
|
5765
5780
|
const contents = readBatch((yield* git(["cat-file", "--batch"], objects.map((object) => `${object}\n`).join(""))).stdout, objects);
|
|
5766
|
-
yield* Effect.tryPromise({
|
|
5781
|
+
yield* Effect.forEach(changes, (change) => Effect.tryPromise({
|
|
5767
5782
|
try: async () => {
|
|
5768
|
-
for (const
|
|
5783
|
+
for (const [object, root] of [[change.fromObject, destination.from], [change.toObject, destination.to]]) {
|
|
5769
5784
|
if (object === void 0) continue;
|
|
5770
5785
|
const file = path.join(root, change.path);
|
|
5771
5786
|
await mkdir(path.dirname(file), {
|
|
@@ -5779,6 +5794,9 @@ const writeChanges = Effect.fn("git.writeChanges")(function* (from, to, destinat
|
|
|
5779
5794
|
repository,
|
|
5780
5795
|
issue: `write source files: ${String(error)}`
|
|
5781
5796
|
})
|
|
5797
|
+
}), {
|
|
5798
|
+
concurrency: 8,
|
|
5799
|
+
discard: true
|
|
5782
5800
|
});
|
|
5783
5801
|
return {
|
|
5784
5802
|
files: changes.length,
|
|
@@ -5839,9 +5857,9 @@ const moduleChanges = (from, to, released) => {
|
|
|
5839
5857
|
};
|
|
5840
5858
|
};
|
|
5841
5859
|
const readSummaries = (workspace, file) => Effect.tryPromise(async () => await readFile(path.join(workspace, file), "utf-8")).pipe(Effect.flatMap((text) => Schema.decodeEffect(Summaries)(text)), Effect.option);
|
|
5860
|
+
const readBinarySummaries = (workspace) => Effect.all([readSummaries(workspace, files.binaryFrom), readSummaries(workspace, files.binaryTo)], { concurrency: "unbounded" });
|
|
5842
5861
|
const goSourceEvidence = Effect.fn("goSource.evidence")(function* (client, workspace, released) {
|
|
5843
|
-
const from = yield*
|
|
5844
|
-
const to = yield* readSummaries(workspace, files.binaryTo);
|
|
5862
|
+
const [from, to] = yield* readBinarySummaries(workspace);
|
|
5845
5863
|
if (from._tag === "None" || to._tag === "None") return;
|
|
5846
5864
|
const { changes, reason } = moduleChanges(from.value, to.value, released);
|
|
5847
5865
|
if (changes.length === 0) return {
|
|
@@ -5853,7 +5871,7 @@ const goSourceEvidence = Effect.fn("goSource.evidence")(function* (client, works
|
|
|
5853
5871
|
const plan = yield* resolve$3(client, "go", modulePath, version);
|
|
5854
5872
|
return yield* materialize$2(client, plan, path.join(workspace, tree, modulePath));
|
|
5855
5873
|
});
|
|
5856
|
-
const fetched = yield* Effect.forEach(changes, (change) => Effect.result(Effect.all([fetch(change.path, change.from, files.goSourceFrom), fetch(change.path, change.to, files.goSourceTo)], { concurrency:
|
|
5874
|
+
const fetched = yield* Effect.forEach(changes, (change) => Effect.result(Effect.all([fetch(change.path, change.from, files.goSourceFrom), fetch(change.path, change.to, files.goSourceTo)], { concurrency: "unbounded" })), { concurrency: 2 });
|
|
5857
5875
|
const failures = changes.flatMap((change, index) => {
|
|
5858
5876
|
const result = fetched[index];
|
|
5859
5877
|
return result?._tag === "Failure" ? [`${change.path}: ${result.failure.issue}`] : [];
|
|
@@ -5912,8 +5930,7 @@ const buildInfoSources = (from, to) => {
|
|
|
5912
5930
|
return [...sources.values()].slice(0, 4);
|
|
5913
5931
|
};
|
|
5914
5932
|
const readBuildInfoSources = Effect.fn("goSource.buildInfoSources")(function* (workspace) {
|
|
5915
|
-
const from = yield*
|
|
5916
|
-
const to = yield* readSummaries(workspace, files.binaryTo);
|
|
5933
|
+
const [from, to] = yield* readBinarySummaries(workspace);
|
|
5917
5934
|
return from._tag === "None" || to._tag === "None" ? [] : buildInfoSources(from.value, to.value);
|
|
5918
5935
|
});
|
|
5919
5936
|
// src/audit/source-evidence.ts
|
|
@@ -6225,7 +6242,7 @@ const releaseAssetSources = Effect.fn("sourceLink.releaseAssets")(function* (cli
|
|
|
6225
6242
|
} })), Effect.catch((error) => Effect.succeed(gap(error.issue))));
|
|
6226
6243
|
}
|
|
6227
6244
|
return Effect.succeed(gap("no release of the repository publishes this exact binary"));
|
|
6228
|
-
});
|
|
6245
|
+
}, { concurrency: 4 });
|
|
6229
6246
|
});
|
|
6230
6247
|
// src/audit/brew.ts
|
|
6231
6248
|
const caskArchiveUnavailable = "compiled cask payloads are not source archives";
|
|
@@ -6291,7 +6308,7 @@ const sourceDiff = Effect.fn("brew.sourceDiff")(function* (client, workspace, pa
|
|
|
6291
6308
|
const [gap] = yield* Effect.all([sourceTree(client, pair.old, path.join(workspace, files.sourceFrom)).pipe(Effect.as(""), Effect.catch((error) => {
|
|
6292
6309
|
const reason = historicalGap(pair.old.url, error);
|
|
6293
6310
|
return reason === void 0 ? Effect.fail(labelled("download old brew source archive")(error)) : Effect.succeed(reason);
|
|
6294
|
-
})), sourceTree(client, pair.new, path.join(workspace, files.source)).pipe(Effect.mapError(labelled("download new brew source archive")))], { concurrency:
|
|
6311
|
+
})), sourceTree(client, pair.new, path.join(workspace, files.source)).pipe(Effect.mapError(labelled("download new brew source archive")))], { concurrency: "unbounded" });
|
|
6295
6312
|
if (gap !== "") return {
|
|
6296
6313
|
diff: Buffer.alloc(0),
|
|
6297
6314
|
reason: gap,
|
|
@@ -6328,9 +6345,11 @@ const sourceEvidence = Effect.fn("brew.sourceEvidence")(function* (client, works
|
|
|
6328
6345
|
};
|
|
6329
6346
|
});
|
|
6330
6347
|
const materialize$1 = Effect.fn("brew.materialize")(function* (client, workspace, identity, plan, key) {
|
|
6331
|
-
const formula = yield*
|
|
6332
|
-
|
|
6333
|
-
|
|
6348
|
+
const [formula, source, payload] = yield* Effect.all([
|
|
6349
|
+
materializeFormula(workspace, plan.formula),
|
|
6350
|
+
sourceEvidence(client, workspace, archives(plan.formula), plan.sourceGap),
|
|
6351
|
+
materializePayload(client, workspace, identity.delta.artifact, plan.payload)
|
|
6352
|
+
], { concurrency: "unbounded" });
|
|
6334
6353
|
const goSource = source.included ? void 0 : yield* goSourceEvidence(client, workspace, identity.delta);
|
|
6335
6354
|
const sources = goSource?.included === true || source.included ? [] : [...plan.repository === void 0 ? [] : [plan.repository], ...yield* readBuildInfoSources(workspace)];
|
|
6336
6355
|
const repository = sources.length === 0 ? void 0 : yield* materializeSources(workspace, sources);
|
|
@@ -6357,7 +6376,7 @@ const resolve$2 = Effect.fn("brew.resolve")(function* (client, identity) {
|
|
|
6357
6376
|
const formulaGap = formula.fromGap === "" ? archiveUnavailableReason(archives(formula)) : "the installed version's formula snapshot is unavailable";
|
|
6358
6377
|
const sourceGap = kind === "cask" ? caskArchiveUnavailable : formulaGap;
|
|
6359
6378
|
const payload = yield* resolvePayload(info, artifact, from, to, formula.from?.text);
|
|
6360
|
-
const released = sourceGap !== "" && payload.old.url !== "" && payload.new.url !== "" ? yield* Effect.all([releaseTagSource(payload.old.url), releaseTagSource(payload.new.url)], { concurrency:
|
|
6379
|
+
const released = sourceGap !== "" && payload.old.url !== "" && payload.new.url !== "" ? yield* Effect.all([releaseTagSource(payload.old.url), releaseTagSource(payload.new.url)], { concurrency: "unbounded" }) : void 0;
|
|
6361
6380
|
const repository = released === void 0 || released.every((side) => "gap" in side) ? void 0 : {
|
|
6362
6381
|
label: artifact,
|
|
6363
6382
|
from: released[0],
|
|
@@ -6422,7 +6441,7 @@ const workspaceOf$1 = Effect.fn("githubActions.workspace")(function* (workspace,
|
|
|
6422
6441
|
const githubActionPreparer = (repositoryOf, options = {}) => Effect.fn("githubActions.prepare")(function* (_client, identity) {
|
|
6423
6442
|
const { artifact, from, to } = identity.delta;
|
|
6424
6443
|
const repository = repositoryOf(artifact);
|
|
6425
|
-
const [fromCommit, toCommit] = yield* Effect.all([tagCommit(repository, from, options), tagCommit(repository, to, options)], { concurrency:
|
|
6444
|
+
const [fromCommit, toCommit] = yield* Effect.all([tagCommit(repository, from, options), tagCommit(repository, to, options)], { concurrency: "unbounded" }).pipe(Effect.mapError(unavailable$1));
|
|
6426
6445
|
const listed = identity.context["revision"];
|
|
6427
6446
|
if (listed !== toCommit) return yield* new EvidenceUnavailable({
|
|
6428
6447
|
source: repository,
|
|
@@ -6619,12 +6638,14 @@ const pypiWorkspace = Effect.fn("pypi.workspace")(function* (client, workspace,
|
|
|
6619
6638
|
issue: error instanceof Error ? error.message : String(error)
|
|
6620
6639
|
})
|
|
6621
6640
|
});
|
|
6622
|
-
const [from, to] = yield* Effect.all([materialize(client, plans.from, path.join(workspace, files.from), path.join(workspace, files.wheelFrom)), materialize(client, plans.to, path.join(workspace, files.to), path.join(workspace, files.wheelTo))], { concurrency:
|
|
6623
|
-
const sources = yield*
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6641
|
+
const [from, to] = yield* Effect.all([materialize(client, plans.from, path.join(workspace, files.from), path.join(workspace, files.wheelFrom)), materialize(client, plans.to, path.join(workspace, files.to), path.join(workspace, files.wheelTo))], { concurrency: "unbounded" });
|
|
6642
|
+
const [sources, records, sourceBinaries, wheels, wheelBinaries] = yield* Effect.all([
|
|
6643
|
+
treeDiff(workspace, files.from, files.to),
|
|
6644
|
+
writeFileDiff(workspace, files.pypiFrom, files.pypiTo, manifestJson(from), manifestJson(to)),
|
|
6645
|
+
writeFileDiff(workspace, files.binaryFrom, files.binaryTo, json(binarySummaries(from.publisher_sdist?.archive_manifest)), json(binarySummaries(to.publisher_sdist?.archive_manifest))),
|
|
6646
|
+
treeDiff(workspace, files.wheelFrom, files.wheelTo),
|
|
6647
|
+
writeFileDiff(workspace, files.binaryWheelFrom, files.binaryWheelTo, json(binarySummaries(from.compatible_universal_wheel?.archive_manifest)), json(binarySummaries(to.compatible_universal_wheel?.archive_manifest)))
|
|
6648
|
+
], { concurrency: "unbounded" });
|
|
6628
6649
|
const detail = `Checksum-verified PyPI publisher artifacts; ${pairedDetail("source distributions", from.publisher_sdist, to.publisher_sdist)}; ${pairedDetail("compatible universal wheel candidates", from.compatible_universal_wheel, to.compatible_universal_wheel)}; the installer’s exact resolver selection is not known.`;
|
|
6629
6650
|
return yield* write(workspace, identity, Buffer.concat([
|
|
6630
6651
|
sources.diff,
|
|
@@ -6641,7 +6662,7 @@ const pypiWorkspace = Effect.fn("pypi.workspace")(function* (client, workspace,
|
|
|
6641
6662
|
const preparePyPI = Effect.fn("pypi.prepare")(function* (client, identity) {
|
|
6642
6663
|
const { artifact, from, to } = identity.delta;
|
|
6643
6664
|
const python = identity.context["python"] ?? "";
|
|
6644
|
-
const [fromPlan, toPlan] = yield* Effect.all([resolve$1(client, artifact, from, python), resolve$1(client, artifact, to, python)], { concurrency:
|
|
6665
|
+
const [fromPlan, toPlan] = yield* Effect.all([resolve$1(client, artifact, from, python), resolve$1(client, artifact, to, python)], { concurrency: "unbounded" });
|
|
6645
6666
|
const plans = {
|
|
6646
6667
|
from: fromPlan,
|
|
6647
6668
|
to: toPlan
|
|
@@ -6734,7 +6755,7 @@ const resolveDependencies = Effect.fn("npmDependencies.resolve")(function* (clie
|
|
|
6734
6755
|
const outcomes = yield* Effect.forEach(changedNames, (dependency) => Effect.gen(function* () {
|
|
6735
6756
|
if (!packageName.test(dependency)) return Result.fail("its name is not a valid registry package name");
|
|
6736
6757
|
const side = (declared) => declared === void 0 ? Effect.undefined : resolveSide(client, host, dependency, declared);
|
|
6737
|
-
const resolved = yield* Effect.result(Effect.all([side(before.get(dependency)), side(after.get(dependency))], { concurrency:
|
|
6758
|
+
const resolved = yield* Effect.result(Effect.all([side(before.get(dependency)), side(after.get(dependency))], { concurrency: "unbounded" }));
|
|
6738
6759
|
return Result.isFailure(resolved) ? Result.fail(resolved.failure.issue) : Result.succeed(resolved.success);
|
|
6739
6760
|
}), { concurrency: 4 });
|
|
6740
6761
|
for (const [index, dependency] of changedNames.entries()) {
|
|
@@ -6841,8 +6862,8 @@ const materializeDependencies = Effect.fn("npmDependencies.materialize")(functio
|
|
|
6841
6862
|
issue: error instanceof Error ? error.message : String(error)
|
|
6842
6863
|
})
|
|
6843
6864
|
});
|
|
6844
|
-
const sides = yield* Effect.forEach(dependencies.changed, (dependency) => Effect.all([fetchSide(client, dependency.from, path.join(workspace, files.dependenciesFrom, dependency.name)), fetchSide(client, dependency.to, path.join(workspace, files.dependenciesTo, dependency.name))], { concurrency:
|
|
6845
|
-
const summaries = yield* writeFileDiff(workspace, files.dependencyListFrom, files.dependencyListTo, record(dependencies, dependencies.changed.map((dependency, index) => ({
|
|
6865
|
+
const sides = yield* Effect.forEach(dependencies.changed, (dependency) => Effect.all([fetchSide(client, dependency.from, path.join(workspace, files.dependenciesFrom, dependency.name)), fetchSide(client, dependency.to, path.join(workspace, files.dependenciesTo, dependency.name))], { concurrency: "unbounded" }), { concurrency: 4 });
|
|
6866
|
+
const [summaries, trees] = yield* Effect.all([writeFileDiff(workspace, files.dependencyListFrom, files.dependencyListTo, record(dependencies, dependencies.changed.map((dependency, index) => ({
|
|
6846
6867
|
name: dependency.name,
|
|
6847
6868
|
...dependency.from === void 0 ? {} : { resolved: dependency.from },
|
|
6848
6869
|
...sides[index]?.[0] === void 0 ? {} : { fetched: sides[index][0] }
|
|
@@ -6850,8 +6871,7 @@ const materializeDependencies = Effect.fn("npmDependencies.materialize")(functio
|
|
|
6850
6871
|
name: dependency.name,
|
|
6851
6872
|
...dependency.to === void 0 ? {} : { resolved: dependency.to },
|
|
6852
6873
|
...sides[index]?.[1] === void 0 ? {} : { fetched: sides[index][1] }
|
|
6853
|
-
}))));
|
|
6854
|
-
const trees = yield* treeDiff(workspace, files.dependenciesFrom, files.dependenciesTo);
|
|
6874
|
+
})))), treeDiff(workspace, files.dependenciesFrom, files.dependenciesTo)], { concurrency: "unbounded" });
|
|
6855
6875
|
const failed = dependencies.changed.filter((_, index) => (sides[index] ?? []).some((side) => side?.error !== void 0));
|
|
6856
6876
|
const included = dependencies.changed.map((dependency) => `${dependency.name} ${dependency.from?.plan.version ?? "(new)"}${dependency.from?.lowest === true ? " (lowest of its range)" : ""} -> ${dependency.to?.plan.version ?? "(removed)"}${dependency.to?.bundled === true ? " (now a devDependency, so probably bundled into the package)" : ""}`);
|
|
6857
6877
|
const noneIncluded = dependencies.omitted.length === 0 ? "No direct dependency's declared version changed." : "No changed direct dependency is compared.";
|
|
@@ -6884,10 +6904,12 @@ const materializeDependencies = Effect.fn("npmDependencies.materialize")(functio
|
|
|
6884
6904
|
// src/audit/registry-evidence.ts
|
|
6885
6905
|
const registryDetail = "Both published packages were downloaded and their checksums verified. File types and modes, and any native binaries, are summarised without running them.";
|
|
6886
6906
|
const registryWorkspace = Effect.fn("evidence.registryWorkspace")(function* (client, workspace, identity, plans, npm, key) {
|
|
6887
|
-
const [from, to] = yield* Effect.all([materialize$2(client, plans.from, path.join(workspace, files.from)), materialize$2(client, plans.to, path.join(workspace, files.to))], { concurrency:
|
|
6888
|
-
const artifacts = yield*
|
|
6889
|
-
|
|
6890
|
-
|
|
6907
|
+
const [from, to] = yield* Effect.all([materialize$2(client, plans.from, path.join(workspace, files.from)), materialize$2(client, plans.to, path.join(workspace, files.to))], { concurrency: "unbounded" });
|
|
6908
|
+
const [artifacts, trees, binaries] = yield* Effect.all([
|
|
6909
|
+
writeFileDiff(workspace, files.artifactFrom, files.artifactTo, manifestJson(from), manifestJson(to)),
|
|
6910
|
+
treeDiff(workspace, files.from, files.to),
|
|
6911
|
+
writeFileDiff(workspace, files.binaryFrom, files.binaryTo, json(binarySummaries(from)), json(binarySummaries(to)))
|
|
6912
|
+
], { concurrency: "unbounded" });
|
|
6891
6913
|
const treeDetail = [registryDetail, partial("artifact", trees.omitted)].filter((sentence) => sentence !== "").join(" ");
|
|
6892
6914
|
if (npm === void 0) return yield* write(workspace, identity, Buffer.concat([
|
|
6893
6915
|
artifacts,
|
|
@@ -6921,7 +6943,7 @@ const npmExtras = Effect.fn("evidence.npmExtras")(function* (client, name, from,
|
|
|
6921
6943
|
cpu: process.arch
|
|
6922
6944
|
});
|
|
6923
6945
|
const verifier = yield* Effect.cached(sigstoreVerifier);
|
|
6924
|
-
const [fromSource, toSource] = yield* Effect.all([npmSource(client, name, from, fromManifest, verifier), npmSource(client, name, to, toManifest, verifier)], { concurrency:
|
|
6946
|
+
const [fromSource, toSource] = yield* Effect.all([npmSource(client, name, from, fromManifest, verifier), npmSource(client, name, to, toManifest, verifier)], { concurrency: "unbounded" });
|
|
6925
6947
|
const { directory } = npmRepository(toManifest);
|
|
6926
6948
|
return {
|
|
6927
6949
|
dependencies,
|
|
@@ -6938,8 +6960,8 @@ const prepareRegistry = Effect.fn("evidence.prepareRegistry")(function* (client,
|
|
|
6938
6960
|
const manifests = ecosystem === "npm" ? yield* Effect.all({
|
|
6939
6961
|
from: npmVersion(client, artifact, from),
|
|
6940
6962
|
to: npmVersion(client, artifact, to)
|
|
6941
|
-
}, { concurrency:
|
|
6942
|
-
const [fromPlan, toPlan] = yield* Effect.all(manifests === void 0 ? [resolve$3(client, ecosystem, artifact, from), resolve$3(client, ecosystem, artifact, to)] : [npmPlan(artifact, from, manifests.from), npmPlan(artifact, to, manifests.to)], { concurrency:
|
|
6963
|
+
}, { concurrency: "unbounded" }) : void 0;
|
|
6964
|
+
const [fromPlan, toPlan] = yield* Effect.all(manifests === void 0 ? [resolve$3(client, ecosystem, artifact, from), resolve$3(client, ecosystem, artifact, to)] : [npmPlan(artifact, from, manifests.from), npmPlan(artifact, to, manifests.to)], { concurrency: "unbounded" });
|
|
6943
6965
|
const plans = {
|
|
6944
6966
|
from: fromPlan,
|
|
6945
6967
|
to: toPlan
|
|
@@ -7314,10 +7336,9 @@ const layer$5 = (cacheDir) => Layer.effect(Audits, Effect.gen(function* () {
|
|
|
7314
7336
|
}));
|
|
7315
7337
|
const started = yield* Clock.currentTimeMillis;
|
|
7316
7338
|
const base = path.join(root, "workspaces");
|
|
7317
|
-
|
|
7318
|
-
if (name.endsWith(".lock")) continue;
|
|
7339
|
+
yield* Effect.forEach((yield* children(base)).filter((name) => !name.endsWith(".lock")), (name) => {
|
|
7319
7340
|
const workspace = path.join(base, name);
|
|
7320
|
-
|
|
7341
|
+
return Effect.scoped(Effect.gen(function* () {
|
|
7321
7342
|
if (!(yield* tryHold(workspace))) return;
|
|
7322
7343
|
const prepared = yield* Effect.promise(async () => await stat(path.join(workspace, files.meta)).then((info) => info.mtimeMs, () => 0));
|
|
7323
7344
|
if (started - prepared > Duration.toMillis(keptWorkspaces)) {
|
|
@@ -7325,9 +7346,15 @@ const layer$5 = (cacheDir) => Layer.effect(Audits, Effect.gen(function* () {
|
|
|
7325
7346
|
return;
|
|
7326
7347
|
}
|
|
7327
7348
|
const entries = yield* Effect.promise(async () => await readdir(workspace, { withFileTypes: true }).catch(() => []));
|
|
7328
|
-
|
|
7349
|
+
yield* Effect.forEach(entries.filter((entry) => entry.isDirectory()), (entry) => discard(path.join(workspace, entry.name), name), {
|
|
7350
|
+
concurrency: "unbounded",
|
|
7351
|
+
discard: true
|
|
7352
|
+
});
|
|
7329
7353
|
})).pipe(Effect.ignore);
|
|
7330
|
-
}
|
|
7354
|
+
}, {
|
|
7355
|
+
concurrency: 8,
|
|
7356
|
+
discard: true
|
|
7357
|
+
});
|
|
7331
7358
|
yield* Effect.forkScoped(Effect.promise(async () => {
|
|
7332
7359
|
for (const name of await readdir(trash).catch(() => [])) await rm(path.join(trash, name), {
|
|
7333
7360
|
recursive: true,
|
|
@@ -7544,12 +7571,15 @@ const workflowFiles = Effect.fn("workflowFiles")(function* (root) {
|
|
|
7544
7571
|
for (const name of ["action.yml", "action.yaml"]) if (yield* present(path.join(dir, name))) return Option.some(path.join(dir, name));
|
|
7545
7572
|
return Option.none();
|
|
7546
7573
|
});
|
|
7547
|
-
const workflows = yield*
|
|
7548
|
-
|
|
7574
|
+
const [workflows, actions, own] = yield* Effect.all([
|
|
7575
|
+
listed(path.join(".github", "workflows"), false),
|
|
7576
|
+
listed(path.join(".github", "actions"), true),
|
|
7577
|
+
actionFile("")
|
|
7578
|
+
], { concurrency: "unbounded" });
|
|
7549
7579
|
const pending = [
|
|
7550
7580
|
...workflows.filter((file) => /\.ya?ml$/u.test(file)),
|
|
7551
7581
|
...actions.filter((file) => /^action\.ya?ml$/u.test(path.basename(file))),
|
|
7552
|
-
...Option.toArray(
|
|
7582
|
+
...Option.toArray(own)
|
|
7553
7583
|
];
|
|
7554
7584
|
const seen = /* @__PURE__ */ new Set();
|
|
7555
7585
|
const files = [];
|
|
@@ -7874,7 +7904,7 @@ const discover$4 = Effect.fn("GitHubActions.discover")(function* (dir) {
|
|
|
7874
7904
|
".github",
|
|
7875
7905
|
"action.yml",
|
|
7876
7906
|
"action.yaml"
|
|
7877
|
-
], exists)).length === 0) return [];
|
|
7907
|
+
], exists, { concurrency: "unbounded" })).length === 0) return [];
|
|
7878
7908
|
const origin = yield* exec.stdout({
|
|
7879
7909
|
command: "git",
|
|
7880
7910
|
args: [
|
|
@@ -7889,7 +7919,7 @@ const discover$4 = Effect.fn("GitHubActions.discover")(function* (dir) {
|
|
|
7889
7919
|
});
|
|
7890
7920
|
// src/process/on-path.ts
|
|
7891
7921
|
const executable = (file) => Effect.promise(async () => await access(file, constants.X_OK).then(() => true, () => false));
|
|
7892
|
-
const onPath = (command) => Effect.forEach((process.env["PATH"] ?? "").split(path.delimiter).filter((dir) => dir !== ""), (dir) => executable(path.join(dir, command))).pipe(Effect.map((found) => found.includes(true)));
|
|
7922
|
+
const onPath = (command) => Effect.forEach((process.env["PATH"] ?? "").split(path.delimiter).filter((dir) => dir !== ""), (dir) => executable(path.join(dir, command)), { concurrency: "unbounded" }).pipe(Effect.map((found) => found.includes(true)));
|
|
7893
7923
|
// src/process/Sudo.ts
|
|
7894
7924
|
var Sudo = class extends Context.Service()("upup/Sudo") {};
|
|
7895
7925
|
const asRoot = (invocation) => [
|
|
@@ -8483,8 +8513,7 @@ const read = Effect.fn("bundles.read")(function* (bundle, arch) {
|
|
|
8483
8513
|
const short = nonEmpty(info.value.CFBundleShortVersionString);
|
|
8484
8514
|
const build = nonEmpty(info.value.CFBundleVersion);
|
|
8485
8515
|
const executable = nonEmpty(info.value.CFBundleExecutable);
|
|
8486
|
-
const sparkle = yield* sparkleKeysOf(bundle, info.value);
|
|
8487
|
-
const source = yield* sourceOf(bundle, bundleId, nonEmpty(info.value.SUFeedURL), arch);
|
|
8516
|
+
const [sparkle, source] = yield* Effect.all([sparkleKeysOf(bundle, info.value), sourceOf(bundle, bundleId, nonEmpty(info.value.SUFeedURL), arch)], { concurrency: "unbounded" });
|
|
8488
8517
|
return Option.some({
|
|
8489
8518
|
path: bundle,
|
|
8490
8519
|
name: path.basename(bundle, ".app"),
|
|
@@ -8497,23 +8526,25 @@ const read = Effect.fn("bundles.read")(function* (bundle, arch) {
|
|
|
8497
8526
|
...plist === void 0 ? {} : { plist }
|
|
8498
8527
|
});
|
|
8499
8528
|
});
|
|
8500
|
-
const
|
|
8529
|
+
const isApp = (entry) => entry.endsWith(".app");
|
|
8530
|
+
const isLeftover = (entry) => entry.endsWith(".app.upup-old");
|
|
8531
|
+
const wanted$1 = (entry) => isApp(entry) || isLeftover(entry);
|
|
8532
|
+
const walk = Effect.fn("bundles.walk")(function* (roots) {
|
|
8501
8533
|
const fs = yield* FileSystem.FileSystem;
|
|
8502
8534
|
const entries = (dir) => fs.readDirectory(dir).pipe(Effect.orElseSucceed(() => []), Effect.map((names) => names.toSorted((left, right) => left.localeCompare(right)).map((name) => path.join(dir, name))));
|
|
8503
8535
|
const isLink = (entry) => fs.readLink(entry).pipe(Effect.isSuccess);
|
|
8504
8536
|
const isDirectory = (entry) => fs.stat(entry).pipe(Effect.map((info) => info.type === "Directory"), Effect.orElseSucceed(() => false));
|
|
8505
|
-
const
|
|
8506
|
-
|
|
8507
|
-
if (yield* isLink(entry))
|
|
8508
|
-
if (wanted(entry))
|
|
8509
|
-
|
|
8510
|
-
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
|
|
8537
|
+
const nestedIn = (folder) => entries(folder).pipe(Effect.flatMap((listed) => Effect.filter(listed.filter(wanted$1), (nested) => Effect.map(isLink(nested), (link) => !link), { concurrency: "unbounded" })));
|
|
8538
|
+
const walked = (yield* Effect.forEach(roots, (root) => entries(root).pipe(Effect.flatMap((listed) => Effect.forEach(listed, (entry) => Effect.gen(function* () {
|
|
8539
|
+
if (yield* isLink(entry)) return [];
|
|
8540
|
+
if (wanted$1(entry)) return [entry];
|
|
8541
|
+
return !/\.(?:app|localized|upup-old|upup-new)$/u.test(entry) && (yield* isDirectory(entry)) ? yield* nestedIn(entry) : [];
|
|
8542
|
+
}), { concurrency: "unbounded" })), Effect.map((listed) => listed.flat())), { concurrency: "unbounded" })).flat();
|
|
8543
|
+
return {
|
|
8544
|
+
apps: walked.filter(isApp),
|
|
8545
|
+
leftovers: walked.filter(isLeftover)
|
|
8546
|
+
};
|
|
8514
8547
|
});
|
|
8515
|
-
const paths = (roots) => walk(roots, (entry) => entry.endsWith(".app"));
|
|
8516
|
-
const leftovers = (roots) => walk(roots, (entry) => entry.endsWith(".app.upup-old"));
|
|
8517
8548
|
// src/apps/running.ts
|
|
8518
8549
|
const command$4 = (name, args) => ({
|
|
8519
8550
|
command: name,
|
|
@@ -8576,7 +8607,7 @@ const command$3 = (name, args) => ({
|
|
|
8576
8607
|
});
|
|
8577
8608
|
const host = Effect.gen(function* () {
|
|
8578
8609
|
const exec = yield* Exec;
|
|
8579
|
-
const [arm64, os] = yield* Effect.all([exec.run(command$3("sysctl", ["-n", "hw.optional.arm64"])).pipe(Effect.map((output) => output.exitCode === 0 && output.stdout.trim() === "1"), Effect.orElseSucceed(() => false)), exec.stdout(command$3("sw_vers", ["-productVersion"])).pipe(Effect.map((text) => text.trim()))], { concurrency:
|
|
8610
|
+
const [arm64, os] = yield* Effect.all([exec.run(command$3("sysctl", ["-n", "hw.optional.arm64"])).pipe(Effect.map((output) => output.exitCode === 0 && output.stdout.trim() === "1"), Effect.orElseSucceed(() => false)), exec.stdout(command$3("sw_vers", ["-productVersion"])).pipe(Effect.map((text) => text.trim()))], { concurrency: "unbounded" });
|
|
8580
8611
|
return {
|
|
8581
8612
|
arch: arm64 ? "arm64" : "x86_64",
|
|
8582
8613
|
os
|
|
@@ -8654,7 +8685,7 @@ const stage = Effect.fn("install.stage")(function* (client, wanted) {
|
|
|
8654
8685
|
const found = (yield* Effect.forEach(candidates, (candidate) => readInfo(candidate).pipe(Effect.map((info) => ({
|
|
8655
8686
|
path: candidate,
|
|
8656
8687
|
info
|
|
8657
|
-
}))))).find(({ info }) => Option.isSome(info) && info.value.CFBundleIdentifier === wanted.bundleId);
|
|
8688
|
+
}))), { concurrency: 4 })).find(({ info }) => Option.isSome(info) && info.value.CFBundleIdentifier === wanted.bundleId);
|
|
8658
8689
|
if (found === void 0 || Option.isNone(found.info)) return yield* refused(`its download holds no app with the bundle ID ${wanted.bundleId}`);
|
|
8659
8690
|
const app = found.path;
|
|
8660
8691
|
const info = found.info.value;
|
|
@@ -8673,7 +8704,7 @@ const stage = Effect.fn("install.stage")(function* (client, wanted) {
|
|
|
8673
8704
|
])).pipe(Effect.mapError((error) => refused(`codesign failed: ${error.output.trim()}`)), Effect.flatMap((output) => {
|
|
8674
8705
|
const hash = /^CDHash=(?<hash>[0-9a-f]+)$/mu.exec(output.stderr)?.groups?.["hash"];
|
|
8675
8706
|
return hash === void 0 ? Effect.fail(unsigned(output.stderr.trim())) : Effect.succeed(hash);
|
|
8676
|
-
}))).pipe(Effect.map((hashes) => `${requirement(wanted.bundleId, wanted.team)} and info [CFBundleShortVersionString] = "${wanted.version.replaceAll(/["\\]/gu, "\\$&")}" and (${hashes.map((hash) => `cdhash H"${hash}"`).join(" or ")})`));
|
|
8707
|
+
})), { concurrency: 2 }).pipe(Effect.map((hashes) => `${requirement(wanted.bundleId, wanted.team)} and info [CFBundleShortVersionString] = "${wanted.version.replaceAll(/["\\]/gu, "\\$&")}" and (${hashes.map((hash) => `cdhash H"${hash}"`).join(" or ")})`));
|
|
8677
8708
|
const signed = yield* exec.run(command$2("codesign", [
|
|
8678
8709
|
"--verify",
|
|
8679
8710
|
"--deep",
|
|
@@ -9156,16 +9187,27 @@ const makeWith = (options) => Effect.gen(function* () {
|
|
|
9156
9187
|
}
|
|
9157
9188
|
};
|
|
9158
9189
|
});
|
|
9190
|
+
const leftoverNotice = (old) => {
|
|
9191
|
+
const app = old.slice(0, -9);
|
|
9192
|
+
return fs.exists(app).pipe(Effect.orElseSucceed(() => true), Effect.map((present) => ({ message: present ? `${old} is the old copy of ${path.basename(app)} that an update left behind; move it to the Trash` : `${old} is ${path.basename(app)} from before an update that did not finish; rename it back to ${path.basename(app)}` })));
|
|
9193
|
+
};
|
|
9194
|
+
const scan = Effect.gen(function* () {
|
|
9195
|
+
const [here, walked] = yield* Effect.all([host, walk(options.roots)], { concurrency: "unbounded" });
|
|
9196
|
+
const [bundles, left] = yield* Effect.all([Effect.forEach(walked.apps, (app) => read(app, here.arch), { concurrency: inFlight }), Effect.forEach(walked.leftovers, leftoverNotice, { concurrency: "unbounded" })], { concurrency: "unbounded" });
|
|
9197
|
+
return {
|
|
9198
|
+
here,
|
|
9199
|
+
found: bundles.flatMap((bundle) => Option.toArray(bundle)),
|
|
9200
|
+
left
|
|
9201
|
+
};
|
|
9202
|
+
});
|
|
9159
9203
|
const list = Effect.gen(function* () {
|
|
9160
|
-
const owners = yield* Effect.result(casks);
|
|
9204
|
+
const [owners, { here, found, left }] = yield* Effect.all([Effect.result(casks), scan], { concurrency: "unbounded" });
|
|
9161
9205
|
if (Result.isFailure(owners)) return {
|
|
9162
9206
|
packages: [],
|
|
9163
9207
|
notices: [{ message: `upup lists no apps while it cannot read which apps Homebrew installed: ${describeError(owners.failure)}` }]
|
|
9164
9208
|
};
|
|
9165
|
-
const here = yield* host;
|
|
9166
9209
|
const locale = yield* Effect.cached(country);
|
|
9167
9210
|
const caskOf = new Map(owners.success.flatMap((cask) => caskApps(cask).map((app) => [app, cask])));
|
|
9168
|
-
const found = (yield* Effect.forEach(yield* paths(options.roots), (app) => read(app, here.arch), { concurrency: inFlight })).flatMap((bundle) => Option.toArray(bundle));
|
|
9169
9211
|
const ids = /* @__PURE__ */ new Set();
|
|
9170
9212
|
const kept = found.filter((bundle) => {
|
|
9171
9213
|
const cask = caskOf.get(path.basename(bundle.path));
|
|
@@ -9193,13 +9235,9 @@ const makeWith = (options) => Effect.gen(function* () {
|
|
|
9193
9235
|
here,
|
|
9194
9236
|
rows: new Map(all.map((row) => [row.pkg.id, row.listed]))
|
|
9195
9237
|
});
|
|
9196
|
-
const leftovers$1 = yield* Effect.forEach(yield* leftovers(options.roots), (old) => {
|
|
9197
|
-
const app = old.slice(0, -9);
|
|
9198
|
-
return fs.exists(app).pipe(Effect.orElseSucceed(() => true), Effect.map((present) => ({ message: present ? `${old} is the old copy of ${path.basename(app)} that an update left behind; move it to the Trash` : `${old} is ${path.basename(app)} from before an update that did not finish; rename it back to ${path.basename(app)}` })));
|
|
9199
|
-
});
|
|
9200
9238
|
return {
|
|
9201
9239
|
packages: all.map((row) => row.pkg),
|
|
9202
|
-
notices: [...all.flatMap((row) => row.notice), ...
|
|
9240
|
+
notices: [...all.flatMap((row) => row.notice), ...left]
|
|
9203
9241
|
};
|
|
9204
9242
|
}).pipe(Effect.withSpan("Apps.list"), provide);
|
|
9205
9243
|
const observe = Effect.fn("Apps.observe")(function* (pkg) {
|
|
@@ -9234,7 +9272,7 @@ const makeWith = (options) => Effect.gen(function* () {
|
|
|
9234
9272
|
const ids = yield* Effect.forEach(paths, (app) => readInfo(app).pipe(Effect.flatMap((info) => Option.match(info, {
|
|
9235
9273
|
onNone: () => Effect.fail(new Unsupported({ reason: `upup could not read ${app}` })),
|
|
9236
9274
|
onSome: (found) => Effect.succeed(found.CFBundleIdentifier)
|
|
9237
|
-
}))));
|
|
9275
|
+
}))), { concurrency: inFlight });
|
|
9238
9276
|
const found = {
|
|
9239
9277
|
paths,
|
|
9240
9278
|
ids: new Set(ids)
|
|
@@ -9515,7 +9553,7 @@ const nestedDirs = Effect.fn("nestedDirs")(function* (dir, names) {
|
|
|
9515
9553
|
args,
|
|
9516
9554
|
cwd: dir
|
|
9517
9555
|
}).pipe(Effect.orElseSucceed(() => ""));
|
|
9518
|
-
const [prefix, listed] = yield* Effect.all([git("rev-parse", "--show-prefix"), git("ls-files", "-z", "--cached", "--others", "--exclude-standard", "--", ...names.map((name) => `:(glob)**/${name}`))], { concurrency:
|
|
9556
|
+
const [prefix, listed] = yield* Effect.all([git("rev-parse", "--show-prefix"), git("ls-files", "-z", "--cached", "--others", "--exclude-standard", "--", ...names.map((name) => `:(glob)**/${name}`))], { concurrency: "unbounded" });
|
|
9519
9557
|
const files = listed.split("\0").filter((file) => {
|
|
9520
9558
|
const folders = file.split("/").slice(0, -1);
|
|
9521
9559
|
return folders.length > 0 && !folders.includes("node_modules") && !(path.basename(file) === "go.mod" && ignoredByGo(folders));
|
|
@@ -9542,8 +9580,7 @@ const failing = (name, error) => ({
|
|
|
9542
9580
|
observe: () => Effect.succeedNone
|
|
9543
9581
|
});
|
|
9544
9582
|
const locateAll = Effect.fn("locateAll")(function* (dir, nested, manifest, locate) {
|
|
9545
|
-
const own = yield* locate(dir);
|
|
9546
|
-
const below = yield* Effect.forEach(nested, (from) => Effect.map(Effect.result(locate(from)), (result) => [from, result]), { concurrency: 8 });
|
|
9583
|
+
const [own, below] = yield* Effect.all([locate(dir), Effect.forEach(nested, (from) => Effect.map(Effect.result(locate(from)), (result) => [from, result]), { concurrency: 8 })], { concurrency: "unbounded" });
|
|
9547
9584
|
const found = /* @__PURE__ */ new Map();
|
|
9548
9585
|
const claimed = /* @__PURE__ */ new Map();
|
|
9549
9586
|
const failed = [];
|
|
@@ -9706,7 +9743,7 @@ const make$9 = (root, place = "") => Effect.gen(function* () {
|
|
|
9706
9743
|
const entries = (manifest) => manifestOf(manifest).pipe(Effect.map((parsed) => entriesOf(manifest, parsed)));
|
|
9707
9744
|
const workspace = Effect.gen(function* () {
|
|
9708
9745
|
const resolved = resolvedByMember(root, yield* metadata);
|
|
9709
|
-
const manifests = yield* Effect.forEach(/* @__PURE__ */ new Set(["Cargo.toml", ...resolved.keys()]), (manifest) => manifestOf(manifest).pipe(Effect.map((parsed) => [manifest, parsed])));
|
|
9746
|
+
const manifests = yield* Effect.forEach(/* @__PURE__ */ new Set(["Cargo.toml", ...resolved.keys()]), (manifest) => manifestOf(manifest).pipe(Effect.map((parsed) => [manifest, parsed])), { concurrency: 8 });
|
|
9710
9747
|
const inheritors = (key) => manifests.flatMap(([manifest, parsed]) => resolved.has(manifest) && inheritedKeys(parsed).includes(key) ? [manifest] : []);
|
|
9711
9748
|
return {
|
|
9712
9749
|
resolved,
|
|
@@ -10011,9 +10048,11 @@ const make$8 = Effect.gen(function* () {
|
|
|
10011
10048
|
});
|
|
10012
10049
|
const isPlainExecutable = Effect.fn("GoInstall.isPlainExecutable")(function* (dir, file) {
|
|
10013
10050
|
const binary = path.join(dir, file);
|
|
10014
|
-
const info = yield*
|
|
10015
|
-
|
|
10016
|
-
|
|
10051
|
+
const [info, real, realDir] = yield* Effect.all([
|
|
10052
|
+
fs.stat(binary).pipe(Effect.mapError(fileFailed("stat", binary))),
|
|
10053
|
+
fs.realPath(binary).pipe(Effect.mapError(fileFailed("resolve", binary))),
|
|
10054
|
+
fs.realPath(dir).pipe(Effect.mapError(fileFailed("resolve", dir)))
|
|
10055
|
+
], { concurrency: "unbounded" });
|
|
10017
10056
|
return info.type === "File" && (info.mode & 73) !== 0 && real === path.join(realDir, file);
|
|
10018
10057
|
});
|
|
10019
10058
|
const latest = Effect.fn("GoInstall.latest")(function* (modules) {
|
|
@@ -10172,8 +10211,7 @@ const make$7 = (root, moduleDir, place = "", local = /* @__PURE__ */ new Set())
|
|
|
10172
10211
|
]);
|
|
10173
10212
|
const origin = exec.stdout(env).pipe(Effect.flatMap(decodeGoJson(GoProxyEnv, commandLine(env))), Effect.map(withGoOrigin));
|
|
10174
10213
|
const list = Effect.gen(function* () {
|
|
10175
|
-
const direct = yield* requirements;
|
|
10176
|
-
const located = yield* origin;
|
|
10214
|
+
const [direct, located] = yield* Effect.all([requirements, origin], { concurrency: "unbounded" });
|
|
10177
10215
|
const entries = yield* selected(direct.map((requirement) => requirement.Path), true);
|
|
10178
10216
|
const notices = [];
|
|
10179
10217
|
return {
|
|
@@ -10235,17 +10273,17 @@ const locate$1 = Effect.fn("GoModule.locate")(function* (dir) {
|
|
|
10235
10273
|
const discover$2 = Effect.fn("GoModule.discover")(function* (dir, nested = []) {
|
|
10236
10274
|
const exec = yield* Exec;
|
|
10237
10275
|
const { found, failed } = yield* locateAll(dir, nested, "go.mod", locate$1);
|
|
10238
|
-
const
|
|
10239
|
-
|
|
10240
|
-
|
|
10241
|
-
if (!work) {
|
|
10242
|
-
listed.add(root);
|
|
10243
|
-
return [{
|
|
10276
|
+
const works = yield* Effect.forEach(found, ({ root, work, claimed }) => Effect.gen(function* () {
|
|
10277
|
+
if (!work) return {
|
|
10278
|
+
modules: [{
|
|
10244
10279
|
root,
|
|
10245
10280
|
moduleDir: root,
|
|
10246
10281
|
local: /* @__PURE__ */ new Set()
|
|
10247
|
-
}]
|
|
10248
|
-
|
|
10282
|
+
}],
|
|
10283
|
+
failed: [],
|
|
10284
|
+
covered: [root]
|
|
10285
|
+
};
|
|
10286
|
+
const covered = [];
|
|
10249
10287
|
const place = placeOf$1(dir, root);
|
|
10250
10288
|
const scanned = yield* Effect.gen(function* () {
|
|
10251
10289
|
const edit = {
|
|
@@ -10259,7 +10297,7 @@ const discover$2 = Effect.fn("GoModule.discover")(function* (dir, nested = []) {
|
|
|
10259
10297
|
};
|
|
10260
10298
|
const file = yield* exec.stdout(edit).pipe(Effect.flatMap(decodeGoJson(WorkFile, commandLine(edit))));
|
|
10261
10299
|
const used = (file.Use ?? []).map((use) => path.resolve(root, use.DiskPath));
|
|
10262
|
-
|
|
10300
|
+
covered.push(...used);
|
|
10263
10301
|
const paths = yield* Effect.forEach(used, (moduleDir) => Effect.gen(function* () {
|
|
10264
10302
|
const mod = yield* readModFile(exec, moduleDir);
|
|
10265
10303
|
if (mod.Module === void 0) return yield* new OutputMalformed({
|
|
@@ -10275,20 +10313,27 @@ const discover$2 = Effect.fn("GoModule.discover")(function* (dir, nested = []) {
|
|
|
10275
10313
|
local
|
|
10276
10314
|
})).filter(({ moduleDir }) => place === "" || placeOf$1(dir, moduleDir) !== "");
|
|
10277
10315
|
}).pipe(Effect.result);
|
|
10278
|
-
if (Result.isSuccess(scanned)) return
|
|
10279
|
-
|
|
10280
|
-
|
|
10281
|
-
|
|
10282
|
-
|
|
10316
|
+
if (Result.isSuccess(scanned)) return {
|
|
10317
|
+
modules: scanned.success,
|
|
10318
|
+
failed: [],
|
|
10319
|
+
covered
|
|
10320
|
+
};
|
|
10321
|
+
return {
|
|
10322
|
+
modules: [],
|
|
10323
|
+
failed: [failing(path.join(place, "go.work"), scanned.failure)],
|
|
10324
|
+
covered: [...covered, ...claimed]
|
|
10325
|
+
};
|
|
10326
|
+
}), { concurrency: 4 });
|
|
10327
|
+
const listed = new Set(works.flatMap((work) => work.covered));
|
|
10283
10328
|
const outside = nested.flatMap((moduleDir) => listed.has(moduleDir) ? [] : [{
|
|
10284
10329
|
root: moduleDir,
|
|
10285
10330
|
moduleDir,
|
|
10286
10331
|
local: /* @__PURE__ */ new Set()
|
|
10287
10332
|
}]);
|
|
10288
|
-
const providers = yield* Effect.forEach([...
|
|
10333
|
+
const providers = yield* Effect.forEach([...works.flatMap(({ modules }) => modules), ...outside], ({ root, moduleDir, local }) => make$7(root, moduleDir, placeOf$1(dir, root), local));
|
|
10289
10334
|
return [
|
|
10290
10335
|
...failed,
|
|
10291
|
-
...
|
|
10336
|
+
...works.flatMap((work) => work.failed),
|
|
10292
10337
|
...providers
|
|
10293
10338
|
];
|
|
10294
10339
|
});
|
|
@@ -10296,24 +10341,23 @@ const discover$2 = Effect.fn("GoModule.discover")(function* (dir, nested = []) {
|
|
|
10296
10341
|
var ProviderSource = class extends Context.Service()("upup/ProviderSource") {};
|
|
10297
10342
|
// src/node/release-history.ts
|
|
10298
10343
|
const minutesPerDay = 1440;
|
|
10299
|
-
const firstPnpmMajorWithDefaultReleaseAge = 11;
|
|
10300
10344
|
const gateSettings = {
|
|
10301
10345
|
pnpm: {
|
|
10302
10346
|
age: "minimumReleaseAge",
|
|
10303
10347
|
exclude: "minimumReleaseAgeExclude",
|
|
10304
10348
|
unit: 1,
|
|
10305
|
-
unset:
|
|
10349
|
+
unset: minutesPerDay
|
|
10306
10350
|
},
|
|
10307
10351
|
npm: {
|
|
10308
10352
|
age: "min-release-age",
|
|
10309
10353
|
exclude: "min-release-age-exclude",
|
|
10310
10354
|
unit: minutesPerDay,
|
|
10311
|
-
unset:
|
|
10355
|
+
unset: 0
|
|
10312
10356
|
}
|
|
10313
10357
|
};
|
|
10314
|
-
const releaseGate = (manager,
|
|
10358
|
+
const releaseGate = (manager, config) => {
|
|
10315
10359
|
const settings = gateSettings[manager];
|
|
10316
|
-
const minutes = Number(config[settings.age] ?? settings.unset
|
|
10360
|
+
const minutes = Number(config[settings.age] ?? settings.unset) * settings.unit;
|
|
10317
10361
|
return {
|
|
10318
10362
|
minutes: Number.isFinite(minutes) && minutes > 0 ? minutes : 0,
|
|
10319
10363
|
exclude: [config[settings.exclude] ?? []].flat().filter((pattern) => typeof pattern === "string")
|
|
@@ -10399,8 +10443,7 @@ const releaseOffers = Effect.fn("releaseOffers")(function* (pins, manager, run,
|
|
|
10399
10443
|
const reads = yield* Effect.result(Effect.forEach(artifacts, read, { concurrency: 8 }));
|
|
10400
10444
|
const histories = new Map(Result.isSuccess(reads) ? reads.success : []);
|
|
10401
10445
|
const notices = Result.isFailure(reads) ? [{ message: `release histories could not be read, so upup offers nothing: ${describeError(reads.failure)}` }] : [];
|
|
10402
|
-
const
|
|
10403
|
-
const gate = releaseGate(manager, version.trim(), config);
|
|
10446
|
+
const gate = releaseGate(manager, config);
|
|
10404
10447
|
const offer = (pin) => {
|
|
10405
10448
|
const history = histories.get(pin.artifact);
|
|
10406
10449
|
if (history === void 0) return Result.succeed(void 0);
|
|
@@ -10511,7 +10554,7 @@ const makeGlobal = (spec) => Effect.gen(function* () {
|
|
|
10511
10554
|
installed,
|
|
10512
10555
|
latest,
|
|
10513
10556
|
readNpmConfig(spec.config, "/").pipe(Effect.provideService(Exec, exec))
|
|
10514
|
-
], { concurrency:
|
|
10557
|
+
], { concurrency: "unbounded" });
|
|
10515
10558
|
const { offer, notices: unread } = yield* releaseOffers(packages.filter((pkg) => isPrerelease(pkg.current)), spec.config, (args) => ({
|
|
10516
10559
|
command: spec.config,
|
|
10517
10560
|
args,
|
|
@@ -10742,9 +10785,10 @@ const scan = Effect.fn("NodePins.scan")(function* (root, dir, nested) {
|
|
|
10742
10785
|
const fs = yield* FileSystem.FileSystem;
|
|
10743
10786
|
const read = (file) => readText(path.join(root, file));
|
|
10744
10787
|
const exists = (file) => fs.exists(path.join(root, file)).pipe(Effect.mapError(fileFailed("stat", path.join(root, file))));
|
|
10745
|
-
const
|
|
10746
|
-
const
|
|
10747
|
-
const
|
|
10788
|
+
const [workflows, listed] = yield* Effect.all([workflowFiles(root), versionFilesOf(root, dir, nested)], { concurrency: "unbounded" });
|
|
10789
|
+
const steps = workflows.flatMap(({ file, text }) => stepPins(file, text) ?? []);
|
|
10790
|
+
const versioned = yield* Effect.filter(listed, exists, { concurrency: "unbounded" });
|
|
10791
|
+
const files = yield* Effect.forEach(versioned.toSorted(), (file) => Effect.map(read(file), (text) => filePin(file, text)), { concurrency: 8 });
|
|
10748
10792
|
return [...steps, ...files.flat()];
|
|
10749
10793
|
});
|
|
10750
10794
|
const make$6 = (root, dir = root, nested = []) => Effect.gen(function* () {
|
|
@@ -11007,26 +11051,31 @@ const make$5 = (root, manager, place = "", claimed = []) => Effect.gen(function*
|
|
|
11007
11051
|
const unlocked = claimed.filter((dir) => !lockedDirs.has(path.normalize(dir))).toSorted((a, b) => a.localeCompare(b));
|
|
11008
11052
|
if (unlocked.length > 0) notices.push({ message: `not listed: ${unlocked.join(", ")} (not in ${lockfile})` });
|
|
11009
11053
|
const catalogLocked = /* @__PURE__ */ new Map();
|
|
11010
|
-
|
|
11054
|
+
const memberManifests = yield* Effect.forEach(members.toSorted((a, b) => a.localeCompare(b)), (member) => {
|
|
11011
11055
|
const memberDir = member === "." ? "" : member;
|
|
11012
11056
|
const manifest = path.join(memberDir, "package.json");
|
|
11013
|
-
|
|
11014
|
-
|
|
11015
|
-
|
|
11016
|
-
|
|
11017
|
-
|
|
11018
|
-
|
|
11019
|
-
|
|
11020
|
-
|
|
11021
|
-
|
|
11022
|
-
|
|
11023
|
-
|
|
11024
|
-
|
|
11025
|
-
|
|
11026
|
-
|
|
11027
|
-
|
|
11028
|
-
|
|
11057
|
+
return Effect.map(readJson(Manifest, path.join(root, manifest)), (fields) => ({
|
|
11058
|
+
member,
|
|
11059
|
+
memberDir,
|
|
11060
|
+
manifest,
|
|
11061
|
+
fields
|
|
11062
|
+
}));
|
|
11063
|
+
}, { concurrency: 8 });
|
|
11064
|
+
for (const { member, memberDir, manifest, fields } of memberManifests) for (const section of sections) for (const [name, spec] of Object.entries(fields[section] ?? {})) {
|
|
11065
|
+
const resolved = Option.match(pnpm, {
|
|
11066
|
+
onSome: (lock) => resolvedVersion(lock.importers?.[member]?.[section]?.[name]?.version),
|
|
11067
|
+
onNone: () => Option.match(npm, {
|
|
11068
|
+
onSome: (lock) => lock.packages[path.join(memberDir, "node_modules", name)]?.version ?? lock.packages[path.join("node_modules", name)]?.version,
|
|
11069
|
+
onNone: () => void 0
|
|
11070
|
+
})
|
|
11071
|
+
});
|
|
11072
|
+
if (spec.startsWith("catalog:")) {
|
|
11073
|
+
const catalog = spec.slice(8) || "default";
|
|
11074
|
+
const locked = catalogLocked.get(catalog) ?? /* @__PURE__ */ new Map();
|
|
11075
|
+
if (resolved !== void 0 && !locked.has(name)) catalogLocked.set(catalog, locked.set(name, resolved));
|
|
11076
|
+
continue;
|
|
11029
11077
|
}
|
|
11078
|
+
add(manifest, section, [section, name], name, spec, resolved);
|
|
11030
11079
|
}
|
|
11031
11080
|
if (Option.isSome(pnpm) && (yield* exists(path.join(root, "pnpm-workspace.yaml")))) {
|
|
11032
11081
|
const workspacePath = path.join(root, "pnpm-workspace.yaml");
|
|
@@ -11096,7 +11145,7 @@ const make$5 = (root, manager, place = "", claimed = []) => Effect.gen(function*
|
|
|
11096
11145
|
};
|
|
11097
11146
|
}).pipe(Effect.provideService(FileSystem.FileSystem, fs));
|
|
11098
11147
|
const list = Effect.gen(function* () {
|
|
11099
|
-
const [{ declared, notices }, config] = yield* Effect.all([declarations, readNpmConfig(manager, root).pipe(Effect.provideService(Exec, exec))], { concurrency:
|
|
11148
|
+
const [{ declared, notices }, config] = yield* Effect.all([declarations, readNpmConfig(manager, root).pipe(Effect.provideService(Exec, exec))], { concurrency: "unbounded" });
|
|
11100
11149
|
const origin = withNpmOrigin(npmRegistries(config));
|
|
11101
11150
|
const { offer, notices: unread } = yield* releaseOffers(declared.flatMap((entry) => entry.held === true ? [] : [entry.pkg]), manager, run, config).pipe(Effect.provideService(Exec, exec));
|
|
11102
11151
|
return {
|
|
@@ -11302,7 +11351,7 @@ const discover = Effect.fn("NodeProject.discover")(function* (dir, nested = [])
|
|
|
11302
11351
|
const installed = yield* fs.exists(lockfile).pipe(Effect.mapError(fileFailed("stat", lockfile)));
|
|
11303
11352
|
if (place !== "" && !installed) unlisted.push(`${place} (no ${lockfiles[manager]} yet)`);
|
|
11304
11353
|
else {
|
|
11305
|
-
const manifests = yield* Effect.filter(claimed, (from) => fs.exists(path.join(from, "package.json")).pipe(Effect.mapError(fileFailed("stat", from))));
|
|
11354
|
+
const manifests = yield* Effect.filter(claimed, (from) => fs.exists(path.join(from, "package.json")).pipe(Effect.mapError(fileFailed("stat", from))), { concurrency: "unbounded" });
|
|
11306
11355
|
providers.push(yield* make$5(root, manager, place, manifests.map((from) => path.relative(root, from))));
|
|
11307
11356
|
}
|
|
11308
11357
|
}
|
|
@@ -11401,10 +11450,13 @@ const make$4 = Effect.gen(function* () {
|
|
|
11401
11450
|
});
|
|
11402
11451
|
const list = Effect.gen(function* () {
|
|
11403
11452
|
const found = yield* configured;
|
|
11453
|
+
const offered = yield* Effect.forEach(found.packages, (pkg) => Effect.map(Effect.result(offer(pkg)), (target) => ({
|
|
11454
|
+
pkg,
|
|
11455
|
+
target
|
|
11456
|
+
})), { concurrency: 4 });
|
|
11404
11457
|
const notices = [...found.notices];
|
|
11405
11458
|
return {
|
|
11406
|
-
packages:
|
|
11407
|
-
const target = yield* Effect.result(offer(pkg));
|
|
11459
|
+
packages: offered.map(({ pkg, target }) => {
|
|
11408
11460
|
if (Result.isFailure(target)) {
|
|
11409
11461
|
notices.push({
|
|
11410
11462
|
rowKey: rowKey(pkg),
|
|
@@ -11413,7 +11465,7 @@ const make$4 = Effect.gen(function* () {
|
|
|
11413
11465
|
return pkg;
|
|
11414
11466
|
}
|
|
11415
11467
|
return target.success === void 0 ? pkg : withTarget(pkg, target.success);
|
|
11416
|
-
})
|
|
11468
|
+
}),
|
|
11417
11469
|
notices
|
|
11418
11470
|
};
|
|
11419
11471
|
}).pipe(Effect.withSpan("VpEnv.list"));
|
|
@@ -11545,7 +11597,7 @@ const make$2 = Effect.gen(function* () {
|
|
|
11545
11597
|
exec.stdout(command$1("apt", ["list", "--upgradable"])).pipe(Effect.map(parseUpgradable)),
|
|
11546
11598
|
exec.stdout(command$1("apt-mark", ["showhold"])).pipe(Effect.map((text) => new Set(text.split("\n").filter((line) => line !== "")))),
|
|
11547
11599
|
restart
|
|
11548
|
-
], { concurrency:
|
|
11600
|
+
], { concurrency: "unbounded" });
|
|
11549
11601
|
const packages = upgradable.map((entry) => {
|
|
11550
11602
|
const pkg = packageOf(entry, arch);
|
|
11551
11603
|
return holds.has(entry.name) || holds.has(pkg.id) ? pkg : withTarget(pkg, entry.version);
|
|
@@ -11690,7 +11742,7 @@ const make$1 = Effect.gen(function* () {
|
|
|
11690
11742
|
running,
|
|
11691
11743
|
scan(args),
|
|
11692
11744
|
Ref.get(installed)
|
|
11693
|
-
], { concurrency:
|
|
11745
|
+
], { concurrency: "unbounded" });
|
|
11694
11746
|
return {
|
|
11695
11747
|
packages: packagesOf$1(version, offers.filter((offer) => !done.has(offer.label))),
|
|
11696
11748
|
done
|
|
@@ -11775,7 +11827,7 @@ const make = Effect.gen(function* () {
|
|
|
11775
11827
|
"list",
|
|
11776
11828
|
"--outdated",
|
|
11777
11829
|
"--show-python"
|
|
11778
|
-
])).pipe(Effect.map(parseTools))], { concurrency:
|
|
11830
|
+
])).pipe(Effect.map(parseTools))], { concurrency: "unbounded" });
|
|
11779
11831
|
const targets = new Map(outdated.flatMap((tool) => tool.fromPyPI && tool.latest !== void 0 ? [[tool.pkg.id, tool.latest]] : []));
|
|
11780
11832
|
const index = privatePypiIndex();
|
|
11781
11833
|
return {
|
|
@@ -11824,8 +11876,8 @@ const system$1 = [
|
|
|
11824
11876
|
["go", make$8],
|
|
11825
11877
|
["uv", make]
|
|
11826
11878
|
];
|
|
11827
|
-
const available = (entries) => Effect.filter([...new Set(entries.map(([command]) => command))], onPath).pipe(Effect.map((found) => entries.filter(([command]) => found.includes(command))));
|
|
11828
|
-
const systemProviders = available(system$1).pipe(Effect.flatMap((found) => Effect.forEach(found, ([, make]) => make)));
|
|
11879
|
+
const available = (entries) => Effect.filter([...new Set(entries.map(([command]) => command))], onPath, { concurrency: "unbounded" }).pipe(Effect.map((found) => entries.filter(([command]) => found.includes(command))));
|
|
11880
|
+
const systemProviders = available(system$1).pipe(Effect.flatMap((found) => Effect.forEach(found, ([, make]) => make, { concurrency: "unbounded" })));
|
|
11829
11881
|
const project$1 = [
|
|
11830
11882
|
["go", {
|
|
11831
11883
|
manifests: ["go.mod"],
|
|
@@ -11851,9 +11903,8 @@ const project$1 = [
|
|
|
11851
11903
|
const manifests = project$1.flatMap(([, kind]) => kind.manifests);
|
|
11852
11904
|
const projectProviders = (given) => Effect.gen(function* () {
|
|
11853
11905
|
const dir = yield* (yield* FileSystem.FileSystem).realPath(given).pipe(Effect.orElseSucceed(() => given));
|
|
11854
|
-
const found = yield* available(project$1);
|
|
11855
|
-
|
|
11856
|
-
return (yield* Effect.forEach(found, ([, kind]) => kind.discover(dir, [...new Set(kind.manifests.flatMap(nested))]))).flat();
|
|
11906
|
+
const [found, nested] = yield* Effect.all([available(project$1), nestedDirs(dir, manifests)], { concurrency: "unbounded" });
|
|
11907
|
+
return (yield* Effect.forEach(found, ([, kind]) => kind.discover(dir, [...new Set(kind.manifests.flatMap(nested))]), { concurrency: "unbounded" })).flat();
|
|
11857
11908
|
});
|
|
11858
11909
|
const layer$3 = Layer.effect(ProviderSource, Effect.gen(function* () {
|
|
11859
11910
|
const context = yield* Effect.context();
|
|
@@ -11963,7 +12014,7 @@ const message = (version) => {
|
|
|
11963
12014
|
};
|
|
11964
12015
|
const lookup$1 = Effect.fn("npm.lookup")(function* (client, wanted) {
|
|
11965
12016
|
const path = wanted.name.replace("/", "%2F");
|
|
11966
|
-
const [packument, downloads] = yield* Effect.all([getJson(client, `https://registry.npmjs.org/${path}`, Packument), getJson(client, `https://api.npmjs.org/downloads/point/last-week/${wanted.name}`, Downloads).pipe(Effect.option)], { concurrency:
|
|
12017
|
+
const [packument, downloads] = yield* Effect.all([getJson(client, `https://registry.npmjs.org/${path}`, Packument), getJson(client, `https://api.npmjs.org/downloads/point/last-week/${wanted.name}`, Downloads).pipe(Effect.option)], { concurrency: "unbounded" });
|
|
11967
12018
|
const versions = packument.versions ?? {};
|
|
11968
12019
|
const latest = packument["dist-tags"]?.latest;
|
|
11969
12020
|
const repository = Predicate.isString(packument.repository) ? packument.repository : packument.repository?.url;
|
|
@@ -12003,7 +12054,7 @@ const repositoryKeys = [
|
|
|
12003
12054
|
"GitHub"
|
|
12004
12055
|
];
|
|
12005
12056
|
const lookup = Effect.fn("pypi.lookup")(function* (client, wanted) {
|
|
12006
|
-
const [project, recent] = yield* Effect.all([getJson(client, `https://pypi.org/pypi/${wanted.name}/json`, Project), getJson(client, `https://pypistats.org/api/packages/${wanted.name.toLowerCase()}/recent`, Recent).pipe(Effect.option)], { concurrency:
|
|
12057
|
+
const [project, recent] = yield* Effect.all([getJson(client, `https://pypi.org/pypi/${wanted.name}/json`, Project), getJson(client, `https://pypistats.org/api/packages/${wanted.name.toLowerCase()}/recent`, Recent).pipe(Effect.option)], { concurrency: "unbounded" });
|
|
12007
12058
|
const urls = project.info.project_urls ?? {};
|
|
12008
12059
|
const repository = repositoryKeys.map((key) => urls[key]).find((url) => url !== void 0);
|
|
12009
12060
|
const homepage = urls["Homepage"] ?? project.info.home_page ?? void 0;
|
|
@@ -12597,12 +12648,10 @@ const layer$1 = (cacheDir) => Layer.succeed(UpdateLog, UpdateLog.of({
|
|
|
12597
12648
|
const directory = path.join(cacheDir, "updates");
|
|
12598
12649
|
const names = (await readdir(directory).catch(() => [])).filter((name) => name.endsWith(".jsonl")).toSorted();
|
|
12599
12650
|
const found = [];
|
|
12600
|
-
|
|
12601
|
-
|
|
12602
|
-
|
|
12603
|
-
|
|
12604
|
-
if (entry?.scope === scope && Date.parse(entry.at) >= since) found.push(entry);
|
|
12605
|
-
}
|
|
12651
|
+
const texts = await Promise.all(names.map(async (name) => await readFile(path.join(directory, name), "utf-8").catch(() => "")));
|
|
12652
|
+
for (const text of texts) for (const line of text.split("\n")) {
|
|
12653
|
+
const entry = Option.getOrUndefined(decodeLine(line));
|
|
12654
|
+
if (entry?.scope === scope && Date.parse(entry.at) >= since) found.push(entry);
|
|
12606
12655
|
}
|
|
12607
12656
|
return found;
|
|
12608
12657
|
})
|
|
@@ -13346,8 +13395,8 @@ const layer = Layer.effect(Session, Effect.gen(function* () {
|
|
|
13346
13395
|
};
|
|
13347
13396
|
});
|
|
13348
13397
|
const recallAll = Effect.gen(function* () {
|
|
13349
|
-
const
|
|
13350
|
-
const logged = yield*
|
|
13398
|
+
const before = yield* SubscriptionRef.get(state);
|
|
13399
|
+
const [found, logged] = yield* Effect.all([earlier(before), fromLog(before)], { concurrency: "unbounded" });
|
|
13351
13400
|
yield* update((latest) => ({
|
|
13352
13401
|
...latest,
|
|
13353
13402
|
installed: {
|
|
@@ -13366,15 +13415,14 @@ const layer = Layer.effect(Session, Effect.gen(function* () {
|
|
|
13366
13415
|
const identity = identityOf(pkg, current.mode);
|
|
13367
13416
|
if (identity !== void 0 && current.audits[jobKey(identity)]?._tag !== "Running") wanted.set(jobKey(identity), identity);
|
|
13368
13417
|
}
|
|
13369
|
-
yield* Effect.forEach(wanted.values(), audits.recall, {
|
|
13370
|
-
concurrency: 4,
|
|
13371
|
-
discard: true
|
|
13372
|
-
});
|
|
13373
13418
|
const offered = packagesOf(current).flatMap((pkg) => {
|
|
13374
13419
|
const identity = pkg.target === void 0 ? void 0 : identityOf(pkg, current.mode);
|
|
13375
13420
|
return identity === void 0 ? [] : [identity];
|
|
13376
13421
|
});
|
|
13377
|
-
const majors = yield* Effect.
|
|
13422
|
+
const [, majors] = yield* Effect.all([Effect.forEach(wanted.values(), audits.recall, {
|
|
13423
|
+
concurrency: 4,
|
|
13424
|
+
discard: true
|
|
13425
|
+
}), Effect.forEach(offered, (identity) => audits.majors(identity).pipe(Effect.map((identityMajors) => [jobKey(identity), identityMajors])), { concurrency: 4 })], { concurrency: "unbounded" });
|
|
13378
13426
|
yield* update((latest) => ({
|
|
13379
13427
|
...latest,
|
|
13380
13428
|
majors: {
|