@gjermundgaraba/upup 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/{Tui-DV_6wbrQ.mjs → Tui-Ri-yz-Sx.mjs} +58 -25
- package/dist/grep-worker.mjs +3 -16
- package/dist/{io-ns6xhFdF.mjs → io-Dgi-IiVu.mjs} +11 -1
- package/dist/main.mjs +501 -525
- package/native/dist/upup-sparkle.json +1 -1
- package/native/dist/upup-sparkle.zip +0 -0
- package/package.json +2 -3
package/dist/main.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as
|
|
2
|
+
import { i as reason, n as decodeUtf8, r as openFlags, t as byName } from "./io-Dgi-IiVu.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";
|
|
@@ -19,6 +19,7 @@ import lockfile from "proper-lockfile";
|
|
|
19
19
|
import { BACKGROUND_CONTEXT, withAbortSignal } from "@earendil-works/chord/context";
|
|
20
20
|
import { GenerationTask, Harness, LiveDoc, ROOT_CONVERSATION_ID, ToolTask, createRegistry, defineDoc, defineExtension, defineTool, hook, section } from "@earendil-works/pi-durable";
|
|
21
21
|
import { openNodeSqliteStorage } from "@earendil-works/pi-durable/storage/sqlite/node";
|
|
22
|
+
import { absurd, constVoid } from "effect/Function";
|
|
22
23
|
import { ChildProcess, ChildProcessSpawner, CommandLine } from "effect/process";
|
|
23
24
|
import { Worker } from "node:worker_threads";
|
|
24
25
|
import semver from "semver";
|
|
@@ -33,16 +34,14 @@ import { bundleFromJSON, isBundleWithDsseEnvelope } from "@sigstore/bundle";
|
|
|
33
34
|
import { getTrustedRoot } from "@sigstore/tuf";
|
|
34
35
|
import { Verifier, toSignedEntity, toTrustMaterial } from "@sigstore/verify";
|
|
35
36
|
import { isDeepStrictEqual } from "node:util";
|
|
36
|
-
import { constVoid } from "effect/Function";
|
|
37
37
|
import { applyEdits, modify, parse as parse$1 } from "jsonc-parser";
|
|
38
38
|
import { getStaticTOMLValue, parseTOML, traverseNodes } from "toml-eslint-parser";
|
|
39
39
|
import { XMLParser } from "fast-xml-parser";
|
|
40
|
-
import { isSea } from "node:sea";
|
|
41
40
|
import * as ActionMcp from "@gjermundgaraba/effect-actions/ActionMcp";
|
|
42
41
|
import * as Action from "@gjermundgaraba/effect-actions/Action";
|
|
43
42
|
import { setup, types } from "xstate/fsm";
|
|
44
43
|
// package.json
|
|
45
|
-
var version$1 = "0.5.
|
|
44
|
+
var version$1 = "0.5.2";
|
|
46
45
|
// src/ai/Setup.ts
|
|
47
46
|
const Thinking = Schema.Literals([
|
|
48
47
|
"off",
|
|
@@ -428,13 +427,15 @@ const withTarget = (pkg, target) => ({
|
|
|
428
427
|
const isUnaudited = Schema.is(UnauditedEcosystem);
|
|
429
428
|
const isApp$1 = Schema.is(AppEcosystem);
|
|
430
429
|
const isRuntime = Schema.is(RuntimeEcosystem);
|
|
430
|
+
const isOs = Schema.is(OsEcosystem);
|
|
431
431
|
const isUnauditedUpdate = (pkg) => isUnaudited(pkg.ecosystem);
|
|
432
432
|
const isAppUpdate = (pkg) => isApp$1(pkg.ecosystem);
|
|
433
|
-
const
|
|
434
|
-
if (isApp$1(
|
|
435
|
-
if (isRuntime(
|
|
436
|
-
|
|
433
|
+
const ecosystemKind = (ecosystem) => {
|
|
434
|
+
if (isApp$1(ecosystem)) return "app";
|
|
435
|
+
if (isRuntime(ecosystem)) return "runtime";
|
|
436
|
+
return isOs(ecosystem) ? "os" : absurd(ecosystem);
|
|
437
437
|
};
|
|
438
|
+
const unauditedKind = (pkg) => isUnaudited(pkg.ecosystem) ? ecosystemKind(pkg.ecosystem) : void 0;
|
|
438
439
|
// src/inventory/Provider.ts
|
|
439
440
|
var OutputMalformed = class extends Schema.TaggedError()("OutputMalformed", {
|
|
440
441
|
command: Schema.String,
|
|
@@ -560,7 +561,8 @@ const layer$6 = Layer.effect(Exec, Effect.gen(function* () {
|
|
|
560
561
|
const nodeLayer = layer$6.pipe(Layer.provide(NodeServices.layer));
|
|
561
562
|
// src/brew/Brew.ts
|
|
562
563
|
const caskPrefix = "cask:";
|
|
563
|
-
const
|
|
564
|
+
const Kind = Schema.Literals(["formula", "cask"]);
|
|
565
|
+
const kindOf$2 = (pkg) => pkg.id.startsWith(caskPrefix) ? "cask" : "formula";
|
|
564
566
|
const Keg = Schema.Struct({
|
|
565
567
|
version: Schema.String,
|
|
566
568
|
installed_on_request: Schema.Boolean,
|
|
@@ -604,13 +606,12 @@ const Outdated$1 = Schema.Struct({
|
|
|
604
606
|
formulae: Schema.Array(OutdatedEntry),
|
|
605
607
|
casks: Schema.Array(OutdatedEntry)
|
|
606
608
|
});
|
|
607
|
-
const brew
|
|
609
|
+
const brew = (args, refreshMetadata = false) => ({
|
|
608
610
|
command: "brew",
|
|
609
611
|
args,
|
|
610
612
|
cwd: "/",
|
|
611
613
|
env: refreshMetadata ? {} : { HOMEBREW_NO_AUTO_UPDATE: "1" }
|
|
612
614
|
});
|
|
613
|
-
const kindOf$2 = (pkg) => pkg.id.startsWith("cask:") ? "cask" : "formula";
|
|
614
615
|
const activeKeg = (formula) => formula.installed.find((keg) => keg.version === formula.linked_keg) ?? formula.installed.at(-1);
|
|
615
616
|
const describedAs = (desc) => desc === void 0 || desc === null || desc === "" ? {} : { description: desc };
|
|
616
617
|
const packages = (installed, outdated) => {
|
|
@@ -657,19 +658,19 @@ const make$14 = Effect.gen(function* () {
|
|
|
657
658
|
const exec = yield* Exec;
|
|
658
659
|
const json = (schema, invocation) => exec.stdout(invocation).pipe(Effect.flatMap(decodeJson(schema, commandLine(invocation))));
|
|
659
660
|
const list = Effect.gen(function* () {
|
|
660
|
-
const installed = yield* json(Installed, brew
|
|
661
|
+
const installed = yield* json(Installed, brew([
|
|
661
662
|
"info",
|
|
662
663
|
"--json=v2",
|
|
663
664
|
"--installed"
|
|
664
665
|
]));
|
|
665
|
-
const outdated = yield* json(Outdated$1, brew
|
|
666
|
+
const outdated = yield* json(Outdated$1, brew(["outdated", "--json=v2"], true));
|
|
666
667
|
return {
|
|
667
668
|
packages: packages(installed, outdated),
|
|
668
669
|
notices: []
|
|
669
670
|
};
|
|
670
671
|
}).pipe(Effect.withSpan("Brew.list"));
|
|
671
672
|
const observe = Effect.fn("Brew.observe")(function* (pkg) {
|
|
672
|
-
const installed = yield* json(Installed, brew
|
|
673
|
+
const installed = yield* json(Installed, brew([
|
|
673
674
|
"info",
|
|
674
675
|
"--json=v2",
|
|
675
676
|
`--${kindOf$2(pkg)}`,
|
|
@@ -682,7 +683,7 @@ const make$14 = Effect.gen(function* () {
|
|
|
682
683
|
return Option.fromUndefinedOr(observed.find((candidate) => candidate.id === pkg.id));
|
|
683
684
|
});
|
|
684
685
|
const offered = Effect.fn("Brew.offered")(function* (pkg) {
|
|
685
|
-
const invocation = brew
|
|
686
|
+
const invocation = brew([
|
|
686
687
|
"outdated",
|
|
687
688
|
"--json=v2",
|
|
688
689
|
`--${kindOf$2(pkg)}`,
|
|
@@ -710,14 +711,14 @@ const make$14 = Effect.gen(function* () {
|
|
|
710
711
|
expected: target,
|
|
711
712
|
...now === void 0 ? {} : { offered: now }
|
|
712
713
|
});
|
|
713
|
-
yield* exec.stdout(brew
|
|
714
|
+
yield* exec.stdout(brew([
|
|
714
715
|
"upgrade",
|
|
715
716
|
`--${kindOf$2(pkg)}`,
|
|
716
717
|
pkg.name
|
|
717
718
|
]));
|
|
718
719
|
}),
|
|
719
720
|
uninstall: Effect.fn("Brew.uninstall")(function* (pkg) {
|
|
720
|
-
yield* exec.stdout(brew
|
|
721
|
+
yield* exec.stdout(brew([
|
|
721
722
|
"uninstall",
|
|
722
723
|
`--${kindOf$2(pkg)}`,
|
|
723
724
|
pkg.name
|
|
@@ -762,65 +763,88 @@ const Report = Schema.Struct({
|
|
|
762
763
|
findings: Schema.Array(Finding),
|
|
763
764
|
unverified: Schema.Array(Schema.String).annotate({ description: "Each thing you could not verify." })
|
|
764
765
|
});
|
|
766
|
+
const Context$1 = Schema.TaggedUnion({
|
|
767
|
+
None: {},
|
|
768
|
+
Brew: { kind: Kind },
|
|
769
|
+
Python: { python: Schema.String },
|
|
770
|
+
Revision: { revision: Schema.String }
|
|
771
|
+
});
|
|
772
|
+
const sameContext = Schema.toEquivalence(Context$1);
|
|
765
773
|
Schema.Struct({
|
|
766
774
|
mode: Mode,
|
|
767
775
|
delta: Delta,
|
|
768
|
-
context:
|
|
776
|
+
context: Context$1
|
|
769
777
|
});
|
|
770
778
|
var ChangesUnavailable = class extends Schema.TaggedError()("ChangesUnavailable", { issue: Schema.String }) {};
|
|
771
779
|
const isRegistry = Schema.is(RegistryEcosystem);
|
|
772
|
-
const deltaOf = (pkg) => pkg.target === void 0 || !isRegistry(pkg.ecosystem) ? void 0 : {
|
|
773
|
-
ecosystem: pkg.ecosystem,
|
|
774
|
-
artifact: pkg.artifact,
|
|
775
|
-
from: pkg.current,
|
|
776
|
-
to: pkg.target
|
|
777
|
-
};
|
|
778
780
|
const contextOf = (pkg) => {
|
|
779
|
-
if (pkg.ecosystem === "brew") return {
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
781
|
+
if (pkg.ecosystem === "brew") return {
|
|
782
|
+
_tag: "Brew",
|
|
783
|
+
kind: kindOf$2(pkg)
|
|
784
|
+
};
|
|
785
|
+
if (pkg.ecosystem === "pypi" && pkg.runtime !== void 0) return {
|
|
786
|
+
_tag: "Python",
|
|
787
|
+
python: pkg.runtime
|
|
788
|
+
};
|
|
789
|
+
if (pkg.ecosystem === "github-actions" && pkg.revision !== void 0) return {
|
|
790
|
+
_tag: "Revision",
|
|
791
|
+
revision: pkg.revision
|
|
792
|
+
};
|
|
793
|
+
return { _tag: "None" };
|
|
794
|
+
};
|
|
795
|
+
const unauditedReasons = {
|
|
796
|
+
app: "an app update",
|
|
797
|
+
runtime: "a Node.js runtime version",
|
|
798
|
+
os: "an operating-system update"
|
|
799
|
+
};
|
|
800
|
+
const registryOf = (pkg) => {
|
|
801
|
+
if (!isRegistry(pkg.ecosystem)) return Result.fail(`it is ${unauditedReasons[ecosystemKind(pkg.ecosystem)]}, which upup does not audit`);
|
|
802
|
+
return pkg.privateRegistry === void 0 ? Result.succeed(pkg.ecosystem) : Result.fail(`it comes from the private registry ${pkg.privateRegistry}, which upup does not audit`);
|
|
803
|
+
};
|
|
804
|
+
const deltaOf = (pkg) => {
|
|
805
|
+
const { target } = pkg;
|
|
806
|
+
return target === void 0 ? Result.fail("no update is offered") : Result.map(registryOf(pkg), (ecosystem) => ({
|
|
807
|
+
ecosystem,
|
|
808
|
+
artifact: pkg.artifact,
|
|
809
|
+
from: pkg.current,
|
|
810
|
+
to: target
|
|
811
|
+
}));
|
|
783
812
|
};
|
|
784
|
-
const
|
|
813
|
+
const auditOf = (pkg, mode) => Result.map(deltaOf(pkg), (delta) => ({
|
|
785
814
|
mode,
|
|
786
|
-
|
|
815
|
+
delta,
|
|
816
|
+
context: contextOf(pkg)
|
|
817
|
+
}));
|
|
818
|
+
const identityOf = (pkg, mode) => Result.getOrUndefined(auditOf(pkg, mode));
|
|
819
|
+
const unauditable = (pkg) => Result.getOrUndefined(Result.flip(deltaOf(pkg)));
|
|
820
|
+
const landingOf = (pkg, mode) => Result.getOrUndefined(Result.map(registryOf(pkg), (ecosystem) => ({
|
|
821
|
+
mode,
|
|
822
|
+
ecosystem,
|
|
787
823
|
artifact: pkg.artifact,
|
|
788
824
|
version: pkg.current,
|
|
789
825
|
context: contextOf(pkg)
|
|
790
|
-
}
|
|
826
|
+
})));
|
|
827
|
+
const landingAt = (identity) => ({
|
|
828
|
+
mode: identity.mode,
|
|
829
|
+
ecosystem: identity.delta.ecosystem,
|
|
830
|
+
artifact: identity.delta.artifact,
|
|
831
|
+
version: identity.delta.to,
|
|
832
|
+
context: identity.context
|
|
833
|
+
});
|
|
791
834
|
const sha256 = (value) => createHash("sha256").update(value).digest("hex");
|
|
792
835
|
const landingKey = (landing) => sha256(JSON.stringify([
|
|
793
836
|
landing.ecosystem,
|
|
794
837
|
landing.artifact,
|
|
795
838
|
landing.version,
|
|
796
|
-
|
|
839
|
+
landing.context
|
|
797
840
|
]));
|
|
798
|
-
const unauditedReasons = {
|
|
799
|
-
app: "an app update",
|
|
800
|
-
runtime: "a Node.js runtime version",
|
|
801
|
-
os: "an operating-system update"
|
|
802
|
-
};
|
|
803
|
-
const unauditable = (pkg) => {
|
|
804
|
-
if (pkg.target === void 0) return "no update is offered";
|
|
805
|
-
const kind = unauditedKind(pkg);
|
|
806
|
-
if (kind !== void 0) return `it is ${unauditedReasons[kind]}, which upup does not audit`;
|
|
807
|
-
return pkg.privateRegistry === void 0 ? void 0 : `it comes from the private registry ${pkg.privateRegistry}, which upup does not audit`;
|
|
808
|
-
};
|
|
809
|
-
const identityOf = (pkg, mode) => {
|
|
810
|
-
const delta = deltaOf(pkg);
|
|
811
|
-
return delta === void 0 || pkg.privateRegistry !== void 0 ? void 0 : {
|
|
812
|
-
mode,
|
|
813
|
-
delta,
|
|
814
|
-
context: contextOf(pkg)
|
|
815
|
-
};
|
|
816
|
-
};
|
|
817
841
|
const deltaKey = (delta) => sha256(JSON.stringify([
|
|
818
842
|
delta.ecosystem,
|
|
819
843
|
delta.artifact,
|
|
820
844
|
delta.from,
|
|
821
845
|
delta.to
|
|
822
846
|
]));
|
|
823
|
-
const workspaceKey = (identity) => sha256(JSON.stringify([deltaKey(identity.delta),
|
|
847
|
+
const workspaceKey = (identity) => sha256(JSON.stringify([deltaKey(identity.delta), identity.context]));
|
|
824
848
|
// src/audit/tools.ts
|
|
825
849
|
const limits$1 = {
|
|
826
850
|
resultBytes: 262144,
|
|
@@ -833,16 +857,6 @@ const limits$1 = {
|
|
|
833
857
|
longLineMatches: 1025
|
|
834
858
|
};
|
|
835
859
|
const grepTimeoutMs = 3e4;
|
|
836
|
-
const names$1 = {
|
|
837
|
-
read: "read",
|
|
838
|
-
grep: "grep",
|
|
839
|
-
list: "list"
|
|
840
|
-
};
|
|
841
|
-
const descriptions = {
|
|
842
|
-
read: "Read a bounded byte range from one regular UTF-8 file.",
|
|
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.",
|
|
844
|
-
list: "List workspace entries below a directory to a bounded depth."
|
|
845
|
-
};
|
|
846
860
|
const count$1 = (maximum) => Schema.Number.pipe(Schema.check(Schema.isInt(), Schema.isBetween({
|
|
847
861
|
minimum: 1,
|
|
848
862
|
maximum
|
|
@@ -895,7 +909,6 @@ const respond = async (signal, run) => {
|
|
|
895
909
|
const checkPath = (name) => {
|
|
896
910
|
if (!(name === "." || name !== "" && !name.includes("\\") && !name.includes("\0") && name.split("/").every((segment) => segment !== "" && segment !== "." && segment !== ".."))) fail$1(`path ${JSON.stringify(name)} is not workspace-relative`);
|
|
897
911
|
};
|
|
898
|
-
const isCount = (value, min, max) => Number.isSafeInteger(value) && value >= min && value <= max;
|
|
899
912
|
const kindOf$1 = (info) => {
|
|
900
913
|
if (info.isFile()) return "file";
|
|
901
914
|
return info.isDirectory() ? "directory" : "other";
|
|
@@ -931,20 +944,9 @@ const trimIncompleteUtf8 = (data) => {
|
|
|
931
944
|
return data;
|
|
932
945
|
}
|
|
933
946
|
};
|
|
934
|
-
const decodeUtf8 = (data) => {
|
|
935
|
-
try {
|
|
936
|
-
return new TextDecoder("utf-8", {
|
|
937
|
-
fatal: true,
|
|
938
|
-
ignoreBOM: true
|
|
939
|
-
}).decode(data);
|
|
940
|
-
} catch {
|
|
941
|
-
return;
|
|
942
|
-
}
|
|
943
|
-
};
|
|
944
947
|
const read$2 = async (workspace, args, signal) => await respond(signal, async () => {
|
|
945
948
|
const name = args.path;
|
|
946
949
|
checkPath(name);
|
|
947
|
-
if (!isCount(args.offset, 0, Number.MAX_SAFE_INTEGER) || !isCount(args.limit, 1, limits$1.readBytes)) fail$1("offset or limit is outside the allowed range");
|
|
948
950
|
const located = await locate$4(workspace, name, `open ${name}`);
|
|
949
951
|
if (located.kind !== "file") fail$1("path is not a regular file");
|
|
950
952
|
signal?.throwIfAborted();
|
|
@@ -978,7 +980,6 @@ const read$2 = async (workspace, args, signal) => await respond(signal, async ()
|
|
|
978
980
|
});
|
|
979
981
|
const list = async (workspace, args, signal) => await respond(signal, async () => {
|
|
980
982
|
checkPath(args.path);
|
|
981
|
-
if (!isCount(args.depth, 1, limits$1.listDepth)) fail$1("depth is outside the allowed range");
|
|
982
983
|
const located = await locate$4(workspace, args.path, `list workspace: walk ${args.path}`);
|
|
983
984
|
if (located.kind !== "directory") return "no entries";
|
|
984
985
|
let result = "";
|
|
@@ -1005,7 +1006,7 @@ const list = async (workspace, args, signal) => await respond(signal, async () =
|
|
|
1005
1006
|
return result === "" ? "no entries" : result;
|
|
1006
1007
|
});
|
|
1007
1008
|
const decodeAnswer = Schema.decodeUnknownOption(Schema.Union([Schema.Struct({ text: Schema.String }), Schema.Struct({ error: Schema.String })]));
|
|
1008
|
-
const grepWorker =
|
|
1009
|
+
const grepWorker = new URL(`grep-worker${path.extname(new URL(import.meta.url).pathname)}`, import.meta.url);
|
|
1009
1010
|
const search = async (job, timeoutMs, signal) => {
|
|
1010
1011
|
const { promise, resolve, reject } = Promise.withResolvers();
|
|
1011
1012
|
const worker = new Worker(grepWorker);
|
|
@@ -1063,15 +1064,29 @@ const ends = (offset, limit) => {
|
|
|
1063
1064
|
const [from, to] = [span(offset), span(offset + limit)];
|
|
1064
1065
|
return from === to ? `${from} +${span(limit)}` : `${from}–${to}`;
|
|
1065
1066
|
};
|
|
1067
|
+
const tool = (description, Args, run, detail) => {
|
|
1068
|
+
const decode = Schema.decodeUnknownSync(Args);
|
|
1069
|
+
return {
|
|
1070
|
+
description,
|
|
1071
|
+
Args,
|
|
1072
|
+
call: async (workspace, args, signal) => await run(workspace, decode(args), signal),
|
|
1073
|
+
detail
|
|
1074
|
+
};
|
|
1075
|
+
};
|
|
1076
|
+
const tools$3 = {
|
|
1077
|
+
read: tool("Read a bounded byte range from one regular UTF-8 file.", ReadArgs, read$2, ({ path: shown, range }) => `${shown}${range}`),
|
|
1078
|
+
grep: tool("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.", GrepArgs, async (workspace, args, signal) => await grep(workspace, args, signal === void 0 ? {} : { signal }), ({ path: shown, pattern }) => `${pattern} ${shown}`),
|
|
1079
|
+
list: tool("List workspace entries below a directory to a bounded depth.", ListArgs, list, ({ path: shown }) => shown)
|
|
1080
|
+
};
|
|
1081
|
+
const isTool = (name) => Object.hasOwn(tools$3, name);
|
|
1066
1082
|
const describeCall = (name, args) => {
|
|
1067
|
-
if (!Predicate.isObject(args)) return name;
|
|
1083
|
+
if (!Predicate.isObject(args) || !isTool(name)) return name;
|
|
1068
1084
|
const { path: target, pattern, offset, limit } = args;
|
|
1069
|
-
const
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
else if (name === names$1.grep) detail = `${Predicate.isString(pattern) ? pattern : ""} ${shownPath}`;
|
|
1085
|
+
const detail = tools$3[name].detail({
|
|
1086
|
+
path: Predicate.isString(target) ? target : "",
|
|
1087
|
+
pattern: Predicate.isString(pattern) ? pattern : "",
|
|
1088
|
+
range: Predicate.isNumber(offset) && Predicate.isNumber(limit) ? ` bytes ${ends(offset, limit)}` : ""
|
|
1089
|
+
});
|
|
1075
1090
|
return detail === "" ? name : `${name} ${detail}`;
|
|
1076
1091
|
};
|
|
1077
1092
|
// src/audit/hashed-names.ts
|
|
@@ -1729,7 +1744,7 @@ const Meta = Schema.Struct({
|
|
|
1729
1744
|
ecosystem: Delta.fields.ecosystem,
|
|
1730
1745
|
from: Schema.String,
|
|
1731
1746
|
to: Schema.String,
|
|
1732
|
-
context:
|
|
1747
|
+
context: Context$1,
|
|
1733
1748
|
evidence: Grade,
|
|
1734
1749
|
evidence_detail: Schema.String,
|
|
1735
1750
|
preparation_key: Schema.String
|
|
@@ -1740,7 +1755,7 @@ const failed$1 = (workspace) => (cause) => new WorkspaceFailed({
|
|
|
1740
1755
|
issue: cause instanceof Error ? cause.message : String(cause)
|
|
1741
1756
|
});
|
|
1742
1757
|
const listed$2 = async (workspace, name) => await readFile(path.join(workspace, name), "utf-8").catch(() => void 0);
|
|
1743
|
-
const write = (workspace, identity, diff, evidence, detail, preparationKey) => Effect.tryPromise({
|
|
1758
|
+
const write = (workspace, identity, { diff, evidence, detail }, preparationKey) => Effect.tryPromise({
|
|
1744
1759
|
try: async () => {
|
|
1745
1760
|
await writeFile(path.join(workspace, files.diff), diff, { mode: 384 });
|
|
1746
1761
|
await writeFile(path.join(workspace, files.index), buildIndex(diff), { mode: 384 });
|
|
@@ -1763,7 +1778,6 @@ const readMeta = (workspace) => Effect.tryPromise({
|
|
|
1763
1778
|
try: async () => await readFile(path.join(workspace, files.meta), "utf-8"),
|
|
1764
1779
|
catch: failed$1(workspace)
|
|
1765
1780
|
}).pipe(Effect.flatMap((text) => Schema.decodeEffect(MetaJson)(text).pipe(Effect.mapError(failed$1(workspace)))));
|
|
1766
|
-
const sameContext = (left, right) => JSON.stringify(Object.entries(left).toSorted(([a], [b]) => a.localeCompare(b))) === JSON.stringify(Object.entries(right).toSorted(([a], [b]) => a.localeCompare(b)));
|
|
1767
1781
|
const describes = (meta, identity) => meta.name === identity.delta.artifact && meta.ecosystem === identity.delta.ecosystem && meta.from === identity.delta.from && meta.to === identity.delta.to && sameContext(meta.context, identity.context);
|
|
1768
1782
|
const readable = (workspace, identity) => readMeta(workspace).pipe(Effect.flatMap((meta) => describes(meta, identity) ? Effect.promise(async () => await stat(path.join(workspace, files.diff)).then(() => true, () => false)) : Effect.succeed(false)), Effect.orElseSucceed(() => false));
|
|
1769
1783
|
const prune = (workspace) => Effect.promise(async () => {
|
|
@@ -1907,7 +1921,7 @@ const Brief = Schema.Struct({
|
|
|
1907
1921
|
artifact: Schema.String,
|
|
1908
1922
|
from: Schema.String,
|
|
1909
1923
|
to: Schema.String,
|
|
1910
|
-
context:
|
|
1924
|
+
context: Context$1,
|
|
1911
1925
|
workspace: Schema.String,
|
|
1912
1926
|
evidence: Grade,
|
|
1913
1927
|
evidenceDetail: Schema.String,
|
|
@@ -1928,9 +1942,6 @@ const BriefDoc = defineDoc({
|
|
|
1928
1942
|
checkpointWhen: () => false
|
|
1929
1943
|
});
|
|
1930
1944
|
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
1945
|
const decodeSubmitted = Schema.decodeUnknownSync(Report);
|
|
1935
1946
|
const encodeReport = (submitted) => ({
|
|
1936
1947
|
...submitted,
|
|
@@ -1960,27 +1971,13 @@ const answer = (result) => {
|
|
|
1960
1971
|
const auditExtension = (workspace) => {
|
|
1961
1972
|
let steps = 0;
|
|
1962
1973
|
let nudged = false;
|
|
1963
|
-
const
|
|
1964
|
-
name
|
|
1965
|
-
description:
|
|
1966
|
-
replay: "safe",
|
|
1967
|
-
parameters: parameters(ReadArgs),
|
|
1968
|
-
execute: async (args, _api, invocation) => answer(await read$2(workspace, decodeRead(args), invocation.abortSignal))
|
|
1969
|
-
});
|
|
1970
|
-
const grep$1 = defineTool({
|
|
1971
|
-
name: "grep",
|
|
1972
|
-
description: descriptions.grep,
|
|
1973
|
-
replay: "safe",
|
|
1974
|
-
parameters: parameters(GrepArgs),
|
|
1975
|
-
execute: async (args, _api, invocation) => answer(await grep(workspace, decodeGrep(args), invocation.abortSignal === void 0 ? {} : { signal: invocation.abortSignal }))
|
|
1976
|
-
});
|
|
1977
|
-
const list$1 = defineTool({
|
|
1978
|
-
name: "list",
|
|
1979
|
-
description: descriptions.list,
|
|
1974
|
+
const investigate = Object.entries(tools$3).map(([name, tool]) => defineTool({
|
|
1975
|
+
name,
|
|
1976
|
+
description: tool.description,
|
|
1980
1977
|
replay: "safe",
|
|
1981
|
-
parameters: parameters(
|
|
1982
|
-
execute: async (args, _api, invocation) => answer(await
|
|
1983
|
-
});
|
|
1978
|
+
parameters: parameters(tool.Args),
|
|
1979
|
+
execute: async (args, _api, invocation) => answer(await tool.call(workspace, args, invocation.abortSignal))
|
|
1980
|
+
}));
|
|
1984
1981
|
const submit = defineTool({
|
|
1985
1982
|
name: "submit_report",
|
|
1986
1983
|
description: "Submit the audit report. Call exactly once, when the investigation is done; the audit ends.",
|
|
@@ -2000,12 +1997,7 @@ const auditExtension = (workspace) => {
|
|
|
2000
1997
|
});
|
|
2001
1998
|
return defineExtension({
|
|
2002
1999
|
name: "upup.audit",
|
|
2003
|
-
tools: [
|
|
2004
|
-
read,
|
|
2005
|
-
grep$1,
|
|
2006
|
-
list$1,
|
|
2007
|
-
submit
|
|
2008
|
-
],
|
|
2000
|
+
tools: [...investigate, submit],
|
|
2009
2001
|
sections: [section("audit", () => instructions$1)],
|
|
2010
2002
|
hooks: [hook(GenerationTask, {
|
|
2011
2003
|
beforeRequest: (request) => {
|
|
@@ -2036,17 +2028,15 @@ const policyKey = (prompt, setup) => sha256(JSON.stringify([
|
|
|
2036
2028
|
setup.modelId,
|
|
2037
2029
|
setup.thinking
|
|
2038
2030
|
]));
|
|
2031
|
+
const said = (kind, content) => content.trim() === "" ? [] : [{
|
|
2032
|
+
kind,
|
|
2033
|
+
text: content
|
|
2034
|
+
}];
|
|
2039
2035
|
const entriesOf$1 = (message) => {
|
|
2040
2036
|
if (message.role === "assistant") {
|
|
2041
2037
|
const blocks = message.content.flatMap((block) => {
|
|
2042
|
-
if (block.type === "thinking") return block.thinking
|
|
2043
|
-
|
|
2044
|
-
text: block.thinking
|
|
2045
|
-
}];
|
|
2046
|
-
if (block.type === "text") return block.text.trim() === "" ? [] : [{
|
|
2047
|
-
kind: "text",
|
|
2048
|
-
text: block.text
|
|
2049
|
-
}];
|
|
2038
|
+
if (block.type === "thinking") return said("thinking", block.thinking);
|
|
2039
|
+
if (block.type === "text") return said("text", block.text);
|
|
2050
2040
|
return [{
|
|
2051
2041
|
kind: "tool",
|
|
2052
2042
|
text: describeCall(block.name, block.arguments)
|
|
@@ -2082,14 +2072,8 @@ const decodeLive = Schema.decodeUnknownOption(Schema.Struct({ generation: Schema
|
|
|
2082
2072
|
retry: Schema.optional(Schema.Struct({ error: Schema.String }))
|
|
2083
2073
|
})) }));
|
|
2084
2074
|
const streamed = (block) => {
|
|
2085
|
-
if (isThinkingBlock(block)) return block.thinking
|
|
2086
|
-
|
|
2087
|
-
text: block.thinking
|
|
2088
|
-
}];
|
|
2089
|
-
if (isTextBlock(block)) return block.text.trim() === "" ? [] : [{
|
|
2090
|
-
kind: "text",
|
|
2091
|
-
text: block.text
|
|
2092
|
-
}];
|
|
2075
|
+
if (isThinkingBlock(block)) return said("thinking", block.thinking);
|
|
2076
|
+
if (isTextBlock(block)) return said("text", block.text);
|
|
2093
2077
|
return [];
|
|
2094
2078
|
};
|
|
2095
2079
|
var Transcript = class {
|
|
@@ -2360,6 +2344,42 @@ const lookup$5 = Effect.fn("go.lookup")(function* (client, wanted) {
|
|
|
2360
2344
|
withdrawn: {}
|
|
2361
2345
|
};
|
|
2362
2346
|
});
|
|
2347
|
+
// src/registry/npm.ts
|
|
2348
|
+
const Version = Schema.Struct({ deprecated: Schema.optionalKey(Schema.Unknown) });
|
|
2349
|
+
const Packument$1 = Schema.Struct({
|
|
2350
|
+
description: Schema.optionalKey(Schema.String),
|
|
2351
|
+
homepage: Schema.optionalKey(Schema.String),
|
|
2352
|
+
repository: Schema.optionalKey(Schema.Union([Schema.String, Schema.Struct({ url: Schema.optionalKey(Schema.String) })])),
|
|
2353
|
+
"dist-tags": Schema.optionalKey(Schema.Struct({ latest: Schema.optionalKey(Schema.String) })),
|
|
2354
|
+
time: Schema.optionalKey(Schema.Record(Schema.String, Schema.String)),
|
|
2355
|
+
versions: Schema.optionalKey(Schema.Record(Schema.String, Version))
|
|
2356
|
+
});
|
|
2357
|
+
const Downloads = Schema.Struct({ downloads: Schema.Finite });
|
|
2358
|
+
const message$2 = (version) => {
|
|
2359
|
+
const deprecated = version?.deprecated;
|
|
2360
|
+
return Predicate.isString(deprecated) && deprecated !== "" ? Option.some(deprecated) : Option.none();
|
|
2361
|
+
};
|
|
2362
|
+
const npmRegistry = "https://registry.npmjs.org";
|
|
2363
|
+
const npmPath = (segment) => encodeURIComponent(segment).replaceAll(/%(?:24|26|2B|3A|3D|40)/gu, (escaped) => decodeURIComponent(escaped));
|
|
2364
|
+
const lookup$4 = Effect.fn("npm.lookup")(function* (client, wanted) {
|
|
2365
|
+
const [packument, downloads] = yield* Effect.all([getJson(client, `${npmRegistry}/${npmPath(wanted.name)}`, Packument$1), getJson(client, `https://api.npmjs.org/downloads/point/last-week/${wanted.name}`, Downloads).pipe(Effect.option)], { concurrency: "unbounded" });
|
|
2366
|
+
const versions = packument.versions ?? {};
|
|
2367
|
+
const latest = packument["dist-tags"]?.latest;
|
|
2368
|
+
const repository = Predicate.isString(packument.repository) ? packument.repository : packument.repository?.url;
|
|
2369
|
+
const deprecated = latest === void 0 ? Option.none() : message$2(versions[latest]);
|
|
2370
|
+
return {
|
|
2371
|
+
...packument.description === void 0 ? {} : { description: packument.description },
|
|
2372
|
+
...packument.homepage === void 0 ? {} : { homepage: packument.homepage },
|
|
2373
|
+
...repository === void 0 ? {} : { repository: repositoryUrl(repository) },
|
|
2374
|
+
...Option.isSome(downloads) ? { popularity: `${count(downloads.value.downloads)} downloads last week` } : {},
|
|
2375
|
+
...Option.isSome(deprecated) ? { deprecated: deprecated.value } : {},
|
|
2376
|
+
released: pick$1(packument.time ?? {}, wanted.versions),
|
|
2377
|
+
withdrawn: Object.fromEntries(wanted.versions.flatMap((version) => Option.match(message$2(versions[version]), {
|
|
2378
|
+
onNone: () => [],
|
|
2379
|
+
onSome: (reason) => [[version, reason]]
|
|
2380
|
+
})))
|
|
2381
|
+
};
|
|
2382
|
+
});
|
|
2363
2383
|
// src/audit/binary.ts
|
|
2364
2384
|
const startsWith$1 = (prefix, magic) => magic.every((byte, index) => prefix[index] === byte);
|
|
2365
2385
|
const binaryKind = (prefix) => {
|
|
@@ -4274,11 +4294,11 @@ var EvidenceUnavailable = class extends Schema.TaggedError()("EvidenceUnavailabl
|
|
|
4274
4294
|
reason: Schema.optionalKey(Schema.Literals(["gone", "mismatch"]))
|
|
4275
4295
|
}) {};
|
|
4276
4296
|
const maxDownloadBytes = 8 * 1024 ** 3;
|
|
4277
|
-
const message$
|
|
4297
|
+
const message$1 = (cause) => cause instanceof Error ? cause.message : String(cause);
|
|
4278
4298
|
const download = Effect.fn("evidence.download")(function* (client, url, limit = maxDownloadBytes, stall) {
|
|
4279
4299
|
const unavailable = (cause) => new EvidenceUnavailable({
|
|
4280
4300
|
source: url,
|
|
4281
|
-
issue: message$
|
|
4301
|
+
issue: message$1(cause)
|
|
4282
4302
|
});
|
|
4283
4303
|
const stalled = (after) => unavailable(`sent nothing for ${Duration.format(after)}, so upup gave up`);
|
|
4284
4304
|
const directory = yield* Effect.acquireRelease(Effect.tryPromise({
|
|
@@ -4324,7 +4344,7 @@ const download = Effect.fn("evidence.download")(function* (client, url, limit =
|
|
|
4324
4344
|
sha256: hash.digest("hex")
|
|
4325
4345
|
};
|
|
4326
4346
|
});
|
|
4327
|
-
const canonicalSha256
|
|
4347
|
+
const canonicalSha256 = (raw) => {
|
|
4328
4348
|
const value = raw.trim().toLowerCase();
|
|
4329
4349
|
return /^[0-9a-f]{64}$/u.test(value) ? value : void 0;
|
|
4330
4350
|
};
|
|
@@ -4346,7 +4366,7 @@ const crate = Effect.fn("evidence.crate")(function* (client, name, version) {
|
|
|
4346
4366
|
source,
|
|
4347
4367
|
issue: `no crates index entry for ${name} ${version}`
|
|
4348
4368
|
});
|
|
4349
|
-
const sum = canonicalSha256
|
|
4369
|
+
const sum = canonicalSha256(entry.cksum);
|
|
4350
4370
|
if (sum === void 0) return yield* new EvidenceUnavailable({
|
|
4351
4371
|
source,
|
|
4352
4372
|
issue: `crates index publishes an invalid checksum for ${name} ${version}`
|
|
@@ -4400,8 +4420,6 @@ const NpmVersion = Schema.Struct({
|
|
|
4400
4420
|
shasum: Schema.optionalKey(Schema.String)
|
|
4401
4421
|
}))
|
|
4402
4422
|
});
|
|
4403
|
-
const npmRegistry = "https://registry.npmjs.org";
|
|
4404
|
-
const npmPath = (segment) => encodeURIComponent(segment).replaceAll(/%(?:24|26|2B|3A|3D|40)/gu, (escaped) => decodeURIComponent(escaped));
|
|
4405
4423
|
const strictBase64 = (value) => {
|
|
4406
4424
|
const decoded = Buffer.from(value, "base64");
|
|
4407
4425
|
return decoded.toString("base64") === value ? decoded : void 0;
|
|
@@ -4452,7 +4470,7 @@ const npmPlan = Effect.fn("evidence.npmPlan")(function* (name, version, metadata
|
|
|
4452
4470
|
try: () => npmDigest(dist.integrity ?? "", dist.shasum ?? ""),
|
|
4453
4471
|
catch: (error) => new EvidenceUnavailable({
|
|
4454
4472
|
source,
|
|
4455
|
-
issue: `npm ${name}@${version}: ${message$
|
|
4473
|
+
issue: `npm ${name}@${version}: ${message$1(error)}`
|
|
4456
4474
|
})
|
|
4457
4475
|
})
|
|
4458
4476
|
};
|
|
@@ -4515,7 +4533,7 @@ const fetchVerified = Effect.fn("evidence.fetchVerified")(function* (client, url
|
|
|
4515
4533
|
try: async () => await computedDigest(digest, downloaded),
|
|
4516
4534
|
catch: (error) => new EvidenceUnavailable({
|
|
4517
4535
|
source: url,
|
|
4518
|
-
issue: message$
|
|
4536
|
+
issue: message$1(error)
|
|
4519
4537
|
})
|
|
4520
4538
|
});
|
|
4521
4539
|
if (computed === void 0) return yield* new EvidenceUnavailable({
|
|
@@ -4568,6 +4586,10 @@ const preparationPlan = (subject, evidence) => {
|
|
|
4568
4586
|
plan: `${JSON.stringify(plan, null, 2)}\n`
|
|
4569
4587
|
};
|
|
4570
4588
|
};
|
|
4589
|
+
const prepareWorkspace = Effect.fn("evidence.prepareWorkspace")(function* (workspace, subject, preparation) {
|
|
4590
|
+
const prepared = yield* preparation.materialize(workspace);
|
|
4591
|
+
return yield* write(workspace, subject, prepared, preparation.key);
|
|
4592
|
+
});
|
|
4571
4593
|
// src/registry/github.ts
|
|
4572
4594
|
const githubApi = "https://api.github.com";
|
|
4573
4595
|
const githubRepository = (name) => `https://github.com/${name}.git`;
|
|
@@ -4630,18 +4652,11 @@ const sourceOf$1 = (entry) => ({
|
|
|
4630
4652
|
tapGitHead: entry.tap_git_head ?? "",
|
|
4631
4653
|
rubySourceChecksum: entry.ruby_source_checksum?.sha256 ?? ""
|
|
4632
4654
|
});
|
|
4633
|
-
const brew = (args) => ({
|
|
4634
|
-
command: "brew",
|
|
4635
|
-
args,
|
|
4636
|
-
cwd: "/",
|
|
4637
|
-
env: { HOMEBREW_NO_AUTO_UPDATE: "1" }
|
|
4638
|
-
});
|
|
4639
4655
|
const unavailable$2 = (source, issue) => new EvidenceUnavailable({
|
|
4640
4656
|
source,
|
|
4641
4657
|
issue
|
|
4642
4658
|
});
|
|
4643
4659
|
const query = Effect.fn("brew.query")(function* (kind, name) {
|
|
4644
|
-
if (kind !== "formula" && kind !== "cask") return yield* unavailable$2("brew", `unsupported brew package variant ${JSON.stringify(kind)}`);
|
|
4645
4660
|
const raw = yield* (yield* Exec).stdout(brew([
|
|
4646
4661
|
"info",
|
|
4647
4662
|
"--json=v2",
|
|
@@ -4791,9 +4806,7 @@ const nextPage = (current, link) => {
|
|
|
4791
4806
|
const githubGet = (client, url, token) => Effect.gen(function* () {
|
|
4792
4807
|
const headers = {
|
|
4793
4808
|
"user-agent": userAgent,
|
|
4794
|
-
|
|
4795
|
-
"x-github-api-version": "2022-11-28",
|
|
4796
|
-
...token !== void 0 && url.startsWith(`https://api.github.com/`) ? { authorization: `Bearer ${token}` } : {}
|
|
4809
|
+
...githubHeaders(url.startsWith(`https://api.github.com/`) ? token : void 0)
|
|
4797
4810
|
};
|
|
4798
4811
|
const response = yield* get(client, url, headers);
|
|
4799
4812
|
const fail = (issue) => Effect.fail(new EvidenceUnavailable({
|
|
@@ -6099,17 +6112,17 @@ const provenanceSource = (statement, integrity) => {
|
|
|
6099
6112
|
commit
|
|
6100
6113
|
};
|
|
6101
6114
|
};
|
|
6102
|
-
const message
|
|
6115
|
+
const message = (cause) => cause instanceof Error ? cause.message : String(cause);
|
|
6103
6116
|
const sigstoreVerifier = Effect.gen(function* () {
|
|
6104
|
-
const cachePath = path.join(yield* cacheDir.pipe(Effect.mapError((error) => `no cache directory: ${message
|
|
6117
|
+
const cachePath = path.join(yield* cacheDir.pipe(Effect.mapError((error) => `no cache directory: ${message(error)}`)), "sigstore");
|
|
6105
6118
|
const root = yield* Effect.tryPromise({
|
|
6106
6119
|
try: async () => await getTrustedRoot({ cachePath }),
|
|
6107
|
-
catch: (error) => `the Sigstore trust root could not be loaded: ${message
|
|
6120
|
+
catch: (error) => `the Sigstore trust root could not be loaded: ${message(error)}`
|
|
6108
6121
|
});
|
|
6109
6122
|
const verifier = new Verifier(toTrustMaterial(root));
|
|
6110
6123
|
return (bundle) => Effect.try({
|
|
6111
6124
|
try: () => verifier.verify(toSignedEntity(bundle), {}),
|
|
6112
|
-
catch: (error) => `its Sigstore verification failed: ${message
|
|
6125
|
+
catch: (error) => `its Sigstore verification failed: ${message(error)}`
|
|
6113
6126
|
});
|
|
6114
6127
|
});
|
|
6115
6128
|
const sourceRepositoryUri = "1.3.6.1.4.1.57264.1.12";
|
|
@@ -6344,7 +6357,7 @@ const sourceEvidence = Effect.fn("brew.sourceEvidence")(function* (client, works
|
|
|
6344
6357
|
detail: ["Checksum-verified publisher source archive Delta is included.", partial("source archive", source.omitted)].filter((sentence) => sentence !== "").join(" ")
|
|
6345
6358
|
};
|
|
6346
6359
|
});
|
|
6347
|
-
const materialize$1 = Effect.fn("brew.materialize")(function* (client, workspace, identity, plan
|
|
6360
|
+
const materialize$1 = Effect.fn("brew.materialize")(function* (client, workspace, identity, plan) {
|
|
6348
6361
|
const [formula, source, payload] = yield* Effect.all([
|
|
6349
6362
|
materializeFormula(workspace, plan.formula),
|
|
6350
6363
|
sourceEvidence(client, workspace, archives(plan.formula), plan.sourceGap),
|
|
@@ -6360,17 +6373,26 @@ const materialize$1 = Effect.fn("brew.materialize")(function* (client, workspace
|
|
|
6360
6373
|
goSource?.detail ?? "",
|
|
6361
6374
|
repository?.detail ?? ""
|
|
6362
6375
|
].filter((sentence) => sentence !== "").join(" ");
|
|
6363
|
-
return
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
|
|
6369
|
-
|
|
6376
|
+
return {
|
|
6377
|
+
diff: Buffer.concat([
|
|
6378
|
+
formula,
|
|
6379
|
+
source.diff,
|
|
6380
|
+
payload.diff,
|
|
6381
|
+
goSource?.diff ?? Buffer.alloc(0),
|
|
6382
|
+
repository?.diff ?? Buffer.alloc(0)
|
|
6383
|
+
]),
|
|
6384
|
+
evidence,
|
|
6385
|
+
detail: plan.formula.fromGap === "" ? detail : `The installed version's formula snapshot is unavailable: ${plan.formula.fromGap}. ${detail}`
|
|
6386
|
+
};
|
|
6370
6387
|
});
|
|
6371
6388
|
const resolve$2 = Effect.fn("brew.resolve")(function* (client, identity) {
|
|
6372
6389
|
const { artifact, from, to } = identity.delta;
|
|
6373
|
-
const
|
|
6390
|
+
const { context } = identity;
|
|
6391
|
+
if (context._tag !== "Brew") return yield* new EvidenceUnavailable({
|
|
6392
|
+
source: "brew",
|
|
6393
|
+
issue: `a brew package's audit needs its kind, not ${context._tag}`
|
|
6394
|
+
});
|
|
6395
|
+
const { kind } = context;
|
|
6374
6396
|
const { source, formula: info } = yield* query(kind, artifact);
|
|
6375
6397
|
const formula = yield* resolveFormula(client, source, from, to);
|
|
6376
6398
|
const formulaGap = formula.fromGap === "" ? archiveUnavailableReason(archives(formula)) : "the installed version's formula snapshot is unavailable";
|
|
@@ -6389,25 +6411,21 @@ const resolve$2 = Effect.fn("brew.resolve")(function* (client, identity) {
|
|
|
6389
6411
|
...repository === void 0 ? {} : { repository }
|
|
6390
6412
|
};
|
|
6391
6413
|
});
|
|
6392
|
-
const prepareBrewWith = (exec) => (client, identity) => resolve$2(client, identity).pipe(Effect.provide(exec), Effect.map((plan) => {
|
|
6393
|
-
|
|
6414
|
+
const prepareBrewWith = (exec) => (client, identity) => resolve$2(client, identity).pipe(Effect.provide(exec), Effect.map((plan) => ({
|
|
6415
|
+
...preparationPlan(identity, {
|
|
6394
6416
|
kind: "brew",
|
|
6395
6417
|
plan: planKey(plan)
|
|
6396
|
-
})
|
|
6397
|
-
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
artifacts: artifactsOf(plan),
|
|
6401
|
-
materialize: (workspace) => materialize$1(client, workspace, identity, plan, key).pipe(Effect.provide(exec))
|
|
6402
|
-
};
|
|
6403
|
-
}));
|
|
6418
|
+
}),
|
|
6419
|
+
artifacts: artifactsOf(plan),
|
|
6420
|
+
materialize: (workspace) => materialize$1(client, workspace, identity, plan).pipe(Effect.provide(exec))
|
|
6421
|
+
})));
|
|
6404
6422
|
const prepareBrew = prepareBrewWith(nodeLayer);
|
|
6405
6423
|
// src/audit/github-actions.ts
|
|
6406
6424
|
const unavailable$1 = (error) => new EvidenceUnavailable({
|
|
6407
6425
|
source: error.repository,
|
|
6408
6426
|
issue: error.issue
|
|
6409
6427
|
});
|
|
6410
|
-
const workspaceOf
|
|
6428
|
+
const workspaceOf = Effect.fn("githubActions.workspace")(function* (workspace, identity, repository, commits, options) {
|
|
6411
6429
|
const trees = {
|
|
6412
6430
|
from: path.join(workspace, files.actionFrom),
|
|
6413
6431
|
to: path.join(workspace, files.actionTo)
|
|
@@ -6432,17 +6450,25 @@ const workspaceOf$1 = Effect.fn("githubActions.workspace")(function* (workspace,
|
|
|
6432
6450
|
const { from, to } = identity.delta;
|
|
6433
6451
|
const commitsSentence = `In ${repository}, ${from} is ${commits.from} and ${to} is ${commits.to}.`;
|
|
6434
6452
|
const modes = yield* writeFileDiff(workspace, files.actionModesFrom, files.actionModesTo, json(Object.fromEntries(changed.modes.map((change) => [change.path, change.from]))), json(Object.fromEntries(changed.modes.map((change) => [change.path, change.to]))));
|
|
6435
|
-
if (changed.omitted !== "") return
|
|
6453
|
+
if (changed.omitted !== "") return {
|
|
6454
|
+
diff: modes,
|
|
6455
|
+
evidence: "metadata-only",
|
|
6456
|
+
detail: `${commitsSentence} The changed files were not fetched: ${changed.omitted}.`
|
|
6457
|
+
};
|
|
6436
6458
|
const { diff, omitted } = yield* treeDiff(workspace, files.actionFrom, files.actionTo);
|
|
6437
6459
|
const submodules = changed.modes.flatMap((change) => change.submodule ? [change.path] : []);
|
|
6438
6460
|
const gaps = [partial("action", omitted), submodules.length === 0 ? "" : `Submodules changed, and their contents were not fetched: ${submodules.join(", ")}.`].filter((sentence) => sentence !== "");
|
|
6439
|
-
return
|
|
6461
|
+
return {
|
|
6462
|
+
diff: Buffer.concat([diff, modes]),
|
|
6463
|
+
evidence: gaps.length === 0 ? "full" : "partial",
|
|
6464
|
+
detail: [commitsSentence, ...gaps].join(" ")
|
|
6465
|
+
};
|
|
6440
6466
|
});
|
|
6441
6467
|
const githubActionPreparer = (repositoryOf, options = {}) => Effect.fn("githubActions.prepare")(function* (_client, identity) {
|
|
6442
6468
|
const { artifact, from, to } = identity.delta;
|
|
6443
6469
|
const repository = repositoryOf(artifact);
|
|
6444
6470
|
const [fromCommit, toCommit] = yield* Effect.all([tagCommit(repository, from, options), tagCommit(repository, to, options)], { concurrency: "unbounded" }).pipe(Effect.mapError(unavailable$1));
|
|
6445
|
-
const listed = identity.context
|
|
6471
|
+
const listed = identity.context._tag === "Revision" ? identity.context.revision : void 0;
|
|
6446
6472
|
if (listed !== toCommit) return yield* new EvidenceUnavailable({
|
|
6447
6473
|
source: repository,
|
|
6448
6474
|
issue: listed === void 0 ? `upup listed no commit for ${to}; refresh` : `${to} now points at ${toCommit}, not the ${listed} upup listed; refresh`,
|
|
@@ -6452,16 +6478,14 @@ const githubActionPreparer = (repositoryOf, options = {}) => Effect.fn("githubAc
|
|
|
6452
6478
|
from: fromCommit,
|
|
6453
6479
|
to: toCommit
|
|
6454
6480
|
};
|
|
6455
|
-
const { key, plan } = preparationPlan(identity, {
|
|
6456
|
-
kind: "github-actions",
|
|
6457
|
-
repository,
|
|
6458
|
-
commits
|
|
6459
|
-
});
|
|
6460
6481
|
return {
|
|
6461
|
-
|
|
6462
|
-
|
|
6482
|
+
...preparationPlan(identity, {
|
|
6483
|
+
kind: "github-actions",
|
|
6484
|
+
repository,
|
|
6485
|
+
commits
|
|
6486
|
+
}),
|
|
6463
6487
|
artifacts: [`from ${fromCommit}`, `to ${toCommit}`],
|
|
6464
|
-
materialize: (workspace) => workspaceOf
|
|
6488
|
+
materialize: (workspace) => workspaceOf(workspace, identity, repository, commits, options)
|
|
6465
6489
|
};
|
|
6466
6490
|
});
|
|
6467
6491
|
const prepareGitHubAction = githubActionPreparer(githubRepository);
|
|
@@ -6475,10 +6499,6 @@ const Release$2 = Schema.Struct({ urls: optional(Schema.Array(Schema.Struct({
|
|
|
6475
6499
|
digests: optional(Schema.Struct({ sha256: optional(Schema.String) }))
|
|
6476
6500
|
}))) });
|
|
6477
6501
|
const releaseUrl = (name, version) => `https://pypi.org/pypi/${encodeURIComponent(name)}/${encodeURIComponent(version)}/json`;
|
|
6478
|
-
const canonicalSha256 = (raw) => {
|
|
6479
|
-
const value = raw.trim().toLowerCase();
|
|
6480
|
-
return /^[0-9a-f]{64}$/u.test(value) ? value : void 0;
|
|
6481
|
-
};
|
|
6482
6502
|
const formatOf = (url) => {
|
|
6483
6503
|
try {
|
|
6484
6504
|
return formatOf$1(url);
|
|
@@ -6627,7 +6647,7 @@ const trees = [
|
|
|
6627
6647
|
files.wheelFrom,
|
|
6628
6648
|
files.wheelTo
|
|
6629
6649
|
];
|
|
6630
|
-
const pypiWorkspace = Effect.fn("pypi.workspace")(function* (client, workspace,
|
|
6650
|
+
const pypiWorkspace = Effect.fn("pypi.workspace")(function* (client, workspace, plans) {
|
|
6631
6651
|
yield* Effect.tryPromise({
|
|
6632
6652
|
try: async () => await Promise.all(trees.map(async (tree) => await mkdir(path.join(workspace, tree), {
|
|
6633
6653
|
recursive: true,
|
|
@@ -6647,38 +6667,40 @@ const pypiWorkspace = Effect.fn("pypi.workspace")(function* (client, workspace,
|
|
|
6647
6667
|
writeFileDiff(workspace, files.binaryWheelFrom, files.binaryWheelTo, json(binarySummaries(from.compatible_universal_wheel?.archive_manifest)), json(binarySummaries(to.compatible_universal_wheel?.archive_manifest)))
|
|
6648
6668
|
], { concurrency: "unbounded" });
|
|
6649
6669
|
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.`;
|
|
6650
|
-
return
|
|
6651
|
-
|
|
6652
|
-
|
|
6653
|
-
|
|
6654
|
-
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
partial
|
|
6659
|
-
|
|
6660
|
-
|
|
6670
|
+
return {
|
|
6671
|
+
diff: Buffer.concat([
|
|
6672
|
+
sources.diff,
|
|
6673
|
+
records,
|
|
6674
|
+
sourceBinaries,
|
|
6675
|
+
wheels.diff,
|
|
6676
|
+
wheelBinaries
|
|
6677
|
+
]),
|
|
6678
|
+
evidence: "partial",
|
|
6679
|
+
detail: [
|
|
6680
|
+
detail,
|
|
6681
|
+
partial("source distribution", sources.omitted),
|
|
6682
|
+
partial("wheel", wheels.omitted)
|
|
6683
|
+
].filter((sentence) => sentence !== "").join(" ")
|
|
6684
|
+
};
|
|
6661
6685
|
});
|
|
6662
6686
|
const preparePyPI = Effect.fn("pypi.prepare")(function* (client, identity) {
|
|
6663
6687
|
const { artifact, from, to } = identity.delta;
|
|
6664
|
-
const python = identity.context
|
|
6688
|
+
const python = identity.context._tag === "Python" ? identity.context.python : "";
|
|
6665
6689
|
const [fromPlan, toPlan] = yield* Effect.all([resolve$1(client, artifact, from, python), resolve$1(client, artifact, to, python)], { concurrency: "unbounded" });
|
|
6666
6690
|
const plans = {
|
|
6667
6691
|
from: fromPlan,
|
|
6668
6692
|
to: toPlan
|
|
6669
6693
|
};
|
|
6670
|
-
const { key, plan } = preparationPlan(identity, {
|
|
6671
|
-
kind: "pypi",
|
|
6672
|
-
...plans
|
|
6673
|
-
});
|
|
6674
6694
|
return {
|
|
6675
|
-
|
|
6676
|
-
|
|
6695
|
+
...preparationPlan(identity, {
|
|
6696
|
+
kind: "pypi",
|
|
6697
|
+
...plans
|
|
6698
|
+
}),
|
|
6677
6699
|
artifacts: ["from", "to"].flatMap((side) => [plans[side].publisher_sdist, plans[side].compatible_universal_wheel].map((selected) => `${side} ${selected === null ? "none" : `sha256:${selected.sha256}`}`)),
|
|
6678
|
-
materialize: (workspace) => pypiWorkspace(client, workspace,
|
|
6700
|
+
materialize: (workspace) => pypiWorkspace(client, workspace, plans)
|
|
6679
6701
|
};
|
|
6680
6702
|
});
|
|
6681
|
-
const Packument
|
|
6703
|
+
const Packument = Schema.Struct({
|
|
6682
6704
|
"dist-tags": Schema.optionalKey(Schema.NullOr(Schema.Record(Schema.String, Schema.String))),
|
|
6683
6705
|
versions: Schema.Record(Schema.String, Schema.Unknown)
|
|
6684
6706
|
});
|
|
@@ -6710,7 +6732,7 @@ const resolveSide = (client, host, name, declared, options = {}) => Effect.gen(f
|
|
|
6710
6732
|
issue: `declares ${JSON.stringify(declared.spec)}, which is not a registry version range`
|
|
6711
6733
|
});
|
|
6712
6734
|
const source = `${npmRegistry}/${npmPath(name)}`;
|
|
6713
|
-
const packument = yield* getJson(client, source, Packument
|
|
6735
|
+
const packument = yield* getJson(client, source, Packument, { accept: "application/vnd.npm.install-v1+json" }).pipe(Effect.mapError((error) => new EvidenceUnavailable({
|
|
6714
6736
|
source,
|
|
6715
6737
|
issue: error.issue
|
|
6716
6738
|
})));
|
|
@@ -6903,87 +6925,102 @@ const materializeDependencies = Effect.fn("npmDependencies.materialize")(functio
|
|
|
6903
6925
|
});
|
|
6904
6926
|
// src/audit/registry-evidence.ts
|
|
6905
6927
|
const registryDetail = "Both published packages were downloaded and their checksums verified. File types and modes, and any native binaries, are summarised without running them.";
|
|
6906
|
-
const
|
|
6928
|
+
const sentences = (parts) => parts.filter((sentence) => sentence !== "").join(" ");
|
|
6929
|
+
const artifactEvidence = Effect.fn("evidence.artifactEvidence")(function* (client, workspace, plans) {
|
|
6907
6930
|
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
6931
|
const [artifacts, trees, binaries] = yield* Effect.all([
|
|
6909
6932
|
writeFileDiff(workspace, files.artifactFrom, files.artifactTo, manifestJson(from), manifestJson(to)),
|
|
6910
6933
|
treeDiff(workspace, files.from, files.to),
|
|
6911
6934
|
writeFileDiff(workspace, files.binaryFrom, files.binaryTo, json(binarySummaries(from)), json(binarySummaries(to)))
|
|
6912
6935
|
], { concurrency: "unbounded" });
|
|
6913
|
-
const treeDetail = [registryDetail, partial("artifact", trees.omitted)].filter((sentence) => sentence !== "").join(" ");
|
|
6914
|
-
if (npm === void 0) return yield* write(workspace, identity, Buffer.concat([
|
|
6915
|
-
artifacts,
|
|
6916
|
-
trees.diff,
|
|
6917
|
-
binaries
|
|
6918
|
-
]), trees.omitted === "" ? "full" : "partial", treeDetail, key);
|
|
6919
|
-
const changed = yield* materializeDependencies(client, workspace, npm.dependencies);
|
|
6920
|
-
const linked = yield* Effect.forEach(changed.binaries, (binary) => releaseAssetSources(client, binary.repository, [binary.from, binary.to]).pipe(Effect.map(([fromRelease, toRelease]) => ({
|
|
6921
|
-
label: binary.label,
|
|
6922
|
-
from: fromRelease ?? { gap: "no release lookup" },
|
|
6923
|
-
to: toRelease ?? { gap: "no release lookup" }
|
|
6924
|
-
}))), { concurrency: 2 });
|
|
6925
|
-
const source = yield* materializeSources(workspace, [npm.source, ...linked]);
|
|
6926
|
-
return yield* write(workspace, identity, Buffer.concat([
|
|
6927
|
-
artifacts,
|
|
6928
|
-
trees.diff,
|
|
6929
|
-
binaries,
|
|
6930
|
-
changed.diff,
|
|
6931
|
-
source.diff
|
|
6932
|
-
]), "partial", [
|
|
6933
|
-
treeDetail,
|
|
6934
|
-
changed.detail,
|
|
6935
|
-
source.detail
|
|
6936
|
-
].filter((sentence) => sentence !== "").join(" "), key);
|
|
6937
|
-
});
|
|
6938
|
-
const npmExtras = Effect.fn("evidence.npmExtras")(function* (client, name, from, to, manifests) {
|
|
6939
|
-
const fromManifest = manifests.from;
|
|
6940
|
-
const toManifest = manifests.to;
|
|
6941
|
-
const dependencies = yield* resolveDependencies(client, manifests, {
|
|
6942
|
-
os: process.platform,
|
|
6943
|
-
cpu: process.arch
|
|
6944
|
-
});
|
|
6945
|
-
const verifier = yield* Effect.cached(sigstoreVerifier);
|
|
6946
|
-
const [fromSource, toSource] = yield* Effect.all([npmSource(client, name, from, fromManifest, verifier), npmSource(client, name, to, toManifest, verifier)], { concurrency: "unbounded" });
|
|
6947
|
-
const { directory } = npmRepository(toManifest);
|
|
6948
6936
|
return {
|
|
6949
|
-
|
|
6950
|
-
|
|
6951
|
-
|
|
6952
|
-
|
|
6953
|
-
|
|
6954
|
-
|
|
6955
|
-
|
|
6937
|
+
diff: Buffer.concat([
|
|
6938
|
+
artifacts,
|
|
6939
|
+
trees.diff,
|
|
6940
|
+
binaries
|
|
6941
|
+
]),
|
|
6942
|
+
evidence: trees.omitted === "" ? "full" : "partial",
|
|
6943
|
+
detail: sentences([registryDetail, partial("artifact", trees.omitted)])
|
|
6956
6944
|
};
|
|
6957
6945
|
});
|
|
6946
|
+
const digests = (plans) => [`from ${plans.from.published_digest}`, `to ${plans.to.published_digest}`];
|
|
6958
6947
|
const prepareRegistry = Effect.fn("evidence.prepareRegistry")(function* (client, identity) {
|
|
6959
6948
|
const { ecosystem, artifact, from, to } = identity.delta;
|
|
6960
|
-
const
|
|
6961
|
-
from: npmVersion(client, artifact, from),
|
|
6962
|
-
to: npmVersion(client, artifact, to)
|
|
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" });
|
|
6949
|
+
const [fromPlan, toPlan] = yield* Effect.all([resolve$3(client, ecosystem, artifact, from), resolve$3(client, ecosystem, artifact, to)], { concurrency: "unbounded" });
|
|
6965
6950
|
const plans = {
|
|
6966
6951
|
from: fromPlan,
|
|
6967
6952
|
to: toPlan
|
|
6968
6953
|
};
|
|
6969
|
-
const npm = manifests === void 0 ? void 0 : yield* npmExtras(client, artifact, from, to, manifests);
|
|
6970
|
-
const { key, plan } = preparationPlan(identity, {
|
|
6971
|
-
kind: "registry",
|
|
6972
|
-
...plans,
|
|
6973
|
-
...npm
|
|
6974
|
-
});
|
|
6975
6954
|
return {
|
|
6976
|
-
|
|
6977
|
-
|
|
6978
|
-
|
|
6979
|
-
|
|
6955
|
+
...preparationPlan(identity, {
|
|
6956
|
+
kind: "registry",
|
|
6957
|
+
...plans
|
|
6958
|
+
}),
|
|
6959
|
+
artifacts: digests(plans),
|
|
6960
|
+
materialize: (workspace) => artifactEvidence(client, workspace, plans)
|
|
6980
6961
|
};
|
|
6981
6962
|
});
|
|
6982
6963
|
// src/audit/prepare.ts
|
|
6983
6964
|
const preparers = {
|
|
6984
6965
|
crates: prepareRegistry,
|
|
6985
6966
|
go: prepareRegistry,
|
|
6986
|
-
npm:
|
|
6967
|
+
npm: Effect.fn("evidence.prepareNpm")(function* (client, identity) {
|
|
6968
|
+
const { artifact, from, to } = identity.delta;
|
|
6969
|
+
const manifests = yield* Effect.all({
|
|
6970
|
+
from: npmVersion(client, artifact, from),
|
|
6971
|
+
to: npmVersion(client, artifact, to)
|
|
6972
|
+
}, { concurrency: "unbounded" });
|
|
6973
|
+
const [fromPlan, toPlan] = yield* Effect.all([npmPlan(artifact, from, manifests.from), npmPlan(artifact, to, manifests.to)], { concurrency: "unbounded" });
|
|
6974
|
+
const dependencies = yield* resolveDependencies(client, manifests, {
|
|
6975
|
+
os: process.platform,
|
|
6976
|
+
cpu: process.arch
|
|
6977
|
+
});
|
|
6978
|
+
const verifier = yield* Effect.cached(sigstoreVerifier);
|
|
6979
|
+
const [fromSource, toSource] = yield* Effect.all([npmSource(client, artifact, from, manifests.from, verifier), npmSource(client, artifact, to, manifests.to, verifier)], { concurrency: "unbounded" });
|
|
6980
|
+
const { directory } = npmRepository(manifests.to);
|
|
6981
|
+
const source = {
|
|
6982
|
+
label: artifact,
|
|
6983
|
+
...directory === void 0 ? {} : { directory },
|
|
6984
|
+
from: fromSource,
|
|
6985
|
+
to: toSource
|
|
6986
|
+
};
|
|
6987
|
+
const plans = {
|
|
6988
|
+
from: fromPlan,
|
|
6989
|
+
to: toPlan
|
|
6990
|
+
};
|
|
6991
|
+
return {
|
|
6992
|
+
...preparationPlan(identity, {
|
|
6993
|
+
kind: "npm",
|
|
6994
|
+
...plans,
|
|
6995
|
+
dependencies,
|
|
6996
|
+
source
|
|
6997
|
+
}),
|
|
6998
|
+
artifacts: digests(plans),
|
|
6999
|
+
materialize: (workspace) => Effect.gen(function* () {
|
|
7000
|
+
const artifacts = yield* artifactEvidence(client, workspace, plans);
|
|
7001
|
+
const changed = yield* materializeDependencies(client, workspace, dependencies);
|
|
7002
|
+
const linked = yield* Effect.forEach(changed.binaries, (binary) => releaseAssetSources(client, binary.repository, [binary.from, binary.to]).pipe(Effect.map(([fromRelease, toRelease]) => ({
|
|
7003
|
+
label: binary.label,
|
|
7004
|
+
from: fromRelease ?? { gap: "no release lookup" },
|
|
7005
|
+
to: toRelease ?? { gap: "no release lookup" }
|
|
7006
|
+
}))), { concurrency: 2 });
|
|
7007
|
+
const sources = yield* materializeSources(workspace, [source, ...linked]);
|
|
7008
|
+
return {
|
|
7009
|
+
diff: Buffer.concat([
|
|
7010
|
+
artifacts.diff,
|
|
7011
|
+
changed.diff,
|
|
7012
|
+
sources.diff
|
|
7013
|
+
]),
|
|
7014
|
+
evidence: "partial",
|
|
7015
|
+
detail: sentences([
|
|
7016
|
+
artifacts.detail,
|
|
7017
|
+
changed.detail,
|
|
7018
|
+
sources.detail
|
|
7019
|
+
])
|
|
7020
|
+
};
|
|
7021
|
+
})
|
|
7022
|
+
};
|
|
7023
|
+
}),
|
|
6987
7024
|
pypi: preparePyPI,
|
|
6988
7025
|
brew: prepareBrew,
|
|
6989
7026
|
"github-actions": prepareGitHubAction
|
|
@@ -7069,7 +7106,7 @@ const within = (effect, what) => effect.pipe(Effect.timeoutOrElse({
|
|
|
7069
7106
|
issue: `evidence preparation timed out after 15 minutes`
|
|
7070
7107
|
}))
|
|
7071
7108
|
}));
|
|
7072
|
-
const ensure = (workspace, preparation) => Effect.gen(function* () {
|
|
7109
|
+
const ensure = (workspace, identity, preparation) => Effect.gen(function* () {
|
|
7073
7110
|
yield* Effect.tryPromise({
|
|
7074
7111
|
try: async () => {
|
|
7075
7112
|
await rm(workspace, {
|
|
@@ -7087,23 +7124,21 @@ const ensure = (workspace, preparation) => Effect.gen(function* () {
|
|
|
7087
7124
|
issue: issueOf$1(error)
|
|
7088
7125
|
})
|
|
7089
7126
|
});
|
|
7090
|
-
yield* within(
|
|
7127
|
+
yield* within(prepareWorkspace(workspace, identity, preparation), "prepare workspace").pipe(Effect.onError(() => Effect.promise(async () => {
|
|
7091
7128
|
await rm(workspace, {
|
|
7092
7129
|
recursive: true,
|
|
7093
7130
|
force: true
|
|
7094
7131
|
});
|
|
7095
7132
|
})));
|
|
7096
7133
|
});
|
|
7097
|
-
const workspaceOf = (file) => path.join(path.dirname(path.dirname(path.dirname(file))), "workspaces", path.basename(path.dirname(file)));
|
|
7098
7134
|
const sameArtifacts = (left, right) => left.length === right.length && left.every((artifact, index) => artifact === right[index]);
|
|
7099
|
-
const reportedFrom = (
|
|
7135
|
+
const reportedFrom = (paths, stored) => Option.isSome(stored.report) && Option.isSome(stored.brief) ? Option.some({
|
|
7100
7136
|
_tag: "Reported",
|
|
7101
7137
|
report: stored.report.value,
|
|
7102
7138
|
evidence: stored.brief.value.evidence,
|
|
7103
7139
|
detail: stored.brief.value.evidenceDetail,
|
|
7104
7140
|
model: `${stored.brief.value.provider}/${stored.brief.value.modelId}`,
|
|
7105
|
-
|
|
7106
|
-
workspace: workspaceOf(file)
|
|
7141
|
+
...paths
|
|
7107
7142
|
}) : Option.none();
|
|
7108
7143
|
const audits$1 = (stored, artifacts) => Option.isSome(stored.brief) && sameArtifacts(stored.brief.value.artifacts, artifacts);
|
|
7109
7144
|
const children = (directory) => Effect.promise(async () => await readdir(directory).catch(() => []));
|
|
@@ -7144,13 +7179,7 @@ const layer$5 = (cacheDir) => Layer.effect(Audits, Effect.gen(function* () {
|
|
|
7144
7179
|
});
|
|
7145
7180
|
const landingFile = (landing) => path.join(root, "landed", landing.mode, `${landingKey(landing)}.json`);
|
|
7146
7181
|
const land = (identity) => Effect.tryPromise(async () => {
|
|
7147
|
-
const file = landingFile(
|
|
7148
|
-
mode: identity.mode,
|
|
7149
|
-
ecosystem: identity.delta.ecosystem,
|
|
7150
|
-
artifact: identity.delta.artifact,
|
|
7151
|
-
version: identity.delta.to,
|
|
7152
|
-
context: identity.context
|
|
7153
|
-
});
|
|
7182
|
+
const file = landingFile(landingAt(identity));
|
|
7154
7183
|
await mkdir(path.dirname(file), {
|
|
7155
7184
|
recursive: true,
|
|
7156
7185
|
mode: 448
|
|
@@ -7164,10 +7193,15 @@ const layer$5 = (cacheDir) => Layer.effect(Audits, Effect.gen(function* () {
|
|
|
7164
7193
|
const note = JSON.parse(text);
|
|
7165
7194
|
return Predicate.hasProperty(note, "from") && Predicate.hasProperty(note, "to") && Predicate.isString(note.from) && note.to === landing.version ? Option.some(note.from) : Option.none();
|
|
7166
7195
|
}, () => Option.none()));
|
|
7167
|
-
const
|
|
7168
|
-
const
|
|
7169
|
-
|
|
7170
|
-
|
|
7196
|
+
const workspaces = path.join(root, "workspaces");
|
|
7197
|
+
const workspaceFor = (identity) => path.join(workspaces, workspaceKey(identity));
|
|
7198
|
+
const pathsOf = (identity, policyKey) => ({
|
|
7199
|
+
file: path.join(root, identity.mode, workspaceKey(identity), `${policyKey}.sqlite`),
|
|
7200
|
+
workspace: workspaceFor(identity)
|
|
7201
|
+
});
|
|
7202
|
+
const storedIn = (paths) => Effect.scoped(Effect.gen(function* () {
|
|
7203
|
+
if (!(yield* tryHold(paths.workspace))) return Option.none();
|
|
7204
|
+
return Option.some(yield* stored(paths.file, ai.models));
|
|
7171
7205
|
})).pipe(Effect.orElseSucceed(() => Option.none()));
|
|
7172
7206
|
const attempt = Effect.fn("Audits.attempt")(function* (identity, options) {
|
|
7173
7207
|
let transcript = [];
|
|
@@ -7186,8 +7220,8 @@ const layer$5 = (cacheDir) => Layer.effect(Audits, Effect.gen(function* () {
|
|
|
7186
7220
|
const prompt = promptFor(identity.mode);
|
|
7187
7221
|
const policyKey$1 = policyKey(prompt, setup.value);
|
|
7188
7222
|
const preparation = yield* within(prepare(client, identity), "resolve evidence");
|
|
7189
|
-
const
|
|
7190
|
-
const workspace =
|
|
7223
|
+
const paths = pathsOf(identity, policyKey$1);
|
|
7224
|
+
const { file, workspace } = paths;
|
|
7191
7225
|
yield* hold(workspace);
|
|
7192
7226
|
const model = `${setup.value.provider}/${setup.value.modelId}`;
|
|
7193
7227
|
if (existsSync(file)) {
|
|
@@ -7195,7 +7229,7 @@ const layer$5 = (cacheDir) => Layer.effect(Audits, Effect.gen(function* () {
|
|
|
7195
7229
|
brief: Option.none(),
|
|
7196
7230
|
report: Option.none()
|
|
7197
7231
|
})));
|
|
7198
|
-
const found = reportedFrom(
|
|
7232
|
+
const found = reportedFrom(paths, stored$1);
|
|
7199
7233
|
if (!options.force && Option.isSome(found) && audits$1(stored$1, preparation.artifacts)) {
|
|
7200
7234
|
yield* land(identity);
|
|
7201
7235
|
return found.value;
|
|
@@ -7209,7 +7243,7 @@ const layer$5 = (cacheDir) => Layer.effect(Audits, Effect.gen(function* () {
|
|
|
7209
7243
|
}, file);
|
|
7210
7244
|
}
|
|
7211
7245
|
yield* Effect.addFinalizer(() => prune(workspace));
|
|
7212
|
-
yield* ensure(workspace, preparation);
|
|
7246
|
+
yield* ensure(workspace, identity, preparation);
|
|
7213
7247
|
const meta = yield* readMeta(workspace);
|
|
7214
7248
|
yield* Effect.tryPromise({
|
|
7215
7249
|
try: async () => await mkdir(path.dirname(file), {
|
|
@@ -7274,8 +7308,7 @@ const layer$5 = (cacheDir) => Layer.effect(Audits, Effect.gen(function* () {
|
|
|
7274
7308
|
evidence: meta.evidence,
|
|
7275
7309
|
detail: meta.evidence_detail,
|
|
7276
7310
|
model,
|
|
7277
|
-
|
|
7278
|
-
workspace
|
|
7311
|
+
...paths
|
|
7279
7312
|
};
|
|
7280
7313
|
});
|
|
7281
7314
|
const audit = (identity, options) => Effect.sync(() => {
|
|
@@ -7294,8 +7327,8 @@ const layer$5 = (cacheDir) => Layer.effect(Audits, Effect.gen(function* () {
|
|
|
7294
7327
|
const recall = Effect.fn("Audits.recall")(function* (identity) {
|
|
7295
7328
|
const setup = yield* ai.setup;
|
|
7296
7329
|
if (Option.isNone(setup)) return Option.none();
|
|
7297
|
-
const
|
|
7298
|
-
const found = Option.flatMap(yield* storedIn(
|
|
7330
|
+
const paths = pathsOf(identity, policyKey(promptFor(identity.mode), setup.value));
|
|
7331
|
+
const found = Option.flatMap(yield* storedIn(paths), (stored) => reportedFrom(paths, stored));
|
|
7299
7332
|
if (Option.isSome(found)) yield* land(identity);
|
|
7300
7333
|
return found;
|
|
7301
7334
|
});
|
|
@@ -7303,26 +7336,26 @@ const layer$5 = (cacheDir) => Layer.effect(Audits, Effect.gen(function* () {
|
|
|
7303
7336
|
const setup = yield* ai.setup;
|
|
7304
7337
|
if (Option.isNone(setup)) return Option.none();
|
|
7305
7338
|
const preparation = yield* within(prepare(client, identity), "resolve evidence");
|
|
7306
|
-
const
|
|
7307
|
-
return Option.filter(yield* storedIn(
|
|
7339
|
+
const paths = pathsOf(identity, policyKey(promptFor(identity.mode), setup.value));
|
|
7340
|
+
return Option.filter(yield* storedIn(paths), (stored) => audits$1(stored, preparation.artifacts)).pipe(Option.flatMap((stored) => reportedFrom(paths, stored)));
|
|
7308
7341
|
}).pipe(Effect.catch((error) => Effect.succeedSome({
|
|
7309
7342
|
_tag: "Failed",
|
|
7310
7343
|
issue: `the update's artifacts could not be resolved: ${issueOf$1(error)}`,
|
|
7311
7344
|
transcript: []
|
|
7312
7345
|
})));
|
|
7313
7346
|
const changes = (identity) => Effect.scoped(Effect.gen(function* () {
|
|
7314
|
-
const workspace =
|
|
7347
|
+
const workspace = workspaceFor(identity);
|
|
7315
7348
|
const held = yield* tryHold(workspace);
|
|
7316
7349
|
if (yield* readable(workspace, identity)) return yield* read$1(workspace);
|
|
7317
7350
|
if (!held) return yield* new ChangesUnavailable({ issue: "A running Audit is preparing this evidence." });
|
|
7318
7351
|
const preparation = yield* within(prepare(client, identity), "resolve evidence");
|
|
7319
|
-
yield* ensure(workspace, preparation);
|
|
7352
|
+
yield* ensure(workspace, identity, preparation);
|
|
7320
7353
|
const view = yield* read$1(workspace);
|
|
7321
7354
|
yield* prune(workspace);
|
|
7322
7355
|
return view;
|
|
7323
7356
|
})).pipe(Effect.mapError((error) => new ChangesUnavailable({ issue: issueOf$1(error) })));
|
|
7324
7357
|
const majors = (identity) => Effect.gen(function* () {
|
|
7325
|
-
const workspace =
|
|
7358
|
+
const workspace = workspaceFor(identity);
|
|
7326
7359
|
if (!(yield* readable(workspace, identity))) return [];
|
|
7327
7360
|
return yield* readMajors(workspace);
|
|
7328
7361
|
}).pipe(Effect.orElseSucceed(() => []));
|
|
@@ -7335,9 +7368,8 @@ const layer$5 = (cacheDir) => Layer.effect(Audits, Effect.gen(function* () {
|
|
|
7335
7368
|
mode: 448
|
|
7336
7369
|
}));
|
|
7337
7370
|
const started = yield* Clock.currentTimeMillis;
|
|
7338
|
-
|
|
7339
|
-
|
|
7340
|
-
const workspace = path.join(base, name);
|
|
7371
|
+
yield* Effect.forEach((yield* children(workspaces)).filter((name) => !name.endsWith(".lock")), (name) => {
|
|
7372
|
+
const workspace = path.join(workspaces, name);
|
|
7341
7373
|
return Effect.scoped(Effect.gen(function* () {
|
|
7342
7374
|
if (!(yield* tryHold(workspace))) return;
|
|
7343
7375
|
const prepared = yield* Effect.promise(async () => await stat(path.join(workspace, files.meta)).then((info) => info.mtimeMs, () => 0));
|
|
@@ -7368,8 +7400,8 @@ const layer$5 = (cacheDir) => Layer.effect(Audits, Effect.gen(function* () {
|
|
|
7368
7400
|
changes,
|
|
7369
7401
|
majors,
|
|
7370
7402
|
landed,
|
|
7371
|
-
transcript: (file) => Effect.scoped(Effect.gen(function* () {
|
|
7372
|
-
if (!(yield* tryHold(
|
|
7403
|
+
transcript: ({ file, workspace }) => Effect.scoped(Effect.gen(function* () {
|
|
7404
|
+
if (!(yield* tryHold(workspace))) return yield* new AgentFailed({ issue: "the Audit is running" });
|
|
7373
7405
|
return yield* transcript(file, ai.models);
|
|
7374
7406
|
}))
|
|
7375
7407
|
}));
|
|
@@ -7385,6 +7417,18 @@ const replaceText = Effect.fn("replaceText")(function* (file, text) {
|
|
|
7385
7417
|
yield* fs.writeFileString(temporary, text, { mode }).pipe(Effect.mapError(fileFailed("write", temporary)));
|
|
7386
7418
|
yield* fs.rename(temporary, file).pipe(Effect.mapError(fileFailed("replace", file)));
|
|
7387
7419
|
});
|
|
7420
|
+
const editFiles = Effect.fn("editFiles")(function* (root, edits) {
|
|
7421
|
+
const edited = /* @__PURE__ */ new Map();
|
|
7422
|
+
for (const { file, edit } of edits) {
|
|
7423
|
+
const next = edit(edited.get(file) ?? (yield* readText(path.join(root, file))));
|
|
7424
|
+
if (Result.isFailure(next)) return yield* new EditRefused({
|
|
7425
|
+
manifest: file,
|
|
7426
|
+
issue: next.failure
|
|
7427
|
+
});
|
|
7428
|
+
edited.set(file, next.success);
|
|
7429
|
+
}
|
|
7430
|
+
for (const [file, text] of edited) yield* replaceText(path.join(root, file), text);
|
|
7431
|
+
});
|
|
7388
7432
|
// src/project/find-up.ts
|
|
7389
7433
|
const findUp = Effect.fn("findUp")(function* (start, name) {
|
|
7390
7434
|
const fs = yield* FileSystem.FileSystem;
|
|
@@ -7782,7 +7826,6 @@ const publicTags = (url) => tags(url, { timeout: lsRemoteTimeout }).pipe(Effect.
|
|
|
7782
7826
|
const make$13 = (root, origin, readPublic = publicTags) => Effect.gen(function* () {
|
|
7783
7827
|
const exec = yield* Exec;
|
|
7784
7828
|
const fs = yield* FileSystem.FileSystem;
|
|
7785
|
-
const read = (file) => readText(file).pipe(Effect.provideService(FileSystem.FileSystem, fs));
|
|
7786
7829
|
const scanned = Effect.gen(function* () {
|
|
7787
7830
|
const files = yield* workflowFiles(root).pipe(Effect.provideService(FileSystem.FileSystem, fs));
|
|
7788
7831
|
return {
|
|
@@ -7869,17 +7912,10 @@ const make$13 = (root, origin, readPublic = publicTags) => Effect.gen(function*
|
|
|
7869
7912
|
expected: pinned && pkg.revision !== void 0 ? `${target} at ${short(pkg.revision)}` : target,
|
|
7870
7913
|
...sha === void 0 ? {} : { offered: `${target} at ${short(sha)}` }
|
|
7871
7914
|
});
|
|
7872
|
-
|
|
7873
|
-
|
|
7874
|
-
|
|
7875
|
-
|
|
7876
|
-
if (Result.isFailure(next)) return yield* new EditRefused({
|
|
7877
|
-
manifest: use.file,
|
|
7878
|
-
issue: next.failure
|
|
7879
|
-
});
|
|
7880
|
-
edited.set(use.file, next.success);
|
|
7881
|
-
}
|
|
7882
|
-
for (const [file, text] of edited) yield* replaceText(path.join(root, file), text).pipe(Effect.provideService(FileSystem.FileSystem, fs));
|
|
7915
|
+
yield* editFiles(root, group.uses.map((use) => ({
|
|
7916
|
+
file: use.file,
|
|
7917
|
+
edit: (text) => pinned ? editYamlScalar(text, use.path, `${use.name}@${sha}`, movedComment(use.comment, target)) : editYamlScalar(text, use.path, `${use.name}@${target}`)
|
|
7918
|
+
}))).pipe(Effect.provideService(FileSystem.FileSystem, fs));
|
|
7883
7919
|
});
|
|
7884
7920
|
return {
|
|
7885
7921
|
name: providerName$1,
|
|
@@ -8757,19 +8793,11 @@ const Manifest$2 = Schema.fromJsonString(Schema.Struct({
|
|
|
8757
8793
|
}));
|
|
8758
8794
|
const zipName = "upup-sparkle.zip";
|
|
8759
8795
|
const manifestName = "upup-sparkle.json";
|
|
8760
|
-
const seaKeys = {
|
|
8761
|
-
zip: `sparkle/${zipName}`,
|
|
8762
|
-
manifest: `sparkle/${manifestName}`
|
|
8763
|
-
};
|
|
8764
8796
|
const decode = (text, zip) => Schema.decodeEffect(Manifest$2)(text).pipe(Effect.map((manifest) => ({
|
|
8765
8797
|
zip,
|
|
8766
8798
|
...manifest
|
|
8767
8799
|
})), Effect.option);
|
|
8768
8800
|
const folder = () => {
|
|
8769
|
-
if (isSea()) {
|
|
8770
|
-
const assets = process.env["OTUI_ASSET_ROOT"];
|
|
8771
|
-
return assets === void 0 ? void 0 : path.join(assets, path.dirname(seaKeys.zip));
|
|
8772
|
-
}
|
|
8773
8801
|
const packageJson = findPackageJSON(import.meta.url);
|
|
8774
8802
|
return packageJson === void 0 ? void 0 : path.join(path.dirname(packageJson), "native", "dist");
|
|
8775
8803
|
};
|
|
@@ -8851,9 +8879,16 @@ ready() {
|
|
|
8851
8879
|
return 1
|
|
8852
8880
|
fi
|
|
8853
8881
|
}
|
|
8854
|
-
# A copy of what upup handed over, where only this user can write; a failure is step $1's.
|
|
8882
|
+
# A copy of what upup handed over, where only this user can write; a failure is step $1's. Others
|
|
8883
|
+
# may also read a shared one ($2): as root, Sparkle starts its progress agent from upup-sparkle's
|
|
8884
|
+
# framework as the user, so it goes in /var/tmp, whose sticky bit keeps others from moving it. An
|
|
8885
|
+
# app's copy stays private, since its owner gets it after it is checked.
|
|
8855
8886
|
secure() {
|
|
8856
|
-
|
|
8887
|
+
if [ "$mode" = root ] && [ "$2" = shared ]; then
|
|
8888
|
+
private=$(mktemp -d /var/tmp/upup.XXXXXX 2>"$log") && chmod 755 "$private" 2>"$log" || { fail "$1"; return 1; }
|
|
8889
|
+
else
|
|
8890
|
+
private=$(mktemp -d 2>"$log") || { fail "$1"; return 1; }
|
|
8891
|
+
fi
|
|
8857
8892
|
payload="$private/$(basename "$source")"
|
|
8858
8893
|
"$ditto" "$source" "$payload" 2>"$log" || { fail "$1"; return 1; }
|
|
8859
8894
|
}
|
|
@@ -8867,7 +8902,7 @@ app() {
|
|
|
8867
8902
|
if [ -e "$old" ] && [ ! -e "$dest" ]; then recover; return; fi
|
|
8868
8903
|
rm -rf "$old" "$new" 2>"$log" || { fail cleanup; return; }
|
|
8869
8904
|
if [ "$mode" = root ]; then
|
|
8870
|
-
secure copy || return
|
|
8905
|
+
secure copy private || return
|
|
8871
8906
|
"$codesign" --verify --deep --strict -R "$check" "$payload" 2>"$log" || { fail recheck; return; }
|
|
8872
8907
|
owner=$("$stat" -f %u:%g "$dest" 2>"$log") && "$chown" -R "$owner" "$payload" 2>"$log" || { fail copy; return; }
|
|
8873
8908
|
staged=$payload
|
|
@@ -8897,7 +8932,7 @@ app() {
|
|
|
8897
8932
|
# upup-sparkle's exit status: 0 installed, 2 nothing to install, 3 Sparkle would install another
|
|
8898
8933
|
# build, 4 the app is open; its last line on standard error says why.
|
|
8899
8934
|
sparkle() {
|
|
8900
|
-
secure helper || return
|
|
8935
|
+
secure helper shared || return
|
|
8901
8936
|
sum=$("$shasum" -a 256 "$payload" 2>"$log") || { fail helper; return; }
|
|
8902
8937
|
[ "\${sum%% *}" = "$check" ] || { echo "its sha256 is \${sum%% *}, not $check" >"$log"; fail helper; return; }
|
|
8903
8938
|
"$ditto" -x -k "$payload" "$private" 2>"$log" || { fail helper; return; }
|
|
@@ -9021,7 +9056,7 @@ const versionsOf = (kind, installed, offer) => {
|
|
|
9021
9056
|
target: withBuild(offer.short, offer.version)
|
|
9022
9057
|
};
|
|
9023
9058
|
};
|
|
9024
|
-
const caskInfo = brew
|
|
9059
|
+
const caskInfo = brew([
|
|
9025
9060
|
"info",
|
|
9026
9061
|
"--json=v2",
|
|
9027
9062
|
"--installed",
|
|
@@ -9283,7 +9318,7 @@ const makeWith = (options) => Effect.gen(function* () {
|
|
|
9283
9318
|
const queue = yield* Ref.make([]);
|
|
9284
9319
|
const using = options.tools ?? tools$2;
|
|
9285
9320
|
const helper = options.sparkle === void 0 ? locate$3.pipe(Effect.provideService(FileSystem.FileSystem, fs)) : Effect.succeed(options.sparkle);
|
|
9286
|
-
const
|
|
9321
|
+
const sparkleHelper = (pkg, install) => {
|
|
9287
9322
|
const refused = (reason) => new InstallRefused({
|
|
9288
9323
|
package: pkg.name,
|
|
9289
9324
|
reason
|
|
@@ -9294,10 +9329,8 @@ const makeWith = (options) => Effect.gen(function* () {
|
|
|
9294
9329
|
if (Option.isNone(found)) return yield* refused("this copy of upup has no upup-sparkle, which installs Sparkle apps' updates; build it with `vp run sparkle`");
|
|
9295
9330
|
if (install.installationType === "package" && found.value.team === null) return yield* refused("its update is an installer package, which Sparkle installs only through an upup-sparkle signed with a Developer ID, and this copy of upup's is signed ad hoc");
|
|
9296
9331
|
return {
|
|
9297
|
-
|
|
9298
|
-
helper: found.value
|
|
9299
|
-
build,
|
|
9300
|
-
feed: install.feed
|
|
9332
|
+
...install,
|
|
9333
|
+
helper: found.value
|
|
9301
9334
|
};
|
|
9302
9335
|
});
|
|
9303
9336
|
};
|
|
@@ -9322,21 +9355,23 @@ const makeWith = (options) => Effect.gen(function* () {
|
|
|
9322
9355
|
const inside = yield* hosts.pipe(Effect.mapError((error) => refused(`upup could not tell which app it runs in, so it risks none: ${describeError(error)}`)));
|
|
9323
9356
|
if (inside.paths.has(pkg.id) || inside.ids.has(bundle.bundleId)) return yield* refused(`upup is running inside ${pkg.name}; update it from another terminal app`);
|
|
9324
9357
|
yield* unchanged$1(pkg, plist);
|
|
9325
|
-
const planned = install.kind === "sparkle" ? yield*
|
|
9358
|
+
const planned = install.kind === "sparkle" ? yield* sparkleHelper(pkg, install) : install;
|
|
9326
9359
|
const writable = yield* Effect.isSuccess(Effect.all([fs.access(pkg.id, { writable: true }), fs.access(path.dirname(pkg.id), { writable: true })]));
|
|
9327
|
-
const ownsApp = install.kind === "sparkle" && (yield* owned(pkg.id));
|
|
9328
9360
|
const quitAllowed = permission?.quitApps === true;
|
|
9329
9361
|
yield* gate(pkg, bundle.bundleId, quitAllowed);
|
|
9330
9362
|
const team = yield* teamOf(pkg.id);
|
|
9331
9363
|
if (team === void 0) return yield* refused("it is not signed by a developer team, so upup cannot check its update");
|
|
9332
|
-
const version = {
|
|
9333
|
-
key: install.kind === "sparkle" ? "CFBundleVersion" : "CFBundleShortVersionString",
|
|
9334
|
-
value: offer.version
|
|
9335
|
-
};
|
|
9336
9364
|
const prepared = planned.kind === "sparkle" ? {
|
|
9337
|
-
|
|
9338
|
-
|
|
9339
|
-
|
|
9365
|
+
update: {
|
|
9366
|
+
kind: "sparkle",
|
|
9367
|
+
helper: planned.helper,
|
|
9368
|
+
build: offer.version,
|
|
9369
|
+
feed: planned.feed,
|
|
9370
|
+
requirement: requirement(bundle.bundleId, team)
|
|
9371
|
+
},
|
|
9372
|
+
dir: yield* room(pkg.name),
|
|
9373
|
+
root: !writable || planned.installationType === "package" || !(yield* owned(pkg.id))
|
|
9374
|
+
} : yield* Effect.map(stage(client, {
|
|
9340
9375
|
name: pkg.name,
|
|
9341
9376
|
url: planned.url,
|
|
9342
9377
|
...planned.size === void 0 ? {} : { size: planned.size },
|
|
@@ -9345,18 +9380,19 @@ const makeWith = (options) => Effect.gen(function* () {
|
|
|
9345
9380
|
team,
|
|
9346
9381
|
arch: listing.here.arch,
|
|
9347
9382
|
version: offer.version
|
|
9348
|
-
})
|
|
9349
|
-
|
|
9383
|
+
}), (staged) => ({
|
|
9384
|
+
update: staged,
|
|
9385
|
+
dir: staged.dir,
|
|
9386
|
+
root: !writable
|
|
9387
|
+
}));
|
|
9350
9388
|
yield* Ref.update(queue, (all) => [...all, {
|
|
9351
9389
|
pkg,
|
|
9352
9390
|
bundleId: bundle.bundleId,
|
|
9353
9391
|
executable: path.join("Contents", "MacOS", bundle.executable ?? pkg.name),
|
|
9354
9392
|
installed: plist,
|
|
9355
|
-
|
|
9356
|
-
dir,
|
|
9393
|
+
...prepared,
|
|
9357
9394
|
quitAllowed,
|
|
9358
|
-
|
|
9359
|
-
version,
|
|
9395
|
+
version: offer.version,
|
|
9360
9396
|
team
|
|
9361
9397
|
}]);
|
|
9362
9398
|
}, provide);
|
|
@@ -9366,9 +9402,10 @@ const makeWith = (options) => Effect.gen(function* () {
|
|
|
9366
9402
|
if (now.value === item.installed) return replaceable(now.value);
|
|
9367
9403
|
const { info, digest } = yield* readInfoStable(item.pkg.id);
|
|
9368
9404
|
if (Option.isNone(info) || digest !== now.value || info.value.CFBundleIdentifier !== item.bundleId || (yield* teamOf(item.pkg.id)) !== item.team) return changed;
|
|
9369
|
-
const
|
|
9370
|
-
|
|
9371
|
-
|
|
9405
|
+
const sparkle = item.update.kind === "sparkle";
|
|
9406
|
+
const version = sparkle ? info.value.CFBundleVersion : info.value.CFBundleShortVersionString;
|
|
9407
|
+
if (version === item.version) return alreadyUpdated;
|
|
9408
|
+
return version !== void 0 && (sparkle ? isNewer(item.version, version) : isNewerRelease(item.version, version)) ? replaceable(now.value) : changed;
|
|
9372
9409
|
}).pipe(Effect.orElseSucceed(() => changed));
|
|
9373
9410
|
const ready = (item) => Effect.gen(function* () {
|
|
9374
9411
|
const now = yield* installedNow(item);
|
|
@@ -9473,7 +9510,7 @@ const makeWith = (options) => Effect.gen(function* () {
|
|
|
9473
9510
|
uninstall: Effect.fn("Apps.uninstall")(function* (pkg) {
|
|
9474
9511
|
const token = (yield* Ref.get(memory))?.rows.get(pkg.id)?.cask;
|
|
9475
9512
|
if (token === void 0) return yield* new Unsupported({ reason: unremovable$1 });
|
|
9476
|
-
yield* exec.stdout(brew
|
|
9513
|
+
yield* exec.stdout(brew([
|
|
9477
9514
|
"uninstall",
|
|
9478
9515
|
"--cask",
|
|
9479
9516
|
token
|
|
@@ -9927,6 +9964,11 @@ const matchesGoPattern = (pattern, path) => {
|
|
|
9927
9964
|
const prefix = segments.slice(0, parts.length).join("/");
|
|
9928
9965
|
return new RegExp(`^${parts.map((part) => RegExp.escape(part).replaceAll("\\*", "[^/]*").replaceAll("\\?", "[^/]")).join("/")}$`, "u").test(prefix);
|
|
9929
9966
|
};
|
|
9967
|
+
const GoProxyEnv = Schema.Struct({
|
|
9968
|
+
GOPROXY: Schema.optionalKey(Schema.String),
|
|
9969
|
+
GOPRIVATE: Schema.optionalKey(Schema.String),
|
|
9970
|
+
GONOPROXY: Schema.optionalKey(Schema.String)
|
|
9971
|
+
});
|
|
9930
9972
|
const privateGoModule = (env, path) => {
|
|
9931
9973
|
if (goPatterns(env.GONOPROXY === void 0 || env.GONOPROXY === "" ? env.GOPRIVATE ?? "" : env.GONOPROXY).some((pattern) => matchesGoPattern(pattern, path))) return "a GOPRIVATE module";
|
|
9932
9974
|
const [proxy] = goPatterns((env.GOPROXY ?? "https://proxy.golang.org,direct").replaceAll("|", ","));
|
|
@@ -9944,7 +9986,21 @@ const privatePypiIndex = (env = process.env) => {
|
|
|
9944
9986
|
const index = env["UV_DEFAULT_INDEX"] ?? env["UV_INDEX_URL"] ?? env["PIP_INDEX_URL"];
|
|
9945
9987
|
return index === void 0 || index === "" || publicPypi.has(trailing(index)) ? void 0 : index;
|
|
9946
9988
|
};
|
|
9989
|
+
const withPypiOrigin = (index) => (pkg) => index === void 0 ? pkg : {
|
|
9990
|
+
...pkg,
|
|
9991
|
+
privateRegistry: index
|
|
9992
|
+
};
|
|
9947
9993
|
// src/go/go-json.ts
|
|
9994
|
+
const go = (cwd, args, env = {}) => ({
|
|
9995
|
+
command: "go",
|
|
9996
|
+
args,
|
|
9997
|
+
cwd,
|
|
9998
|
+
env: {
|
|
9999
|
+
GOWORK: "off",
|
|
10000
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
10001
|
+
...env
|
|
10002
|
+
}
|
|
10003
|
+
});
|
|
9948
10004
|
const decodeGoJson = (schema, command) => decodeJson(Schema.toCodecGoJson(schema), command);
|
|
9949
10005
|
const jsonObjects = (text) => {
|
|
9950
10006
|
const objects = [];
|
|
@@ -9973,22 +10029,14 @@ const jsonObjects = (text) => {
|
|
|
9973
10029
|
const GoEnv = Schema.Struct({
|
|
9974
10030
|
GOBIN: Schema.String,
|
|
9975
10031
|
GOPATH: Schema.String,
|
|
9976
|
-
|
|
9977
|
-
GOPRIVATE: Schema.optionalKey(Schema.String),
|
|
9978
|
-
GONOPROXY: Schema.optionalKey(Schema.String)
|
|
10032
|
+
...GoProxyEnv.fields
|
|
9979
10033
|
});
|
|
9980
|
-
const envKeys =
|
|
9981
|
-
"GOBIN",
|
|
9982
|
-
"GOPATH",
|
|
9983
|
-
"GOPROXY",
|
|
9984
|
-
"GOPRIVATE",
|
|
9985
|
-
"GONOPROXY"
|
|
9986
|
-
];
|
|
10034
|
+
const envKeys = Object.keys(GoEnv.fields);
|
|
9987
10035
|
const BuildInfo = Schema.Struct({
|
|
9988
|
-
Path: Schema.String,
|
|
10036
|
+
Path: Schema.optionalKey(Schema.String),
|
|
9989
10037
|
Main: Schema.Struct({
|
|
9990
|
-
Path: Schema.String,
|
|
9991
|
-
Version: Schema.String,
|
|
10038
|
+
Path: Schema.optionalKey(Schema.String),
|
|
10039
|
+
Version: Schema.optionalKey(Schema.String),
|
|
9992
10040
|
Sum: Schema.optionalKey(Schema.String),
|
|
9993
10041
|
Replace: Schema.optionalKey(Schema.Unknown)
|
|
9994
10042
|
})
|
|
@@ -9998,36 +10046,27 @@ const ModuleQuery = Schema.Struct({
|
|
|
9998
10046
|
Version: Schema.String,
|
|
9999
10047
|
Error: Schema.optionalKey(Schema.Struct({ Err: Schema.String }))
|
|
10000
10048
|
});
|
|
10001
|
-
const go = (args, env = {}) => ({
|
|
10002
|
-
command: "go",
|
|
10003
|
-
args,
|
|
10004
|
-
cwd: "/",
|
|
10005
|
-
env: {
|
|
10006
|
-
GOWORK: "off",
|
|
10007
|
-
GIT_TERMINAL_PROMPT: "0",
|
|
10008
|
-
...env
|
|
10009
|
-
}
|
|
10010
|
-
});
|
|
10011
10049
|
const executableName = (importPath) => {
|
|
10012
10050
|
const elements = importPath.split("/");
|
|
10013
10051
|
const last = elements.at(-1) ?? importPath;
|
|
10014
10052
|
return /^v\d+$/u.test(last) && elements.length > 1 ? elements.at(-2) ?? last : last;
|
|
10015
10053
|
};
|
|
10016
10054
|
const fromBuildInfo = (info, file) => {
|
|
10017
|
-
const { Main: main } = info;
|
|
10018
|
-
|
|
10055
|
+
const { Path: importPath, Main: main } = info;
|
|
10056
|
+
const { Path: module, Version: version } = main;
|
|
10057
|
+
return importPath !== void 0 && module !== void 0 && version !== void 0 && main.Sum !== void 0 && main.Replace === void 0 && semver.valid(version) !== null && (importPath === module || importPath.startsWith(`${module}/`)) && executableName(importPath) === file ? Option.some({
|
|
10019
10058
|
provider: "go-install",
|
|
10020
|
-
id:
|
|
10059
|
+
id: importPath,
|
|
10021
10060
|
name: file,
|
|
10022
10061
|
ecosystem: "go",
|
|
10023
|
-
artifact:
|
|
10024
|
-
current:
|
|
10062
|
+
artifact: module,
|
|
10063
|
+
current: version
|
|
10025
10064
|
}) : Option.none();
|
|
10026
10065
|
};
|
|
10027
10066
|
const make$8 = Effect.gen(function* () {
|
|
10028
10067
|
const exec = yield* Exec;
|
|
10029
10068
|
const fs = yield* FileSystem.FileSystem;
|
|
10030
|
-
const envInvocation = go([
|
|
10069
|
+
const envInvocation = go("/", [
|
|
10031
10070
|
"env",
|
|
10032
10071
|
"-json",
|
|
10033
10072
|
...envKeys
|
|
@@ -10035,7 +10074,7 @@ const make$8 = Effect.gen(function* () {
|
|
|
10035
10074
|
const goEnv = yield* Effect.cached(exec.stdout(envInvocation).pipe(Effect.flatMap(decodeGoJson(GoEnv, commandLine(envInvocation)))));
|
|
10036
10075
|
const binDir = goEnv.pipe(Effect.map((env) => env.GOBIN || path.join(env.GOPATH.split(":")[0] ?? env.GOPATH, "bin")));
|
|
10037
10076
|
const inspect = Effect.fn("GoInstall.inspect")(function* (dir, file) {
|
|
10038
|
-
const invocation = go([
|
|
10077
|
+
const invocation = go("/", [
|
|
10039
10078
|
"version",
|
|
10040
10079
|
"-m",
|
|
10041
10080
|
"-json",
|
|
@@ -10057,7 +10096,7 @@ const make$8 = Effect.gen(function* () {
|
|
|
10057
10096
|
});
|
|
10058
10097
|
const latest = Effect.fn("GoInstall.latest")(function* (modules) {
|
|
10059
10098
|
if (modules.length === 0) return /* @__PURE__ */ new Map();
|
|
10060
|
-
const invocation = go([
|
|
10099
|
+
const invocation = go("/", [
|
|
10061
10100
|
"list",
|
|
10062
10101
|
"-m",
|
|
10063
10102
|
"-e",
|
|
@@ -10107,7 +10146,7 @@ const make$8 = Effect.gen(function* () {
|
|
|
10107
10146
|
}),
|
|
10108
10147
|
update: Effect.fn("GoInstall.update")(function* (pkg, target) {
|
|
10109
10148
|
const dir = yield* binDir;
|
|
10110
|
-
yield* exec.stdout(go([
|
|
10149
|
+
yield* exec.stdout(go("/", [
|
|
10111
10150
|
"install",
|
|
10112
10151
|
"--",
|
|
10113
10152
|
`${pkg.id}@${target}`
|
|
@@ -10140,27 +10179,12 @@ const WorkFile = Schema.Struct({
|
|
|
10140
10179
|
Use: Schema.optionalKey(Schema.Array(Schema.Struct({ DiskPath: Schema.String }))),
|
|
10141
10180
|
Replace: Schema.optionalKey(Schema.Array(Schema.Struct({ Old: Schema.Struct({ Path: Schema.String }) })))
|
|
10142
10181
|
});
|
|
10143
|
-
const goEnv = {
|
|
10144
|
-
GOWORK: "off",
|
|
10145
|
-
GIT_TERMINAL_PROMPT: "0"
|
|
10146
|
-
};
|
|
10147
|
-
const GoProxyEnv = Schema.Struct({
|
|
10148
|
-
GOPROXY: Schema.optionalKey(Schema.String),
|
|
10149
|
-
GOPRIVATE: Schema.optionalKey(Schema.String),
|
|
10150
|
-
GONOPROXY: Schema.optionalKey(Schema.String)
|
|
10151
|
-
});
|
|
10152
10182
|
const directRequirements = (mod, local) => {
|
|
10153
10183
|
const replaced = new Set((mod.Replace ?? []).map((replace) => replace.Old.Path));
|
|
10154
10184
|
return (mod.Require ?? []).filter((requirement) => requirement.Indirect !== true && !replaced.has(requirement.Path) && !local.has(requirement.Path));
|
|
10155
10185
|
};
|
|
10156
|
-
const goIn = (cwd, args) => ({
|
|
10157
|
-
command: "go",
|
|
10158
|
-
args,
|
|
10159
|
-
cwd,
|
|
10160
|
-
env: goEnv
|
|
10161
|
-
});
|
|
10162
10186
|
const readModFile = (exec, cwd) => {
|
|
10163
|
-
const edit =
|
|
10187
|
+
const edit = go(cwd, [
|
|
10164
10188
|
"mod",
|
|
10165
10189
|
"edit",
|
|
10166
10190
|
"-json"
|
|
@@ -10170,13 +10194,13 @@ const readModFile = (exec, cwd) => {
|
|
|
10170
10194
|
const make$7 = (root, moduleDir, place = "", local = /* @__PURE__ */ new Set()) => Effect.gen(function* () {
|
|
10171
10195
|
const exec = yield* Exec;
|
|
10172
10196
|
const manifest = path.join(place, path.relative(root, path.join(moduleDir, "go.mod")));
|
|
10173
|
-
const
|
|
10197
|
+
const inModule = (args) => go(moduleDir, args);
|
|
10174
10198
|
const requirements = Effect.gen(function* () {
|
|
10175
10199
|
return directRequirements(yield* readModFile(exec, moduleDir), local);
|
|
10176
10200
|
});
|
|
10177
10201
|
const selected = Effect.fn("GoModule.selected")(function* (paths, withUpdates) {
|
|
10178
10202
|
if (paths.length === 0) return /* @__PURE__ */ new Map();
|
|
10179
|
-
const list =
|
|
10203
|
+
const list = inModule([
|
|
10180
10204
|
"list",
|
|
10181
10205
|
"-m",
|
|
10182
10206
|
...withUpdates ? ["-u"] : [],
|
|
@@ -10202,12 +10226,10 @@ const make$7 = (root, moduleDir, place = "", local = /* @__PURE__ */ new Set())
|
|
|
10202
10226
|
selector: requirement.Version
|
|
10203
10227
|
}
|
|
10204
10228
|
});
|
|
10205
|
-
const env =
|
|
10229
|
+
const env = inModule([
|
|
10206
10230
|
"env",
|
|
10207
10231
|
"-json",
|
|
10208
|
-
|
|
10209
|
-
"GOPRIVATE",
|
|
10210
|
-
"GONOPROXY"
|
|
10232
|
+
...Object.keys(GoProxyEnv.fields)
|
|
10211
10233
|
]);
|
|
10212
10234
|
const origin = exec.stdout(env).pipe(Effect.flatMap(decodeGoJson(GoProxyEnv, commandLine(env))), Effect.map(withGoOrigin));
|
|
10213
10235
|
const list = Effect.gen(function* () {
|
|
@@ -10238,16 +10260,16 @@ const make$7 = (root, moduleDir, place = "", local = /* @__PURE__ */ new Set())
|
|
|
10238
10260
|
return Option.some(toPackage(requirement, entries.get(requirement.Path)));
|
|
10239
10261
|
});
|
|
10240
10262
|
const update = Effect.fn("GoModule.update")(function* (pkg, target) {
|
|
10241
|
-
yield* exec.stdout(
|
|
10263
|
+
yield* exec.stdout(inModule(["get", `${pkg.id}@${target}`]));
|
|
10242
10264
|
});
|
|
10243
10265
|
const uninstall = Effect.fn("GoModule.uninstall")(function* (pkg) {
|
|
10244
|
-
yield* exec.stdout(
|
|
10266
|
+
yield* exec.stdout(inModule([
|
|
10245
10267
|
"mod",
|
|
10246
10268
|
"edit",
|
|
10247
10269
|
`-droprequire=${pkg.id}`
|
|
10248
10270
|
]));
|
|
10249
10271
|
});
|
|
10250
|
-
const reconcile = () => exec.stdout(
|
|
10272
|
+
const reconcile = () => exec.stdout(inModule(["mod", "tidy"])).pipe(Effect.as(void 0));
|
|
10251
10273
|
return {
|
|
10252
10274
|
name: manifest,
|
|
10253
10275
|
mode: "project",
|
|
@@ -10663,7 +10685,6 @@ const makeVp = makeGlobal({
|
|
|
10663
10685
|
list: [
|
|
10664
10686
|
"list",
|
|
10665
10687
|
"-g",
|
|
10666
|
-
"--depth=0",
|
|
10667
10688
|
"--json"
|
|
10668
10689
|
],
|
|
10669
10690
|
outdated: [
|
|
@@ -10796,7 +10817,6 @@ const make$6 = (root, dir = root, nested = []) => Effect.gen(function* () {
|
|
|
10796
10817
|
const client = yield* HttpClient.HttpClient;
|
|
10797
10818
|
const context = yield* Effect.context();
|
|
10798
10819
|
const scanned = scan(root, dir, nested).pipe(Effect.provideContext(context));
|
|
10799
|
-
const read = (file) => readText(path.join(root, file)).pipe(Effect.provideService(FileSystem.FileSystem, fs));
|
|
10800
10820
|
const list = Effect.gen(function* () {
|
|
10801
10821
|
const pins = yield* scanned;
|
|
10802
10822
|
const notices = [];
|
|
@@ -10835,19 +10855,15 @@ const make$6 = (root, dir = root, nested = []) => Effect.gen(function* () {
|
|
|
10835
10855
|
manifest: pkg.declaration?.manifest ?? "",
|
|
10836
10856
|
issue: `Node.js ${pkg.current} is no longer pinned there`
|
|
10837
10857
|
});
|
|
10838
|
-
|
|
10839
|
-
|
|
10840
|
-
|
|
10841
|
-
|
|
10842
|
-
|
|
10843
|
-
|
|
10844
|
-
|
|
10845
|
-
|
|
10846
|
-
|
|
10847
|
-
});
|
|
10848
|
-
edited.set(pin.file, moved.success);
|
|
10849
|
-
}
|
|
10850
|
-
for (const [file, text] of edited) yield* replaceText(path.join(root, file), text).pipe(Effect.provideService(FileSystem.FileSystem, fs));
|
|
10858
|
+
yield* editFiles(root, group.map((pin) => ({
|
|
10859
|
+
file: pin.file,
|
|
10860
|
+
edit: (text) => {
|
|
10861
|
+
const next = `${pin.prefix}${target}`;
|
|
10862
|
+
if (pin.path !== void 0) return editYamlScalar(text, pin.path, next);
|
|
10863
|
+
const { parts, at } = versionLine(text);
|
|
10864
|
+
return Result.succeed(parts.map((part, index) => index === at ? part.replace(`${pin.prefix}${pin.version}`, next) : part).join(""));
|
|
10865
|
+
}
|
|
10866
|
+
}))).pipe(Effect.provideService(FileSystem.FileSystem, fs));
|
|
10851
10867
|
});
|
|
10852
10868
|
return {
|
|
10853
10869
|
name: providerName,
|
|
@@ -11158,7 +11174,7 @@ const make$5 = (root, manager, place = "", claimed = []) => Effect.gen(function*
|
|
|
11158
11174
|
message: line.failure
|
|
11159
11175
|
});
|
|
11160
11176
|
const target = Result.getOrUndefined(line);
|
|
11161
|
-
if (target === void 0
|
|
11177
|
+
if (target === void 0) return pkg;
|
|
11162
11178
|
const selector = parseSelector(pkg.name, pkg.declaration?.selector ?? "");
|
|
11163
11179
|
if (selector === void 0 || moveTo(selector, target) === void 0) {
|
|
11164
11180
|
notices.push({
|
|
@@ -11829,13 +11845,10 @@ const make = Effect.gen(function* () {
|
|
|
11829
11845
|
"--show-python"
|
|
11830
11846
|
])).pipe(Effect.map(parseTools))], { concurrency: "unbounded" });
|
|
11831
11847
|
const targets = new Map(outdated.flatMap((tool) => tool.fromPyPI && tool.latest !== void 0 ? [[tool.pkg.id, tool.latest]] : []));
|
|
11832
|
-
const
|
|
11848
|
+
const origin = withPypiOrigin(privatePypiIndex());
|
|
11833
11849
|
return {
|
|
11834
11850
|
packages: packages.map((listed) => {
|
|
11835
|
-
const pkg =
|
|
11836
|
-
...listed,
|
|
11837
|
-
privateRegistry: index
|
|
11838
|
-
};
|
|
11851
|
+
const pkg = origin(listed);
|
|
11839
11852
|
const target = targets.get(pkg.id);
|
|
11840
11853
|
return target === void 0 ? pkg : withTarget(pkg, target);
|
|
11841
11854
|
}),
|
|
@@ -11927,12 +11940,12 @@ const deprecationOf = (formula) => {
|
|
|
11927
11940
|
if (formula.disabled) return `Homebrew disabled it (${formula.disable_reason ?? "no reason given"})`;
|
|
11928
11941
|
if (formula.deprecated) return formula.deprecation_reason ?? "no reason given";
|
|
11929
11942
|
};
|
|
11930
|
-
const lookup$
|
|
11943
|
+
const lookup$3 = Effect.fn("brew.lookup")(function* (client, wanted) {
|
|
11931
11944
|
if (wanted.name.includes("/")) return yield* new MetadataUnavailable({
|
|
11932
11945
|
source: wanted.name,
|
|
11933
11946
|
issue: "Homebrew's API only describes formulae and casks from the core taps"
|
|
11934
11947
|
});
|
|
11935
|
-
const kind = wanted.kind
|
|
11948
|
+
const kind = wanted.kind ?? "formula";
|
|
11936
11949
|
const formula = yield* getJson(client, `https://formulae.brew.sh/api/${kind}/${wanted.name}.json`, Formula);
|
|
11937
11950
|
const installs = formula.analytics?.install["30d"][wanted.name];
|
|
11938
11951
|
const deprecated = deprecationOf(formula);
|
|
@@ -11960,7 +11973,7 @@ const Crate = Schema.Struct({
|
|
|
11960
11973
|
yank_message: Schema.NullOr(Schema.String)
|
|
11961
11974
|
}))
|
|
11962
11975
|
});
|
|
11963
|
-
const lookup$
|
|
11976
|
+
const lookup$2 = Effect.fn("crates.lookup")(function* (client, wanted) {
|
|
11964
11977
|
const { crate, versions } = yield* getJson(client, `https://crates.io/api/v1/crates/${wanted.name}`, Crate);
|
|
11965
11978
|
const relevant = versions.filter((version) => wanted.versions.includes(version.num));
|
|
11966
11979
|
return {
|
|
@@ -11981,7 +11994,7 @@ const Repository = Schema.Struct({
|
|
|
11981
11994
|
archived: Schema.Boolean
|
|
11982
11995
|
});
|
|
11983
11996
|
const Release = Schema.Struct({ published_at: Schema.NullOr(Schema.String) });
|
|
11984
|
-
const lookup$
|
|
11997
|
+
const lookup$1 = Effect.fn("githubActions.lookup")(function* (client, wanted) {
|
|
11985
11998
|
const token = yield* githubToken.pipe(Effect.provide(nodeLayer));
|
|
11986
11999
|
const headers = githubHeaders(token);
|
|
11987
12000
|
const base = `${githubApi}/repos/${wanted.name}`;
|
|
@@ -11997,41 +12010,6 @@ const lookup$2 = Effect.fn("githubActions.lookup")(function* (client, wanted) {
|
|
|
11997
12010
|
withdrawn: {}
|
|
11998
12011
|
};
|
|
11999
12012
|
});
|
|
12000
|
-
// src/registry/npm.ts
|
|
12001
|
-
const Version = Schema.Struct({ deprecated: Schema.optionalKey(Schema.Unknown) });
|
|
12002
|
-
const Packument = Schema.Struct({
|
|
12003
|
-
description: Schema.optionalKey(Schema.String),
|
|
12004
|
-
homepage: Schema.optionalKey(Schema.String),
|
|
12005
|
-
repository: Schema.optionalKey(Schema.Union([Schema.String, Schema.Struct({ url: Schema.optionalKey(Schema.String) })])),
|
|
12006
|
-
"dist-tags": Schema.optionalKey(Schema.Struct({ latest: Schema.optionalKey(Schema.String) })),
|
|
12007
|
-
time: Schema.optionalKey(Schema.Record(Schema.String, Schema.String)),
|
|
12008
|
-
versions: Schema.optionalKey(Schema.Record(Schema.String, Version))
|
|
12009
|
-
});
|
|
12010
|
-
const Downloads = Schema.Struct({ downloads: Schema.Finite });
|
|
12011
|
-
const message = (version) => {
|
|
12012
|
-
const deprecated = version?.deprecated;
|
|
12013
|
-
return Predicate.isString(deprecated) && deprecated !== "" ? Option.some(deprecated) : Option.none();
|
|
12014
|
-
};
|
|
12015
|
-
const lookup$1 = Effect.fn("npm.lookup")(function* (client, wanted) {
|
|
12016
|
-
const path = wanted.name.replace("/", "%2F");
|
|
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" });
|
|
12018
|
-
const versions = packument.versions ?? {};
|
|
12019
|
-
const latest = packument["dist-tags"]?.latest;
|
|
12020
|
-
const repository = Predicate.isString(packument.repository) ? packument.repository : packument.repository?.url;
|
|
12021
|
-
const deprecated = latest === void 0 ? Option.none() : message(versions[latest]);
|
|
12022
|
-
return {
|
|
12023
|
-
...packument.description === void 0 ? {} : { description: packument.description },
|
|
12024
|
-
...packument.homepage === void 0 ? {} : { homepage: packument.homepage },
|
|
12025
|
-
...repository === void 0 ? {} : { repository: repositoryUrl(repository) },
|
|
12026
|
-
...Option.isSome(downloads) ? { popularity: `${count(downloads.value.downloads)} downloads last week` } : {},
|
|
12027
|
-
...Option.isSome(deprecated) ? { deprecated: deprecated.value } : {},
|
|
12028
|
-
released: pick$1(packument.time ?? {}, wanted.versions),
|
|
12029
|
-
withdrawn: Object.fromEntries(wanted.versions.flatMap((version) => Option.match(message(versions[version]), {
|
|
12030
|
-
onNone: () => [],
|
|
12031
|
-
onSome: (reason) => [[version, reason]]
|
|
12032
|
-
})))
|
|
12033
|
-
};
|
|
12034
|
-
});
|
|
12035
12013
|
// src/registry/pypi.ts
|
|
12036
12014
|
const Project = Schema.Struct({
|
|
12037
12015
|
info: Schema.Struct({
|
|
@@ -12081,12 +12059,12 @@ const vendor = (source, issue) => (_, wanted) => Effect.fail(new MetadataUnavail
|
|
|
12081
12059
|
issue: `${wanted.name} ${issue}`
|
|
12082
12060
|
}));
|
|
12083
12061
|
const sources = {
|
|
12084
|
-
brew: lookup$
|
|
12085
|
-
npm: lookup$
|
|
12086
|
-
crates: lookup$
|
|
12062
|
+
brew: lookup$3,
|
|
12063
|
+
npm: lookup$4,
|
|
12064
|
+
crates: lookup$2,
|
|
12087
12065
|
go: lookup$5,
|
|
12088
12066
|
pypi: lookup,
|
|
12089
|
-
"github-actions": lookup$
|
|
12067
|
+
"github-actions": lookup$1,
|
|
12090
12068
|
macos: vendor("Software Update", "comes from Apple's Software Update, which has no registry"),
|
|
12091
12069
|
apt: vendor("apt", "comes from your distribution's apt repositories, which upup does not read"),
|
|
12092
12070
|
sparkle: vendor("Sparkle", "updates from its own Sparkle feed, which has no registry"),
|
|
@@ -12103,7 +12081,7 @@ const freshFor = 864e5;
|
|
|
12103
12081
|
const wanted = (pkg) => ({
|
|
12104
12082
|
name: pkg.artifact,
|
|
12105
12083
|
versions: [pkg.current, ...pkg.target === void 0 ? [] : [pkg.target]],
|
|
12106
|
-
...
|
|
12084
|
+
...kindOf$2(pkg) === "cask" ? { kind: "cask" } : {}
|
|
12107
12085
|
});
|
|
12108
12086
|
const layer$2 = (cacheDir) => Layer.effect(Registry, Effect.gen(function* () {
|
|
12109
12087
|
const client = yield* HttpClient.HttpClient;
|
|
@@ -12440,15 +12418,16 @@ const auditTools = (home) => Action.implement(AuditActions, Effect.gen(function*
|
|
|
12440
12418
|
const audits = yield* Audits;
|
|
12441
12419
|
const ai = yield* Ai;
|
|
12442
12420
|
const status = (pkg, mode) => Effect.gen(function* () {
|
|
12443
|
-
const
|
|
12444
|
-
if (
|
|
12445
|
-
const reason =
|
|
12421
|
+
const audit = auditOf(pkg, mode);
|
|
12422
|
+
if (Result.isFailure(audit)) {
|
|
12423
|
+
const reason = audit.failure;
|
|
12446
12424
|
return {
|
|
12447
12425
|
key: rowKey(pkg),
|
|
12448
12426
|
status: "not-auditable",
|
|
12449
12427
|
reason: `${reason.charAt(0).toUpperCase()}${reason.slice(1)}.`
|
|
12450
12428
|
};
|
|
12451
12429
|
}
|
|
12430
|
+
const identity = audit.success;
|
|
12452
12431
|
const job = (yield* audits.jobs)[jobKey(identity)];
|
|
12453
12432
|
if (job?._tag === "Running") return {
|
|
12454
12433
|
key: rowKey(pkg),
|
|
@@ -12481,17 +12460,17 @@ const auditTools = (home) => Action.implement(AuditActions, Effect.gen(function*
|
|
|
12481
12460
|
}),
|
|
12482
12461
|
package_changes: ({ key, path, ...where }) => Effect.gen(function* () {
|
|
12483
12462
|
const { scope, pkg } = yield* resolve.one(where, key);
|
|
12484
|
-
const
|
|
12485
|
-
if (
|
|
12463
|
+
const audit = auditOf(pkg, scope.mode);
|
|
12464
|
+
if (Result.isFailure(audit)) {
|
|
12486
12465
|
if (pkg.target === void 0) return yield* new ChangesUnavailable({ issue: "No update is offered." });
|
|
12487
|
-
if (pkg.notes === void 0) return yield* new ChangesUnavailable({ issue: `Nothing to compare: ${
|
|
12466
|
+
if (pkg.notes === void 0) return yield* new ChangesUnavailable({ issue: `Nothing to compare: ${audit.failure}${isAppUpdate(pkg) ? ", and its feed has no release notes" : ""}.` });
|
|
12488
12467
|
if (path !== void 0) return yield* new ChangesUnavailable({ issue: `${pkg.name}'s update has release notes but no files to diff; leave out path.` });
|
|
12489
12468
|
return {
|
|
12490
12469
|
...versions(pkg),
|
|
12491
12470
|
notes: pkg.notes
|
|
12492
12471
|
};
|
|
12493
12472
|
}
|
|
12494
|
-
const view = yield* audits.changes(
|
|
12473
|
+
const view = yield* audits.changes(audit.success);
|
|
12495
12474
|
const files = view.sections.map((section) => ({
|
|
12496
12475
|
path: sectionPath(section),
|
|
12497
12476
|
...changedLines(section),
|
|
@@ -12796,33 +12775,34 @@ const reasonFor = (result) => Option.match(result, {
|
|
|
12796
12775
|
onNone: () => "it has no finished audit of these exact artifacts",
|
|
12797
12776
|
onSome: (found) => found._tag === "Failed" ? `its audit failed: ${found.issue}` : `its audit found ${found.report.verdict}`
|
|
12798
12777
|
});
|
|
12778
|
+
const approves = (result) => Option.isSome(result) && result.value._tag === "Reported" && result.value.report.verdict === "ok";
|
|
12799
12779
|
const screen = (targets, mode, resultOf) => Effect.gen(function* () {
|
|
12800
|
-
const identities = /* @__PURE__ */ new Map();
|
|
12801
|
-
for (const target of targets) {
|
|
12802
|
-
const identity = identityOf(target.pkg, mode);
|
|
12803
|
-
if (identity !== void 0) identities.set(workspaceKey(identity), identity);
|
|
12804
|
-
}
|
|
12805
|
-
const results = new Map(yield* Effect.forEach(identities, ([key, identity]) => Effect.map(resultOf(identity), (result) => [key, result]), { concurrency: 4 }));
|
|
12806
|
-
const approved = [];
|
|
12807
12780
|
const refused = {};
|
|
12781
|
+
const groups = /* @__PURE__ */ new Map();
|
|
12808
12782
|
for (const target of targets) {
|
|
12809
|
-
if (isUnauditedUpdate(target.pkg))
|
|
12810
|
-
|
|
12783
|
+
if (isUnauditedUpdate(target.pkg)) continue;
|
|
12784
|
+
const audit = auditOf(target.pkg, mode);
|
|
12785
|
+
if (Result.isFailure(audit)) {
|
|
12786
|
+
refused[rowKey(target.pkg)] = Outcome.Excluded({ reason: audit.failure });
|
|
12811
12787
|
continue;
|
|
12812
12788
|
}
|
|
12813
|
-
const
|
|
12814
|
-
const
|
|
12815
|
-
|
|
12816
|
-
|
|
12817
|
-
|
|
12818
|
-
|
|
12819
|
-
|
|
12820
|
-
}
|
|
12821
|
-
}
|
|
12822
|
-
refused[rowKey(target.pkg)] = Outcome.Excluded({ reason: result === void 0 ? unauditable(target.pkg) ?? "it has no exact update to audit" : reasonFor(result) });
|
|
12789
|
+
const key = workspaceKey(audit.success);
|
|
12790
|
+
const group = groups.get(key) ?? {
|
|
12791
|
+
identity: audit.success,
|
|
12792
|
+
members: []
|
|
12793
|
+
};
|
|
12794
|
+
group.members.push(target);
|
|
12795
|
+
groups.set(key, group);
|
|
12823
12796
|
}
|
|
12797
|
+
yield* Effect.forEach(groups.values(), ({ identity, members }) => Effect.map(resultOf(identity), (found) => {
|
|
12798
|
+
if (approves(found)) return;
|
|
12799
|
+
for (const target of members) refused[rowKey(target.pkg)] = Outcome.Excluded({ reason: reasonFor(found) });
|
|
12800
|
+
}), {
|
|
12801
|
+
concurrency: 4,
|
|
12802
|
+
discard: true
|
|
12803
|
+
});
|
|
12824
12804
|
return {
|
|
12825
|
-
approved,
|
|
12805
|
+
approved: targets.filter((target) => !Object.hasOwn(refused, rowKey(target.pkg))),
|
|
12826
12806
|
refused
|
|
12827
12807
|
};
|
|
12828
12808
|
});
|
|
@@ -13165,8 +13145,7 @@ const initial = (mode, scope, preferences, audits = {}, settingsIssue) => ({
|
|
|
13165
13145
|
selected: [],
|
|
13166
13146
|
operation: machine$1.initialState,
|
|
13167
13147
|
activity: {},
|
|
13168
|
-
|
|
13169
|
-
actions: {},
|
|
13148
|
+
ran: {},
|
|
13170
13149
|
installed: {},
|
|
13171
13150
|
removed: {},
|
|
13172
13151
|
password: void 0,
|
|
@@ -13459,8 +13438,7 @@ const layer = Layer.effect(Session, Effect.gen(function* () {
|
|
|
13459
13438
|
const reset = (mode, scope) => SubscriptionRef.update(state, (current) => {
|
|
13460
13439
|
places.set(`${current.mode}:${current.scope}`, {
|
|
13461
13440
|
selected: current.selected,
|
|
13462
|
-
|
|
13463
|
-
actions: current.actions,
|
|
13441
|
+
ran: current.ran,
|
|
13464
13442
|
installed: current.installed,
|
|
13465
13443
|
removed: current.removed
|
|
13466
13444
|
});
|
|
@@ -13531,13 +13509,12 @@ const layer = Layer.effect(Session, Effect.gen(function* () {
|
|
|
13531
13509
|
const confirmed = targets.filter((target) => accepted.includes(rowKey(target.pkg)));
|
|
13532
13510
|
const chosen = vetting ? vet(targets.filter((target) => !accepted.includes(rowKey(target.pkg))), current.mode).pipe(Effect.flatMap(({ approved, refused }) => update((latest) => ({
|
|
13533
13511
|
...latest,
|
|
13534
|
-
|
|
13535
|
-
...latest.
|
|
13536
|
-
...refused
|
|
13537
|
-
|
|
13538
|
-
|
|
13539
|
-
|
|
13540
|
-
...Object.fromEntries(Object.keys(refused).map((key) => [key, action]))
|
|
13512
|
+
ran: {
|
|
13513
|
+
...latest.ran,
|
|
13514
|
+
...Object.fromEntries(Object.entries(refused).map(([key, outcome]) => [key, {
|
|
13515
|
+
action,
|
|
13516
|
+
outcome
|
|
13517
|
+
}]))
|
|
13541
13518
|
}
|
|
13542
13519
|
})).pipe(Effect.as([...confirmed, ...approved])))) : Effect.succeed(targets);
|
|
13543
13520
|
yield* FiberHandle.run(operation, chosen.pipe(Effect.tap((approved) => update((latest) => ({
|
|
@@ -13555,13 +13532,12 @@ const layer = Layer.effect(Session, Effect.gen(function* () {
|
|
|
13555
13532
|
} : {
|
|
13556
13533
|
...latest,
|
|
13557
13534
|
activity: without(latest.activity, event.key),
|
|
13558
|
-
|
|
13559
|
-
...latest.
|
|
13560
|
-
[event.key]:
|
|
13561
|
-
|
|
13562
|
-
|
|
13563
|
-
|
|
13564
|
-
[event.key]: action
|
|
13535
|
+
ran: {
|
|
13536
|
+
...latest.ran,
|
|
13537
|
+
[event.key]: {
|
|
13538
|
+
action,
|
|
13539
|
+
outcome: event.outcome
|
|
13540
|
+
}
|
|
13565
13541
|
},
|
|
13566
13542
|
installed: installedAfter(latest.installed, approved, event),
|
|
13567
13543
|
removed: removedAfter(latest.removed, approved, event),
|
|
@@ -13587,10 +13563,10 @@ const layer = Layer.effect(Session, Effect.gen(function* () {
|
|
|
13587
13563
|
if ((yield* SubscriptionRef.get(state)).about[key] !== void 0) return;
|
|
13588
13564
|
yield* about.load(key, registry.lookup(pkg));
|
|
13589
13565
|
});
|
|
13590
|
-
const readTranscript = Effect.fn("Session.readTranscript")(function* (
|
|
13591
|
-
const known = (yield* SubscriptionRef.get(state)).transcripts[file];
|
|
13566
|
+
const readTranscript = Effect.fn("Session.readTranscript")(function* (paths) {
|
|
13567
|
+
const known = (yield* SubscriptionRef.get(state)).transcripts[paths.file];
|
|
13592
13568
|
if (known !== void 0 && known._tag !== "Unavailable") return;
|
|
13593
|
-
yield* transcripts.load(file, audits.transcript(
|
|
13569
|
+
yield* transcripts.load(paths.file, audits.transcript(paths));
|
|
13594
13570
|
});
|
|
13595
13571
|
const readChanges = Effect.fn("Session.readChanges")(function* (pkg) {
|
|
13596
13572
|
const current = yield* SubscriptionRef.get(state);
|
|
@@ -13751,7 +13727,7 @@ const silenceNodeWarningsWhileTuiDraws = () => {
|
|
|
13751
13727
|
};
|
|
13752
13728
|
const loadTui = Effect.suspend(() => {
|
|
13753
13729
|
silenceNodeWarningsWhileTuiDraws();
|
|
13754
|
-
return process.getBuiltinModule("node:ffi") === void 0 ? Effect.die(`upup's TUI needs Node 26.13 or newer; this is Node ${process.versions.node}`) : Effect.promise(async () => await import("./Tui-
|
|
13730
|
+
return process.getBuiltinModule("node:ffi") === void 0 ? Effect.die(`upup's TUI needs Node 26.13 or newer; this is Node ${process.versions.node}`) : Effect.promise(async () => await import("./Tui-Ri-yz-Sx.mjs"));
|
|
13755
13731
|
});
|
|
13756
13732
|
const open$1 = (begin, projectDir) => Effect.gen(function* () {
|
|
13757
13733
|
const { launch } = yield* loadTui;
|