@event4u/agent-config 17.3.0 → 17.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +164 -342
- package/CREDITS.md +2 -2
- package/README.md +1 -1
- package/dist/agent-src/skills/code-intelligence/SKILL.md +3 -0
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/cli/registry.js +2 -2
- package/dist/cli-delegate/{chunk-DHSSP7V3.js → chunk-5AYJGUA3.js} +0 -2
- package/dist/cli-delegate/chunk-DIFZBP4G.js +1336 -0
- package/dist/cli-delegate/{chunk-MT2WOOCY.js → chunk-WY5ZZPGL.js} +2 -2
- package/dist/cli-delegate/{chunk-ORJPBER2.js → chunk-X6LZ7W5A.js} +73 -10
- package/dist/cli-delegate/cmd_conformance.js +175 -183
- package/dist/cli-delegate/cmd_doctor.js +5 -5
- package/dist/cli-delegate/cmd_doctor_neighbours.js +3 -3
- package/dist/cli-delegate/cmd_explain.js +1 -1
- package/dist/cli-delegate/cmd_handoff.js +2 -2
- package/dist/cli-delegate/cmd_memory_get.js +1 -1
- package/dist/cli-delegate/cmd_route_audit.js +1 -1
- package/dist/cli-delegate/cmd_session_recycle.js +2 -2
- package/dist/cli-delegate/cmd_update.js +24 -13
- package/dist/cli-delegate/cmd_upgrade.js +2 -2
- package/dist/cli-delegate/dist-25AZAHOP.js +3240 -0
- package/dist/cli-delegate/dist-P7MFPMF3.js +411 -0
- package/dist/cli-delegate/dist-XAS5ZLQB.js +6 -0
- package/dist/cli-delegate/{upgrade_unattended-VVL6JLSX.js → upgrade_unattended-QCWOKTUN.js} +178 -163
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +3 -3
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +1 -1
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +2 -2
- package/dist/discovery/trust-report.md +1 -1
- package/dist/discovery/workspaces.json +2 -2
- package/dist/hooks/code_graph_refresh.chunk.cjs +56 -27
- package/dist/hooks/code_graph_refresh.chunk.cjs.sha256 +1 -1
- package/dist/hooks/dispatch.js +982 -929
- package/dist/hooks/dispatch.sha256 +1 -1
- package/dist/hooks/egress_engine.chunk.cjs +56 -6
- package/dist/hooks/egress_engine.chunk.cjs.sha256 +1 -1
- package/dist/hooks/update_notice.chunk.cjs +914 -0
- package/dist/hooks/update_notice.chunk.cjs.sha256 +1 -0
- package/dist/mcp/registry-manifest.json +1 -1
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +71259 -66437
- package/dist/scripts/condense.js +9 -6
- package/package.json +4 -1
- package/src/config/evaluator-budgets.json +9 -8
- package/src/config/gate-violation-baselines.json +2 -2
- package/src/config/hook-bundle-budget.json +31 -6
- package/src/config/packed-binary-manifest.json +9 -0
- package/src/config/sigstore/npm_keys.json +50 -0
- package/src/config/sigstore/trust-material.json +9 -0
- package/src/config/sigstore/trusted_root.json +126 -0
- package/src/config/skill-body-budget.json +7 -1
- package/src/scripts/_cli/cmd_update.ts +48 -20
- package/src/scripts/_cli/cmd_upgrade.ts +7 -1
- package/src/scripts/_cli/upgrade_unattended.ts +90 -76
- package/src/scripts/_dispatch.bash +3 -2
- package/src/scripts/_lib/confusables.ts +0 -19
- package/src/scripts/_lib/egress_normalize.ts +53 -23
- package/src/scripts/_lib/egress_text.ts +5 -3
- package/src/scripts/_lib/egress_token.ts +7 -5
- package/src/scripts/_lib/gate_collector_experimental.ts +633 -0
- package/src/scripts/_lib/git_common_dir.ts +10 -0
- package/src/scripts/_lib/graph_feeder_record.ts +3 -2
- package/src/scripts/_lib/install_reach_checks.ts +32 -2
- package/src/scripts/_lib/lineage_backfill.ts +136 -0
- package/src/scripts/_lib/lineage_ledger.ts +211 -0
- package/src/scripts/_lib/lineage_map.ts +55 -0
- package/src/scripts/_lib/lineage_query.ts +140 -0
- package/src/scripts/_lib/lineage_seed.ts +116 -0
- package/src/scripts/_lib/lineage_watch.ts +249 -0
- package/src/scripts/_lib/link_crypto.ts +8 -4
- package/src/scripts/_lib/production_reach.ts +3 -3
- package/src/scripts/_lib/project_registry.ts +227 -0
- package/src/scripts/_lib/provenance_verify.ts +14 -242
- package/src/scripts/_lib/sigstore_provenance.ts +177 -0
- package/src/scripts/_lib/source_id.ts +48 -0
- package/src/scripts/_lib/source_shape.ts +4 -0
- package/src/scripts/_lib/unattended_gates.ts +6 -1
- package/src/scripts/advisories.ts +26 -10
- package/src/scripts/ai_council/council_egress.ts +5 -6
- package/src/scripts/bench_graph_feeder_latency.ts +10 -3
- package/src/scripts/check_dependency_floors.ts +7 -0
- package/src/scripts/check_egress_mutations.ts +1 -0
- package/src/scripts/code_graph/build.ts +67 -3
- package/src/scripts/code_graph/cli.ts +131 -28
- package/src/scripts/code_graph/conventions_default.ts +20 -1
- package/src/scripts/code_graph/detect.ts +5 -5
- package/src/scripts/code_graph/estate_cli.ts +135 -0
- package/src/scripts/code_graph/estate_index.ts +394 -0
- package/src/scripts/code_graph/estate_manifests.ts +223 -0
- package/src/scripts/code_graph/estate_map.ts +141 -0
- package/src/scripts/code_graph/extract.ts +4 -1
- package/src/scripts/code_graph/extract_more.ts +137 -2
- package/src/scripts/code_graph/graph_budget.ts +158 -0
- package/src/scripts/code_graph/graph_home.ts +80 -0
- package/src/scripts/code_graph/lineage_cli.ts +315 -0
- package/src/scripts/code_graph/map.ts +22 -13
- package/src/scripts/code_graph/map_model.ts +67 -12
- package/src/scripts/code_graph/map_verify.ts +68 -5
- package/src/scripts/code_graph/map_viewer/viewer.css +12 -0
- package/src/scripts/code_graph/map_viewer/viewer.js +45 -15
- package/src/scripts/code_graph/project_ref.ts +25 -0
- package/src/scripts/code_graph/projects_cli.ts +254 -0
- package/src/scripts/code_graph/providers/catalog.ts +14 -5
- package/src/scripts/code_graph/providers/django.ts +52 -9
- package/src/scripts/code_graph/providers/index.ts +2 -0
- package/src/scripts/code_graph/providers/rails.ts +204 -0
- package/src/scripts/code_graph/providers/spring.ts +38 -1
- package/src/scripts/code_graph/query.ts +9 -9
- package/src/scripts/code_graph/refresh_lock.ts +12 -8
- package/src/scripts/code_graph/repo_identity.ts +169 -0
- package/src/scripts/code_graph/sqlite_store.ts +22 -25
- package/src/scripts/code_graph/types.ts +6 -2
- package/src/scripts/condense.ts +6 -6
- package/src/scripts/hook_chunks.mjs +7 -0
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +20 -17
- package/src/scripts/hooks/code_graph_refresh_hook.ts +10 -7
- package/src/scripts/hooks/dispatch_hook.ts +6 -7
- package/src/scripts/hooks/host_semantics.ts +72 -0
- package/src/scripts/hooks/lazy_concern.ts +4 -0
- package/src/scripts/hooks/user_notice.ts +105 -0
- package/src/scripts/lint_harvest_provenance.ts +137 -11
- package/src/scripts/mcp_server/consumer_tool_catalog.json +69 -15
- package/src/scripts/mcp_server/graph_tools.ts +161 -41
- package/src/scripts/network_sources.ts +24 -6
- package/src/scripts/schemas/provenance-mechanism.schema.json +46 -0
- package/src/scripts/update_notice_hook.ts +75 -7
- package/src/vendor/grammars/README.md +7 -6
- package/src/vendor/grammars/tree-sitter-ruby.wasm +0 -0
- /package/dist/cli-delegate/{chunk-FKYZOWVD.js → chunk-QBAFP67O.js} +0 -0
- /package/dist/cli-delegate/{chunk-BMGUGSY6.js → chunk-TQG6UMPC.js} +0 -0
|
@@ -24,46 +24,24 @@ import {
|
|
|
24
24
|
import "./chunk-J55WI3RR.js";
|
|
25
25
|
|
|
26
26
|
// src/scripts/_cli/upgrade_unattended.ts
|
|
27
|
-
import * as
|
|
28
|
-
import * as
|
|
27
|
+
import * as crypto from "node:crypto";
|
|
28
|
+
import * as fs2 from "node:fs";
|
|
29
|
+
import * as os from "node:os";
|
|
30
|
+
import * as path2 from "node:path";
|
|
29
31
|
import { spawnSync } from "node:child_process";
|
|
30
32
|
import process from "node:process";
|
|
31
33
|
|
|
34
|
+
// src/scripts/_lib/sigstore_provenance.ts
|
|
35
|
+
import { createHash } from "node:crypto";
|
|
36
|
+
import * as fs from "node:fs";
|
|
37
|
+
import * as path from "node:path";
|
|
38
|
+
|
|
32
39
|
// src/scripts/_lib/provenance_verify.ts
|
|
33
40
|
var EXPECTED_WORKFLOW_REF = ".github/workflows/publish-npm.yml";
|
|
34
41
|
var EXPECTED_REPOSITORY = "https://github.com/event4u-app/agent-config";
|
|
35
42
|
function asRecord(v) {
|
|
36
43
|
return v !== null && typeof v === "object" && !Array.isArray(v) ? v : null;
|
|
37
44
|
}
|
|
38
|
-
function decode_payload(doc) {
|
|
39
|
-
const list = asRecord(doc)?.["attestations"];
|
|
40
|
-
if (!Array.isArray(list) || list.length === 0) return null;
|
|
41
|
-
for (const entry of list) {
|
|
42
|
-
const payload = asRecord(asRecord(asRecord(entry)?.["bundle"])?.["dsseEnvelope"])?.["payload"];
|
|
43
|
-
if (typeof payload !== "string" || payload === "") continue;
|
|
44
|
-
try {
|
|
45
|
-
const parsed = JSON.parse(Buffer.from(payload, "base64").toString("utf8"));
|
|
46
|
-
const rec = asRecord(parsed);
|
|
47
|
-
if (rec !== null) return rec;
|
|
48
|
-
} catch {
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
function external_workflow(doc) {
|
|
54
|
-
const payload = decode_payload(doc);
|
|
55
|
-
if (payload === null) return null;
|
|
56
|
-
const predicate = asRecord(payload["predicate"]);
|
|
57
|
-
const external = asRecord(asRecord(predicate?.["buildDefinition"])?.["externalParameters"]);
|
|
58
|
-
return asRecord(external?.["workflow"]);
|
|
59
|
-
}
|
|
60
|
-
function attestation_workflow_ref(doc) {
|
|
61
|
-
const path_value = external_workflow(doc)?.["path"];
|
|
62
|
-
return typeof path_value === "string" && path_value !== "" ? path_value : null;
|
|
63
|
-
}
|
|
64
|
-
function provenance_matches_publish(doc) {
|
|
65
|
-
return payload_names_publish(decode_payload(doc));
|
|
66
|
-
}
|
|
67
45
|
function payload_names_publish(payload) {
|
|
68
46
|
const predicate = asRecord(payload?.["predicate"]);
|
|
69
47
|
const workflow = asRecord(asRecord(asRecord(predicate?.["buildDefinition"])?.["externalParameters"])?.["workflow"]);
|
|
@@ -72,109 +50,124 @@ function payload_names_publish(payload) {
|
|
|
72
50
|
if (typeof repo !== "string" || repo === "") return false;
|
|
73
51
|
return repo.replace(/\.git$/, "").replace(/\/$/, "") === EXPECTED_REPOSITORY;
|
|
74
52
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
var
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
53
|
+
|
|
54
|
+
// src/scripts/_lib/sigstore_provenance.ts
|
|
55
|
+
var SLSA_PROVENANCE_V1 = "https://slsa.dev/provenance/v1";
|
|
56
|
+
var NPM_PUBLISH_V01 = "https://github.com/npm/attestation/tree/main/specs/publish/v0.1";
|
|
57
|
+
var GITHUB_OIDC_ISSUER = "https://token.actions.githubusercontent.com";
|
|
58
|
+
var PACKAGE_PURL_BASE = "pkg:npm/%40event4u/agent-config";
|
|
59
|
+
function asRecord2(v) {
|
|
60
|
+
return v !== null && typeof v === "object" && !Array.isArray(v) ? v : null;
|
|
61
|
+
}
|
|
62
|
+
function escapeRegExp(s) {
|
|
63
|
+
return s.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&");
|
|
64
|
+
}
|
|
65
|
+
function expectedSan(version) {
|
|
66
|
+
return new RegExp(`^${escapeRegExp(`${EXPECTED_REPOSITORY}/${EXPECTED_WORKFLOW_REF}@refs/tags/${version}`)}$`);
|
|
67
|
+
}
|
|
68
|
+
function readTrustFiles(packageRoot = resolvePackageRoot(import.meta.url)) {
|
|
69
|
+
const dir = path.join(packageRoot, "src", "config", "sigstore");
|
|
70
|
+
try {
|
|
71
|
+
const manifest = JSON.parse(fs.readFileSync(path.join(dir, "trust-material.json"), "utf-8"));
|
|
72
|
+
const read = (name) => {
|
|
73
|
+
const bytes = fs.readFileSync(path.join(dir, name));
|
|
74
|
+
const want = manifest.files?.[name];
|
|
75
|
+
const got = createHash("sha256").update(bytes).digest("hex");
|
|
76
|
+
if (want !== got) throw new Error(`${name} has sha256 ${got}, the recorded one is ${String(want)}`);
|
|
77
|
+
return JSON.parse(bytes.toString("utf-8"));
|
|
78
|
+
};
|
|
79
|
+
return { trustedRoot: read("trusted_root.json"), npmKeys: read("npm_keys.json") };
|
|
80
|
+
} catch (err) {
|
|
81
|
+
return `the pinned sigstore trust material is unusable: ${err instanceof Error ? err.message : String(err)}`;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function subjectMatches(payload, version, sha512Hex) {
|
|
85
|
+
const subjects = payload?.["subject"];
|
|
86
|
+
if (!Array.isArray(subjects) || subjects.length !== 1) return "it does not name exactly one subject";
|
|
87
|
+
const subject = asRecord2(subjects[0]);
|
|
88
|
+
if (subject?.["name"] !== `${PACKAGE_PURL_BASE}@${version}`) return `its subject is ${String(subject?.["name"])}, not ${version}`;
|
|
89
|
+
const digest = asRecord2(subject["digest"])?.["sha512"];
|
|
90
|
+
if (typeof digest !== "string" || digest.toLowerCase() !== sha512Hex.toLowerCase()) {
|
|
91
|
+
return "its subject digest does not match the tarball about to be installed";
|
|
92
|
+
}
|
|
93
|
+
return null;
|
|
110
94
|
}
|
|
111
|
-
async function
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
95
|
+
async function verify_release_provenance(release, trust = readTrustFiles()) {
|
|
96
|
+
if (typeof trust === "string") return trust;
|
|
97
|
+
const list = asRecord2(release.attestations)?.["attestations"];
|
|
98
|
+
if (!Array.isArray(list)) return "the attestation document carries no attestations";
|
|
99
|
+
const byType = /* @__PURE__ */ new Map();
|
|
116
100
|
for (const entry of list) {
|
|
117
|
-
const
|
|
118
|
-
if (
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
ok = false;
|
|
136
|
-
}
|
|
137
|
-
if (!ok) {
|
|
138
|
-
lastReason = "the DSSE signature does not verify against the certificate in the bundle";
|
|
139
|
-
continue;
|
|
101
|
+
const type = asRecord2(entry)?.["predicateType"];
|
|
102
|
+
if (typeof type === "string" && !byType.has(type)) byType.set(type, asRecord2(entry)?.["bundle"]);
|
|
103
|
+
}
|
|
104
|
+
for (const type of [SLSA_PROVENANCE_V1, NPM_PUBLISH_V01]) {
|
|
105
|
+
if (!byType.has(type)) return `the release carries no ${type} attestation`;
|
|
106
|
+
}
|
|
107
|
+
const { Verifier, toSignedEntity, toTrustMaterial } = await import("./dist-25AZAHOP.js");
|
|
108
|
+
const { bundleFromJSON } = await import("./dist-P7MFPMF3.js");
|
|
109
|
+
const { PublicKey, TrustedRoot } = await import("./dist-XAS5ZLQB.js");
|
|
110
|
+
let material;
|
|
111
|
+
try {
|
|
112
|
+
const keys = {};
|
|
113
|
+
const listed = asRecord2(trust.npmKeys)?.["keys"];
|
|
114
|
+
for (const k of Array.isArray(listed) ? listed : []) {
|
|
115
|
+
const key = asRecord2(k);
|
|
116
|
+
if (key?.["keyUsage"] === "npm:attestations" && typeof key["keyId"] === "string") {
|
|
117
|
+
keys[key["keyId"]] = PublicKey.fromJSON(key["publicKey"]);
|
|
118
|
+
}
|
|
140
119
|
}
|
|
141
|
-
|
|
120
|
+
material = toTrustMaterial(TrustedRoot.fromJSON(trust.trustedRoot), keys);
|
|
121
|
+
} catch (err) {
|
|
122
|
+
return `the pinned sigstore trust material could not be loaded: ${err instanceof Error ? err.message : String(err)}`;
|
|
123
|
+
}
|
|
124
|
+
for (const type of [SLSA_PROVENANCE_V1, NPM_PUBLISH_V01]) {
|
|
125
|
+
let payload;
|
|
142
126
|
try {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
127
|
+
const bundle = bundleFromJSON(byType.get(type));
|
|
128
|
+
const verifier = new Verifier(material, { tlogThreshold: 1, ctlogThreshold: 1, timestampThreshold: 1 });
|
|
129
|
+
const policy = type === SLSA_PROVENANCE_V1 ? { subjectAlternativeName: expectedSan(release.version), extensions: { issuer: GITHUB_OIDC_ISSUER } } : void 0;
|
|
130
|
+
verifier.verify(toSignedEntity(bundle), policy);
|
|
131
|
+
if (bundle.content.$case !== "dsseEnvelope") return `the ${type} attestation is not a DSSE envelope`;
|
|
132
|
+
payload = asRecord2(JSON.parse(bundle.content.dsseEnvelope.payload.toString("utf-8")));
|
|
133
|
+
} catch (err) {
|
|
134
|
+
const code = asRecord2(err)?.["code"];
|
|
135
|
+
return `the ${type} attestation does not verify${typeof code === "string" ? ` (${code})` : ""}: ${err instanceof Error ? err.message : String(err)}`;
|
|
146
136
|
}
|
|
147
|
-
if (
|
|
148
|
-
|
|
149
|
-
|
|
137
|
+
if (payload?.["predicateType"] !== type) return `the ${type} attestation's statement names another predicate type`;
|
|
138
|
+
const subject = subjectMatches(payload, release.version, release.tarballSha512Hex);
|
|
139
|
+
if (subject !== null) return `the ${type} attestation is not for this tarball: ${subject}`;
|
|
140
|
+
if (type === SLSA_PROVENANCE_V1 && !payload_names_publish(payload)) {
|
|
141
|
+
return `the signed provenance does not name ${EXPECTED_WORKFLOW_REF} in ${EXPECTED_REPOSITORY}`;
|
|
150
142
|
}
|
|
151
|
-
return null;
|
|
152
143
|
}
|
|
153
|
-
return
|
|
144
|
+
return null;
|
|
154
145
|
}
|
|
155
146
|
|
|
156
147
|
// src/scripts/_lib/unattended_gates.ts
|
|
157
148
|
var UNATTENDED_MIN_RELEASE_AGE_HOURS = 72;
|
|
158
|
-
function
|
|
149
|
+
function asRecord3(v) {
|
|
159
150
|
return v !== null && typeof v === "object" && !Array.isArray(v) ? v : null;
|
|
160
151
|
}
|
|
161
152
|
function read_candidate(packument) {
|
|
162
|
-
const doc =
|
|
163
|
-
const version =
|
|
153
|
+
const doc = asRecord3(packument);
|
|
154
|
+
const version = asRecord3(doc?.["dist-tags"])?.["latest"];
|
|
164
155
|
if (typeof version !== "string" || version === "") return null;
|
|
165
|
-
const manifest =
|
|
156
|
+
const manifest = asRecord3(asRecord3(doc?.["versions"])?.[version]);
|
|
166
157
|
if (manifest === null) return null;
|
|
167
|
-
const published =
|
|
168
|
-
const attestations =
|
|
169
|
-
const predicate =
|
|
158
|
+
const published = asRecord3(doc?.["time"])?.[version];
|
|
159
|
+
const attestations = asRecord3(asRecord3(manifest["dist"])?.["attestations"]);
|
|
160
|
+
const predicate = asRecord3(attestations?.["provenance"])?.["predicateType"];
|
|
170
161
|
return {
|
|
171
162
|
version,
|
|
172
163
|
publishedAt: typeof published === "string" ? published : null,
|
|
173
164
|
deprecated: manifest["deprecated"],
|
|
174
165
|
engines: manifest["engines"],
|
|
175
166
|
provenance: typeof predicate === "string" && predicate.startsWith("https://slsa.dev/provenance/"),
|
|
176
|
-
impactMap:
|
|
177
|
-
attestationsUrl: typeof attestations?.["url"] === "string" ? attestations["url"] : null
|
|
167
|
+
impactMap: asRecord3(manifest["agentConfig"])?.["impact"] ?? null,
|
|
168
|
+
attestationsUrl: typeof attestations?.["url"] === "string" ? attestations["url"] : null,
|
|
169
|
+
tarballUrl: typeof asRecord3(manifest["dist"])?.["tarball"] === "string" ? asRecord3(manifest["dist"])?.["tarball"] : null,
|
|
170
|
+
integrity: typeof asRecord3(manifest["dist"])?.["integrity"] === "string" ? asRecord3(manifest["dist"])?.["integrity"] : null
|
|
178
171
|
};
|
|
179
172
|
}
|
|
180
173
|
function unattended_decision(input) {
|
|
@@ -214,7 +207,7 @@ function say(sink, line) {
|
|
|
214
207
|
}
|
|
215
208
|
function read_skips(skipPath) {
|
|
216
209
|
try {
|
|
217
|
-
const data = JSON.parse(
|
|
210
|
+
const data = JSON.parse(fs2.readFileSync(skipPath, "utf-8"));
|
|
218
211
|
const list = data?.skip;
|
|
219
212
|
return Array.isArray(list) ? list.filter((v) => typeof v === "string") : [];
|
|
220
213
|
} catch {
|
|
@@ -224,12 +217,12 @@ function read_skips(skipPath) {
|
|
|
224
217
|
function record_skip(skipPath, version) {
|
|
225
218
|
const skips = read_skips(skipPath);
|
|
226
219
|
if (!skips.includes(version)) skips.push(version);
|
|
227
|
-
|
|
228
|
-
|
|
220
|
+
fs2.mkdirSync(path2.dirname(skipPath), { recursive: true });
|
|
221
|
+
fs2.writeFileSync(skipPath, JSON.stringify({ skip: skips.sort() }, null, 2) + "\n", "utf-8");
|
|
229
222
|
}
|
|
230
223
|
function read_text(p) {
|
|
231
224
|
try {
|
|
232
|
-
return
|
|
225
|
+
return fs2.readFileSync(p, "utf-8");
|
|
233
226
|
} catch {
|
|
234
227
|
return null;
|
|
235
228
|
}
|
|
@@ -238,15 +231,15 @@ function acquire_lock(deps) {
|
|
|
238
231
|
const record = { pid: deps.pid, started_at: deps.now().toISOString(), ttl_ms: LOCK_TTL_MS };
|
|
239
232
|
const mine = `${deps.lockPath}.${deps.pid}.${process.hrtime.bigint()}`;
|
|
240
233
|
try {
|
|
241
|
-
|
|
242
|
-
|
|
234
|
+
fs2.mkdirSync(path2.dirname(deps.lockPath), { recursive: true });
|
|
235
|
+
fs2.writeFileSync(mine, JSON.stringify(record) + "\n", { flag: "wx" });
|
|
243
236
|
} catch (exc) {
|
|
244
237
|
return `cannot write the lock: ${String(exc)}`;
|
|
245
238
|
}
|
|
246
239
|
try {
|
|
247
240
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
248
241
|
try {
|
|
249
|
-
|
|
242
|
+
fs2.linkSync(mine, deps.lockPath);
|
|
250
243
|
return null;
|
|
251
244
|
} catch (exc) {
|
|
252
245
|
if (exc.code !== "EEXIST") return `cannot write the lock: ${String(exc)}`;
|
|
@@ -264,35 +257,35 @@ function acquire_lock(deps) {
|
|
|
264
257
|
}
|
|
265
258
|
const tomb = `${mine}.stale`;
|
|
266
259
|
try {
|
|
267
|
-
|
|
260
|
+
fs2.renameSync(deps.lockPath, tomb);
|
|
268
261
|
} catch {
|
|
269
262
|
continue;
|
|
270
263
|
}
|
|
271
264
|
if (read_text(tomb) !== judged) {
|
|
272
265
|
try {
|
|
273
|
-
|
|
266
|
+
fs2.linkSync(tomb, deps.lockPath);
|
|
274
267
|
} catch {
|
|
275
268
|
}
|
|
276
|
-
|
|
269
|
+
fs2.rmSync(tomb, { force: true });
|
|
277
270
|
return "another unattended upgrade took the lock over first";
|
|
278
271
|
}
|
|
279
|
-
|
|
272
|
+
fs2.rmSync(tomb, { force: true });
|
|
280
273
|
}
|
|
281
274
|
return "the lock could not be taken";
|
|
282
275
|
} finally {
|
|
283
|
-
|
|
276
|
+
fs2.rmSync(mine, { force: true });
|
|
284
277
|
}
|
|
285
278
|
}
|
|
286
279
|
function release_lock(deps) {
|
|
287
280
|
try {
|
|
288
|
-
const held = JSON.parse(
|
|
289
|
-
if (held.pid === deps.pid)
|
|
281
|
+
const held = JSON.parse(fs2.readFileSync(deps.lockPath, "utf-8"));
|
|
282
|
+
if (held.pid === deps.pid) fs2.unlinkSync(deps.lockPath);
|
|
290
283
|
} catch {
|
|
291
284
|
}
|
|
292
285
|
}
|
|
293
|
-
function install_steps(
|
|
286
|
+
function install_steps(spec, deps) {
|
|
294
287
|
return [
|
|
295
|
-
["npm", "install", "-g",
|
|
288
|
+
["npm", "install", "-g", spec],
|
|
296
289
|
[deps.agentConfigBin, "global", "--no-ui"],
|
|
297
290
|
...deps.globalSettings.map((target) => [deps.agentConfigBin, "settings:sync", "--path", target])
|
|
298
291
|
];
|
|
@@ -307,7 +300,7 @@ function run_steps(steps, deps, honourSignal = true) {
|
|
|
307
300
|
return { ok: true };
|
|
308
301
|
}
|
|
309
302
|
function restore(previous, deps) {
|
|
310
|
-
const back = run_steps(install_steps(previous
|
|
303
|
+
const back = run_steps(install_steps(`${PACKAGE_NAME}@${previous}`, deps).slice(0, 2), deps, false);
|
|
311
304
|
const lock = deps.readInstalled();
|
|
312
305
|
const binary = deps.readBinary();
|
|
313
306
|
if (back.ok && lock === previous && binary === previous) {
|
|
@@ -334,41 +327,58 @@ async function decide(installed, deps) {
|
|
|
334
327
|
});
|
|
335
328
|
if (!decision.install) return { refused: [...decision.reasons] };
|
|
336
329
|
const provenance = await deps.verifyProvenance(candidate);
|
|
337
|
-
if (provenance
|
|
338
|
-
return { candidate };
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
330
|
+
if (!provenance.ok) return { refused: [provenance.reason] };
|
|
331
|
+
return { candidate, tarball: provenance.tarball };
|
|
332
|
+
}
|
|
333
|
+
var MAX_TARBALL_BYTES = 64 * 1024 * 1024;
|
|
334
|
+
async function verify_provenance_default(candidate, fetch_impl = fetch, timeoutMs = 6e4, verify = (r) => verify_release_provenance(r)) {
|
|
335
|
+
const v = candidate.version;
|
|
336
|
+
const registry = new URL(PACKUMENT_URL).origin;
|
|
337
|
+
const refuse = (reason2) => ({ ok: false, reason: `${v}: ${reason2}` });
|
|
338
|
+
for (const [what, url] of [
|
|
339
|
+
["attestation bundle", candidate.attestationsUrl],
|
|
340
|
+
["tarball", candidate.tarballUrl]
|
|
341
|
+
]) {
|
|
342
|
+
if (url === null) return refuse(`the registry names no ${what} to verify`);
|
|
343
|
+
let origin = "";
|
|
344
|
+
try {
|
|
345
|
+
origin = new URL(url).origin;
|
|
346
|
+
} catch {
|
|
347
|
+
}
|
|
348
|
+
if (origin !== registry) return refuse(`the ${what} url is not on ${registry}`);
|
|
343
349
|
}
|
|
344
|
-
|
|
350
|
+
const integrity = /^sha512-([A-Za-z0-9+/=]+)$/.exec(candidate.integrity ?? "");
|
|
351
|
+
if (integrity === null) return refuse("the registry records no sha512 integrity for the tarball");
|
|
352
|
+
const get = async (url) => {
|
|
353
|
+
const resp = await fetch_impl(url, { signal: AbortSignal.timeout(timeoutMs), redirect: "error" });
|
|
354
|
+
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
|
355
|
+
return resp;
|
|
356
|
+
};
|
|
357
|
+
let attestations;
|
|
358
|
+
let bytes;
|
|
345
359
|
try {
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
360
|
+
attestations = await (await get(candidate.attestationsUrl)).json();
|
|
361
|
+
const resp = await get(candidate.tarballUrl);
|
|
362
|
+
if (Number(resp.headers.get("content-length") ?? 0) > MAX_TARBALL_BYTES) return refuse("the tarball is larger than allowed");
|
|
363
|
+
bytes = Buffer.from(await resp.arrayBuffer());
|
|
364
|
+
} catch (err) {
|
|
365
|
+
return refuse(`download failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
349
366
|
}
|
|
350
|
-
if (
|
|
351
|
-
|
|
367
|
+
if (bytes.length > MAX_TARBALL_BYTES) return refuse("the tarball is larger than allowed");
|
|
368
|
+
const digest = crypto.createHash("sha512").update(bytes).digest();
|
|
369
|
+
if (!digest.equals(Buffer.from(integrity[1], "base64"))) {
|
|
370
|
+
return refuse("the downloaded tarball does not match the integrity the registry records");
|
|
352
371
|
}
|
|
353
|
-
|
|
372
|
+
const reason = await verify({ version: v, tarballSha512Hex: digest.toString("hex"), attestations });
|
|
373
|
+
if (reason !== null) return refuse(reason);
|
|
354
374
|
try {
|
|
355
|
-
const
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
});
|
|
360
|
-
if (!resp.ok) return `attestation fetch failed: HTTP ${resp.status}`;
|
|
361
|
-
doc = await resp.json();
|
|
375
|
+
const dir = fs2.mkdtempSync(path2.join(os.tmpdir(), "agent-config-upgrade-"));
|
|
376
|
+
const tarball = path2.join(dir, `agent-config-${v}.tgz`);
|
|
377
|
+
fs2.writeFileSync(tarball, bytes, { mode: 384, flag: "wx" });
|
|
378
|
+
return { ok: true, tarball };
|
|
362
379
|
} catch (err) {
|
|
363
|
-
return `
|
|
364
|
-
}
|
|
365
|
-
if (!provenance_matches_publish(doc)) {
|
|
366
|
-
const named = attestation_workflow_ref(doc);
|
|
367
|
-
return named === null ? `${candidate.version} has no readable provenance workflow in its attestation` : `${candidate.version} was built by ${named}, not ${EXPECTED_WORKFLOW_REF}`;
|
|
380
|
+
return refuse(`cannot write the verified tarball: ${err instanceof Error ? err.message : String(err)}`);
|
|
368
381
|
}
|
|
369
|
-
const signature = await verify_attestation_signature(doc);
|
|
370
|
-
if (signature !== null) return `${candidate.version}: ${signature}`;
|
|
371
|
-
return null;
|
|
372
382
|
}
|
|
373
383
|
function quiet_context(deps) {
|
|
374
384
|
if (deps.env.ci) return "suppressed: CI";
|
|
@@ -392,14 +402,16 @@ async function run_unattended(deps) {
|
|
|
392
402
|
say(deps.err, `${PREFIX}: not installing \u2014 ${locked}.`);
|
|
393
403
|
return EXIT_REFUSED;
|
|
394
404
|
}
|
|
405
|
+
let verified = null;
|
|
395
406
|
try {
|
|
396
407
|
const verdict = await decide(previous, deps);
|
|
397
408
|
if ("refused" in verdict) {
|
|
398
409
|
say(deps.out, `\u2139\uFE0F ${PREFIX}: not installing (installed: ${previous}) \u2014 ${verdict.refused.join("; ")}.`);
|
|
399
410
|
return EXIT_REFUSED;
|
|
400
411
|
}
|
|
412
|
+
verified = verdict.tarball;
|
|
401
413
|
const target = verdict.candidate.version;
|
|
402
|
-
const steps = install_steps(
|
|
414
|
+
const steps = install_steps(verified, deps);
|
|
403
415
|
if (deps.activationBlocked !== null) {
|
|
404
416
|
const how = deps.dryRun ? "dry run: a real run would not install" : "not installing";
|
|
405
417
|
say(deps.out, `\u2139\uFE0F ${PREFIX}: every gate passed for ${target}, but ${how} \u2014 ${deps.activationBlocked}.`);
|
|
@@ -417,9 +429,10 @@ async function run_unattended(deps) {
|
|
|
417
429
|
}
|
|
418
430
|
const what = `${ran.cmd.join(" ")} (exit ${ran.result.rc})`;
|
|
419
431
|
if (/\bEACCES\b/.test(ran.result.stderr)) {
|
|
432
|
+
const manual = ran.cmd === steps[0] ? ["npm", "install", "-g", `${PACKAGE_NAME}@${target}`] : ran.cmd;
|
|
420
433
|
say(
|
|
421
434
|
deps.err,
|
|
422
|
-
`\u274C ${PREFIX}: permission denied on ${what}. agent-config never runs sudo; run this yourself with the right permissions: ${
|
|
435
|
+
`\u274C ${PREFIX}: permission denied on ${what}. agent-config never runs sudo; run this yourself with the right permissions: ${manual.join(" ")}`
|
|
423
436
|
);
|
|
424
437
|
const untouched = ran.cmd === steps[0] && deps.readInstalled() === previous && deps.readBinary() === previous;
|
|
425
438
|
if (untouched) return 1;
|
|
@@ -428,6 +441,7 @@ async function run_unattended(deps) {
|
|
|
428
441
|
say(deps.err, `\u274C ${PREFIX}: step failed: ${what} \u2014 restoring ${previous}.`);
|
|
429
442
|
return restore(previous, deps);
|
|
430
443
|
} finally {
|
|
444
|
+
if (verified !== null) fs2.rmSync(path2.dirname(verified), { recursive: true, force: true });
|
|
431
445
|
release_lock(deps);
|
|
432
446
|
}
|
|
433
447
|
}
|
|
@@ -467,8 +481,8 @@ function skip_version(version, out) {
|
|
|
467
481
|
return 0;
|
|
468
482
|
}
|
|
469
483
|
async function run_unattended_default(options) {
|
|
470
|
-
const globalSettings =
|
|
471
|
-
const packageJson =
|
|
484
|
+
const globalSettings = path2.join(event4u_root(), "settings", ".agent-settings.yml");
|
|
485
|
+
const packageJson = path2.join(resolvePackageRoot(import.meta.url), "package.json");
|
|
472
486
|
let terminated = false;
|
|
473
487
|
const onTerm = () => {
|
|
474
488
|
terminated = true;
|
|
@@ -484,7 +498,7 @@ function run_unattended_wired(options, globalSettings, packageJson, interrupted)
|
|
|
484
498
|
return run_unattended({
|
|
485
499
|
readBinary: () => {
|
|
486
500
|
try {
|
|
487
|
-
const v = JSON.parse(
|
|
501
|
+
const v = JSON.parse(fs2.readFileSync(packageJson, "utf-8")).version;
|
|
488
502
|
return typeof v === "string" ? v : "";
|
|
489
503
|
} catch {
|
|
490
504
|
return "";
|
|
@@ -500,7 +514,7 @@ function run_unattended_wired(options, globalSettings, packageJson, interrupted)
|
|
|
500
514
|
},
|
|
501
515
|
origin: running_origin(),
|
|
502
516
|
agentConfigBin: options.agentConfigBin,
|
|
503
|
-
globalSettings:
|
|
517
|
+
globalSettings: fs2.existsSync(globalSettings) ? [globalSettings] : [],
|
|
504
518
|
lockPath: write_target(LOCK_FILE),
|
|
505
519
|
skipPath: write_target(SKIP_FILE),
|
|
506
520
|
env: {
|
|
@@ -523,6 +537,7 @@ export {
|
|
|
523
537
|
EXIT_RESTORE_FAILED,
|
|
524
538
|
LOCK_FILE,
|
|
525
539
|
LOCK_TTL_MS,
|
|
540
|
+
MAX_TARBALL_BYTES,
|
|
526
541
|
PACKAGE_NAME,
|
|
527
542
|
PACKUMENT_URL,
|
|
528
543
|
SKIP_FILE,
|
|
@@ -9206,7 +9206,7 @@
|
|
|
9206
9206
|
},
|
|
9207
9207
|
{
|
|
9208
9208
|
"category": "skill",
|
|
9209
|
-
"checksum": "sha256:
|
|
9209
|
+
"checksum": "sha256:f5dc56a475d0180931625a4c590af8b45dc365593fdd44ec992284d4d7b0d6c8",
|
|
9210
9210
|
"install": {
|
|
9211
9211
|
"default": true,
|
|
9212
9212
|
"removable": false
|
|
@@ -15120,7 +15120,7 @@
|
|
|
15120
15120
|
"workspaces": []
|
|
15121
15121
|
}
|
|
15122
15122
|
],
|
|
15123
|
-
"checksum": "sha256:
|
|
15123
|
+
"checksum": "sha256:03d3bf776b1cd4eb516f50f873eb435611b9d8ab590337913eb19e786224d144",
|
|
15124
15124
|
"deprecations": [
|
|
15125
15125
|
{
|
|
15126
15126
|
"key": "tier",
|
|
@@ -15269,7 +15269,7 @@
|
|
|
15269
15269
|
"reason": "scaffold template for ticket-bundle tickets (ADR-101); carries no runtime frontmatter — emit-tickets fills it in per ticket"
|
|
15270
15270
|
}
|
|
15271
15271
|
],
|
|
15272
|
-
"generated_at": "2026-10-
|
|
15272
|
+
"generated_at": "2026-10-24T10:59:12Z",
|
|
15273
15273
|
"packs": [
|
|
15274
15274
|
{
|
|
15275
15275
|
"artefact_count": 130,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
1388c41a068bccdb4c8ad314e25db5de1c2ba4e5bd68ba9ffa5a0f1cf5755318 discovery-manifest.json
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"checksum": "sha256:
|
|
3
|
-
"generated_at": "2026-10-
|
|
2
|
+
"checksum": "sha256:03d3bf776b1cd4eb516f50f873eb435611b9d8ab590337913eb19e786224d144",
|
|
3
|
+
"generated_at": "2026-10-24T10:59:12Z",
|
|
4
4
|
"packs": [
|
|
5
5
|
{
|
|
6
6
|
"always_on": false,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"checksum": "sha256:
|
|
3
|
-
"generated_at": "2026-10-
|
|
2
|
+
"checksum": "sha256:03d3bf776b1cd4eb516f50f873eb435611b9d8ab590337913eb19e786224d144",
|
|
3
|
+
"generated_at": "2026-10-24T10:59:12Z",
|
|
4
4
|
"scanner_version": "de0a22b4ac4c",
|
|
5
5
|
"workspaces": [
|
|
6
6
|
{
|