orionfold-relay 0.20.0 → 0.21.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/README.md +4 -1
- package/dist/cli.js +315 -67
- package/package.json +1 -1
- package/src/app/api/packs/update/route.ts +87 -0
- package/src/app/packs/page.tsx +33 -11
- package/src/components/packs/pack-update-button.tsx +102 -0
- package/src/lib/packs/cli.ts +63 -11
- package/src/lib/packs/install-state.ts +66 -0
- package/src/lib/packs/install.ts +60 -20
- package/src/lib/packs/templates/relay-agency-pro/base/blueprints/relay-agency-pro--grant-pipeline-deep.yaml +117 -0
- package/src/lib/packs/templates/relay-agency-pro/base/manifest.yaml +15 -2
- package/src/lib/packs/templates/relay-agency-pro/base/profiles/relay-agency-pro--nonprofit-grants-analyst/SKILL.md +59 -0
- package/src/lib/packs/templates/relay-agency-pro/base/profiles/relay-agency-pro--nonprofit-grants-analyst/profile.yaml +19 -0
- package/src/lib/packs/templates/relay-agency-pro/pack.yaml +8 -5
- package/src/lib/packs/update.ts +239 -0
- package/src/lib/plugins/examples/echo-server/plugin.yaml +1 -1
- package/src/lib/plugins/examples/finance-pack/plugin.yaml +1 -1
- package/src/lib/plugins/examples/reading-radar/plugin.yaml +1 -1
- package/src/lib/plugins/registry.ts +1 -1
- package/src/lib/plugins/sdk/types.ts +1 -1
package/README.md
CHANGED
|
@@ -143,7 +143,10 @@ relay license remove <license-id> # forget a license
|
|
|
143
143
|
pack. Paid packs are new content, not repossessed features.
|
|
144
144
|
|
|
145
145
|
The full terms in plain language — seats, transfer, what expiry does and doesn't do —
|
|
146
|
-
are in [docs/trust/license-terms.md](docs/trust/license-terms.md).
|
|
146
|
+
are in [docs/trust/license-terms.md](docs/trust/license-terms.md). The gating
|
|
147
|
+
philosophy behind the boundary — and the never-regress promise that binds us to it —
|
|
148
|
+
is published at [orionfold.com/promise](https://orionfold.com/promise/). Browse and
|
|
149
|
+
buy premium packs at [orionfold.com/relay](https://orionfold.com/relay/).
|
|
147
150
|
|
|
148
151
|
---
|
|
149
152
|
|
package/dist/cli.js
CHANGED
|
@@ -1186,7 +1186,7 @@ var CURRENT_PLUGIN_API_VERSION, CAPABILITY_VALUES, ORIGIN_VALUES, PrimitivesBund
|
|
|
1186
1186
|
var init_types = __esm({
|
|
1187
1187
|
"src/lib/plugins/sdk/types.ts"() {
|
|
1188
1188
|
"use strict";
|
|
1189
|
-
CURRENT_PLUGIN_API_VERSION = "0.
|
|
1189
|
+
CURRENT_PLUGIN_API_VERSION = "0.21";
|
|
1190
1190
|
CAPABILITY_VALUES = ["fs", "net", "child_process", "env"];
|
|
1191
1191
|
ORIGIN_VALUES = ["ainative-internal", "third-party"];
|
|
1192
1192
|
PrimitivesBundleManifestSchema = z.object({
|
|
@@ -1232,16 +1232,16 @@ function computeHash(content) {
|
|
|
1232
1232
|
function safePreview(content) {
|
|
1233
1233
|
return content.slice(0, MAX_PREVIEW_CHARS).trim();
|
|
1234
1234
|
}
|
|
1235
|
-
function safeStat(
|
|
1235
|
+
function safeStat(path23) {
|
|
1236
1236
|
try {
|
|
1237
|
-
return statSync2(
|
|
1237
|
+
return statSync2(path23);
|
|
1238
1238
|
} catch {
|
|
1239
1239
|
return null;
|
|
1240
1240
|
}
|
|
1241
1241
|
}
|
|
1242
|
-
function safeReadFile(
|
|
1242
|
+
function safeReadFile(path23) {
|
|
1243
1243
|
try {
|
|
1244
|
-
return readFileSync4(
|
|
1244
|
+
return readFileSync4(path23, "utf-8");
|
|
1245
1245
|
} catch {
|
|
1246
1246
|
return null;
|
|
1247
1247
|
}
|
|
@@ -11951,9 +11951,9 @@ function buildPermissionSummary(toolName, input) {
|
|
|
11951
11951
|
}
|
|
11952
11952
|
}
|
|
11953
11953
|
if (toolName === "Read" || toolName === "Write" || toolName === "Edit" || toolName === "read" || toolName === "write" || toolName === "edit") {
|
|
11954
|
-
const
|
|
11955
|
-
if (typeof
|
|
11956
|
-
return truncate(
|
|
11954
|
+
const path23 = input.file_path ?? input.path;
|
|
11955
|
+
if (typeof path23 === "string" && path23.trim().length > 0) {
|
|
11956
|
+
return truncate(path23.trim());
|
|
11957
11957
|
}
|
|
11958
11958
|
}
|
|
11959
11959
|
if (toolName?.startsWith("mcp__")) {
|
|
@@ -11987,9 +11987,9 @@ function getPermissionDetailEntries(toolName, input) {
|
|
|
11987
11987
|
}
|
|
11988
11988
|
}
|
|
11989
11989
|
if (toolName === "Read" || toolName === "Write" || toolName === "Edit" || toolName === "read" || toolName === "write" || toolName === "edit") {
|
|
11990
|
-
const
|
|
11991
|
-
if (typeof
|
|
11992
|
-
return [{ label: "Path", value:
|
|
11990
|
+
const path23 = input.file_path ?? input.path;
|
|
11991
|
+
if (typeof path23 === "string") {
|
|
11992
|
+
return [{ label: "Path", value: path23 }];
|
|
11993
11993
|
}
|
|
11994
11994
|
}
|
|
11995
11995
|
return Object.entries(input).slice(0, 6).map(([key, value]) => ({
|
|
@@ -12891,7 +12891,7 @@ var init_registry6 = __esm({
|
|
|
12891
12891
|
init_registry5();
|
|
12892
12892
|
init_installer();
|
|
12893
12893
|
init_schedule_spec();
|
|
12894
|
-
SUPPORTED_API_VERSIONS = /* @__PURE__ */ new Set([CURRENT_PLUGIN_API_VERSION, "0.
|
|
12894
|
+
SUPPORTED_API_VERSIONS = /* @__PURE__ */ new Set([CURRENT_PLUGIN_API_VERSION, "0.20"]);
|
|
12895
12895
|
pluginCache = null;
|
|
12896
12896
|
lastLoadedPluginIds = /* @__PURE__ */ new Set();
|
|
12897
12897
|
PluginTableSchema = z16.object({
|
|
@@ -12934,8 +12934,8 @@ function pluginTools(_ctx) {
|
|
|
12934
12934
|
Promise.resolve().then(() => (init_ainative_paths(), ainative_paths_exports)),
|
|
12935
12935
|
Promise.resolve().then(() => (init_types(), types_exports))
|
|
12936
12936
|
]);
|
|
12937
|
-
const
|
|
12938
|
-
const
|
|
12937
|
+
const fs22 = await import("fs");
|
|
12938
|
+
const path23 = await import("path");
|
|
12939
12939
|
const yaml13 = await import("js-yaml");
|
|
12940
12940
|
const kind5 = listPlugins2();
|
|
12941
12941
|
const registrations = await listPluginMcpRegistrations2();
|
|
@@ -12952,13 +12952,13 @@ function pluginTools(_ctx) {
|
|
|
12952
12952
|
let manifestHash;
|
|
12953
12953
|
let capabilityAcceptStatus = "pending";
|
|
12954
12954
|
try {
|
|
12955
|
-
const pluginYamlPath =
|
|
12955
|
+
const pluginYamlPath = path23.join(
|
|
12956
12956
|
pluginsDir,
|
|
12957
12957
|
pluginId,
|
|
12958
12958
|
"plugin.yaml"
|
|
12959
12959
|
);
|
|
12960
|
-
if (
|
|
12961
|
-
const content =
|
|
12960
|
+
if (fs22.existsSync(pluginYamlPath)) {
|
|
12961
|
+
const content = fs22.readFileSync(pluginYamlPath, "utf-8");
|
|
12962
12962
|
const rawManifest = yaml13.load(content);
|
|
12963
12963
|
if (rawManifest !== null && typeof rawManifest === "object" && !Array.isArray(rawManifest)) {
|
|
12964
12964
|
const record = rawManifest;
|
|
@@ -12971,7 +12971,7 @@ function pluginTools(_ctx) {
|
|
|
12971
12971
|
try {
|
|
12972
12972
|
manifestHash = deriveManifestHash2(content);
|
|
12973
12973
|
const parsed = PluginManifestSchema2.safeParse(rawManifest);
|
|
12974
|
-
const pluginRootDir =
|
|
12974
|
+
const pluginRootDir = path23.join(pluginsDir, pluginId);
|
|
12975
12975
|
const check = isCapabilityAccepted2(
|
|
12976
12976
|
pluginId,
|
|
12977
12977
|
manifestHash,
|
|
@@ -19387,13 +19387,13 @@ var init_codex_app_server_client = __esm({
|
|
|
19387
19387
|
await syncPluginMcpToCodex2();
|
|
19388
19388
|
} catch (err2) {
|
|
19389
19389
|
try {
|
|
19390
|
-
const
|
|
19391
|
-
const
|
|
19390
|
+
const fs22 = await import("fs");
|
|
19391
|
+
const path23 = await import("path");
|
|
19392
19392
|
const { getAinativeLogsDir: getAinativeLogsDir2 } = await Promise.resolve().then(() => (init_ainative_paths(), ainative_paths_exports));
|
|
19393
19393
|
const dir = getAinativeLogsDir2();
|
|
19394
|
-
|
|
19395
|
-
|
|
19396
|
-
|
|
19394
|
+
fs22.mkdirSync(dir, { recursive: true });
|
|
19395
|
+
fs22.appendFileSync(
|
|
19396
|
+
path23.join(dir, "plugins.log"),
|
|
19397
19397
|
`${(/* @__PURE__ */ new Date()).toISOString()} codex-sync-failed: ${err2 instanceof Error ? err2.message : String(err2)}
|
|
19398
19398
|
`
|
|
19399
19399
|
);
|
|
@@ -22985,14 +22985,14 @@ function resolvePostAction(action, row, itemVariable) {
|
|
|
22985
22985
|
function substituteRowPath(template, row, itemVariable) {
|
|
22986
22986
|
const escaped = itemVariable.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
22987
22987
|
const pattern = new RegExp(`\\{\\{\\s*${escaped}\\.([\\w.]+)\\s*\\}\\}`, "g");
|
|
22988
|
-
return template.replace(pattern, (_match,
|
|
22989
|
-
const value = readPath(row,
|
|
22988
|
+
return template.replace(pattern, (_match, path23) => {
|
|
22989
|
+
const value = readPath(row, path23);
|
|
22990
22990
|
if (value === void 0 || value === null) return "";
|
|
22991
22991
|
return String(value);
|
|
22992
22992
|
});
|
|
22993
22993
|
}
|
|
22994
|
-
function readPath(obj,
|
|
22995
|
-
const parts =
|
|
22994
|
+
function readPath(obj, path23) {
|
|
22995
|
+
const parts = path23.split(".");
|
|
22996
22996
|
let current = obj;
|
|
22997
22997
|
for (const part of parts) {
|
|
22998
22998
|
if (current === null || current === void 0) return void 0;
|
|
@@ -23179,14 +23179,14 @@ ${resolvedTemplate}`);
|
|
|
23179
23179
|
return parts.join("");
|
|
23180
23180
|
}
|
|
23181
23181
|
function resolveRowTemplate(template, context) {
|
|
23182
|
-
return template.replace(/\{\{\s*([^}]+)\s*\}\}/g, (_match,
|
|
23183
|
-
const value = readContextPath(context,
|
|
23182
|
+
return template.replace(/\{\{\s*([^}]+)\s*\}\}/g, (_match, path23) => {
|
|
23183
|
+
const value = readContextPath(context, path23.trim());
|
|
23184
23184
|
if (value === void 0 || value === null) return "";
|
|
23185
23185
|
return typeof value === "string" ? value : JSON.stringify(value);
|
|
23186
23186
|
});
|
|
23187
23187
|
}
|
|
23188
|
-
function readContextPath(value,
|
|
23189
|
-
const parts =
|
|
23188
|
+
function readContextPath(value, path23) {
|
|
23189
|
+
const parts = path23.split(".");
|
|
23190
23190
|
let current = value;
|
|
23191
23191
|
for (const part of parts) {
|
|
23192
23192
|
if (current === null || current === void 0) return void 0;
|
|
@@ -25611,25 +25611,76 @@ var init_app_schedule_id = __esm({
|
|
|
25611
25611
|
}
|
|
25612
25612
|
});
|
|
25613
25613
|
|
|
25614
|
+
// src/lib/packs/install-state.ts
|
|
25615
|
+
var install_state_exports = {};
|
|
25616
|
+
__export(install_state_exports, {
|
|
25617
|
+
InstallStateSchema: () => InstallStateSchema,
|
|
25618
|
+
hashFileSha256: () => hashFileSha256,
|
|
25619
|
+
installStatePath: () => installStatePath,
|
|
25620
|
+
readInstallState: () => readInstallState,
|
|
25621
|
+
writeInstallState: () => writeInstallState
|
|
25622
|
+
});
|
|
25623
|
+
import fs19 from "fs";
|
|
25624
|
+
import path20 from "path";
|
|
25625
|
+
import { createHash as createHash5 } from "crypto";
|
|
25626
|
+
import { z as z30 } from "zod";
|
|
25627
|
+
function installStatePath(appsDir, appId) {
|
|
25628
|
+
return path20.join(appsDir, appId, "install-state.json");
|
|
25629
|
+
}
|
|
25630
|
+
function readInstallState(appsDir, appId) {
|
|
25631
|
+
try {
|
|
25632
|
+
const raw = fs19.readFileSync(installStatePath(appsDir, appId), "utf-8");
|
|
25633
|
+
const parsed = InstallStateSchema.safeParse(JSON.parse(raw));
|
|
25634
|
+
return parsed.success ? parsed.data : null;
|
|
25635
|
+
} catch {
|
|
25636
|
+
return null;
|
|
25637
|
+
}
|
|
25638
|
+
}
|
|
25639
|
+
function writeInstallState(appsDir, appId, state) {
|
|
25640
|
+
const dir = path20.join(appsDir, appId);
|
|
25641
|
+
fs19.mkdirSync(dir, { recursive: true });
|
|
25642
|
+
const tmp = path20.join(dir, `.install-state.${process.pid}.tmp`);
|
|
25643
|
+
fs19.writeFileSync(tmp, JSON.stringify(state, null, 2) + "\n");
|
|
25644
|
+
fs19.renameSync(tmp, installStatePath(appsDir, appId));
|
|
25645
|
+
}
|
|
25646
|
+
function hashFileSha256(absPath) {
|
|
25647
|
+
return createHash5("sha256").update(fs19.readFileSync(absPath)).digest("hex");
|
|
25648
|
+
}
|
|
25649
|
+
var InstallStateSchema;
|
|
25650
|
+
var init_install_state = __esm({
|
|
25651
|
+
"src/lib/packs/install-state.ts"() {
|
|
25652
|
+
"use strict";
|
|
25653
|
+
InstallStateSchema = z30.object({
|
|
25654
|
+
packVersion: z30.string().min(1),
|
|
25655
|
+
installedAt: z30.string().min(1),
|
|
25656
|
+
/** Dropped-artifact relPath (pack space, e.g. "profiles/x--y/SKILL.md") → sha256 hex of the DEST bytes. */
|
|
25657
|
+
files: z30.record(z30.string(), z30.string())
|
|
25658
|
+
}).strict();
|
|
25659
|
+
}
|
|
25660
|
+
});
|
|
25661
|
+
|
|
25614
25662
|
// src/lib/packs/install.ts
|
|
25615
25663
|
var install_exports = {};
|
|
25616
25664
|
__export(install_exports, {
|
|
25617
|
-
|
|
25665
|
+
acquirePack: () => acquirePack,
|
|
25666
|
+
artifactDestPath: () => artifactDestPath,
|
|
25667
|
+
installPack: () => installPack,
|
|
25668
|
+
relayCoreVersion: () => relayCoreVersion
|
|
25618
25669
|
});
|
|
25619
|
-
import
|
|
25620
|
-
import
|
|
25670
|
+
import fs20 from "fs";
|
|
25671
|
+
import path21 from "path";
|
|
25621
25672
|
import os4 from "os";
|
|
25622
25673
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
25623
25674
|
import yaml12 from "js-yaml";
|
|
25624
25675
|
import semver from "semver";
|
|
25625
25676
|
function relayCoreVersion() {
|
|
25626
|
-
if (semver.valid("0.
|
|
25627
|
-
return "0.
|
|
25677
|
+
if (semver.valid("0.21.0")) {
|
|
25678
|
+
return "0.21.0";
|
|
25628
25679
|
}
|
|
25629
25680
|
try {
|
|
25630
25681
|
const root = getAppRoot(import.meta.dirname, 3);
|
|
25631
25682
|
const pkg2 = JSON.parse(
|
|
25632
|
-
|
|
25683
|
+
fs20.readFileSync(path21.join(root, "package.json"), "utf-8")
|
|
25633
25684
|
);
|
|
25634
25685
|
if (pkg2.version && semver.valid(pkg2.version)) return pkg2.version;
|
|
25635
25686
|
} catch {
|
|
@@ -25783,11 +25834,21 @@ async function installPack(source, options = {}) {
|
|
|
25783
25834
|
droppedManifest.entitlement = pack.meta.entitlement;
|
|
25784
25835
|
}
|
|
25785
25836
|
writeManifest(appsDir, pack.meta.id, droppedManifest);
|
|
25786
|
-
const { profilesDropped, blueprintsDropped } = dropArtifacts(
|
|
25837
|
+
const { profilesDropped, blueprintsDropped, dropped } = dropArtifacts(
|
|
25787
25838
|
resolved.files,
|
|
25788
25839
|
profilesDir,
|
|
25789
25840
|
blueprintsDir
|
|
25790
25841
|
);
|
|
25842
|
+
const { writeInstallState: writeInstallState2, hashFileSha256: hashFileSha2562 } = await Promise.resolve().then(() => (init_install_state(), install_state_exports));
|
|
25843
|
+
const stateFiles = {};
|
|
25844
|
+
for (const artifact of dropped) {
|
|
25845
|
+
stateFiles[artifact.relPath] = hashFileSha2562(artifact.destPath);
|
|
25846
|
+
}
|
|
25847
|
+
writeInstallState2(appsDir, pack.meta.id, {
|
|
25848
|
+
packVersion: pack.meta.version,
|
|
25849
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
25850
|
+
files: stateFiles
|
|
25851
|
+
});
|
|
25791
25852
|
if (blueprintsDropped > 0) {
|
|
25792
25853
|
const { reloadBlueprints: reloadBlueprints2 } = await Promise.resolve().then(() => (init_registry3(), registry_exports3));
|
|
25793
25854
|
reloadBlueprints2();
|
|
@@ -25812,25 +25873,25 @@ function isGitUrl(source) {
|
|
|
25812
25873
|
}
|
|
25813
25874
|
function acquirePack(source) {
|
|
25814
25875
|
if (!isGitUrl(source)) {
|
|
25815
|
-
const resolved =
|
|
25816
|
-
if (!
|
|
25876
|
+
const resolved = path21.resolve(source);
|
|
25877
|
+
if (!fs20.existsSync(resolved)) {
|
|
25817
25878
|
throw new PackValidationError(`Pack path does not exist: ${resolved}`);
|
|
25818
25879
|
}
|
|
25819
25880
|
return { dir: resolved, cleanup: () => {
|
|
25820
25881
|
} };
|
|
25821
25882
|
}
|
|
25822
|
-
const tmp =
|
|
25883
|
+
const tmp = fs20.mkdtempSync(path21.join(os4.tmpdir(), "ainative-pack-clone-"));
|
|
25823
25884
|
try {
|
|
25824
25885
|
execFileSync3("git", ["clone", "--depth", "1", source, tmp], {
|
|
25825
25886
|
stdio: "pipe"
|
|
25826
25887
|
});
|
|
25827
25888
|
} catch (err2) {
|
|
25828
|
-
|
|
25889
|
+
fs20.rmSync(tmp, { recursive: true, force: true });
|
|
25829
25890
|
throw new PackValidationError(`git clone failed for ${source}`, err2);
|
|
25830
25891
|
}
|
|
25831
25892
|
return {
|
|
25832
25893
|
dir: tmp,
|
|
25833
|
-
cleanup: () =>
|
|
25894
|
+
cleanup: () => fs20.rmSync(tmp, { recursive: true, force: true })
|
|
25834
25895
|
};
|
|
25835
25896
|
}
|
|
25836
25897
|
function findResolved(files, relPath) {
|
|
@@ -25839,7 +25900,7 @@ function findResolved(files, relPath) {
|
|
|
25839
25900
|
function readCustomerSeed(resolved) {
|
|
25840
25901
|
const file = findResolved(resolved.files, "seed/customers.yaml");
|
|
25841
25902
|
if (!file) return [];
|
|
25842
|
-
const parsed = yaml12.load(
|
|
25903
|
+
const parsed = yaml12.load(fs20.readFileSync(file.absPath, "utf-8"));
|
|
25843
25904
|
if (!Array.isArray(parsed)) {
|
|
25844
25905
|
throw new PackValidationError(
|
|
25845
25906
|
"seed/customers.yaml must be a YAML list of { slug, name, ... }"
|
|
@@ -25851,7 +25912,7 @@ function readTableSeed(resolved, logicalId) {
|
|
|
25851
25912
|
for (const ext of ["json", "yaml", "yml"]) {
|
|
25852
25913
|
const file = findResolved(resolved.files, `seed/tables/${logicalId}.${ext}`);
|
|
25853
25914
|
if (!file) continue;
|
|
25854
|
-
const text2 =
|
|
25915
|
+
const text2 = fs20.readFileSync(file.absPath, "utf-8");
|
|
25855
25916
|
const parsed = ext === "json" ? JSON.parse(text2) : yaml12.load(text2);
|
|
25856
25917
|
if (!Array.isArray(parsed)) {
|
|
25857
25918
|
throw new PackValidationError(
|
|
@@ -25909,30 +25970,36 @@ function rewriteViewRefs(view, maps) {
|
|
|
25909
25970
|
return view;
|
|
25910
25971
|
}
|
|
25911
25972
|
function writeManifest(appsDir, appId, manifest) {
|
|
25912
|
-
|
|
25973
|
+
fs20.mkdirSync(path21.join(appsDir, appId), { recursive: true });
|
|
25913
25974
|
writeAppManifest(appId, manifest, appsDir);
|
|
25914
25975
|
}
|
|
25976
|
+
function artifactDestPath(relPath, profilesDir, blueprintsDir) {
|
|
25977
|
+
if (relPath.startsWith("profiles/")) {
|
|
25978
|
+
return path21.join(profilesDir, relPath.slice("profiles/".length));
|
|
25979
|
+
}
|
|
25980
|
+
if (relPath.startsWith("blueprints/") && relPath.endsWith(".yaml")) {
|
|
25981
|
+
return path21.join(blueprintsDir, relPath.slice("blueprints/".length));
|
|
25982
|
+
}
|
|
25983
|
+
return null;
|
|
25984
|
+
}
|
|
25915
25985
|
function dropArtifacts(files, profilesDir, blueprintsDir) {
|
|
25916
25986
|
const profileDirs = /* @__PURE__ */ new Set();
|
|
25917
25987
|
let blueprintsDropped = 0;
|
|
25988
|
+
const dropped = [];
|
|
25918
25989
|
for (const file of files) {
|
|
25990
|
+
const dest = artifactDestPath(file.relPath, profilesDir, blueprintsDir);
|
|
25991
|
+
if (!dest) continue;
|
|
25992
|
+
fs20.mkdirSync(path21.dirname(dest), { recursive: true });
|
|
25993
|
+
fs20.copyFileSync(file.absPath, dest);
|
|
25994
|
+
dropped.push({ relPath: file.relPath, destPath: dest });
|
|
25919
25995
|
if (file.relPath.startsWith("profiles/")) {
|
|
25920
|
-
const dest = path20.join(profilesDir, file.relPath.slice("profiles/".length));
|
|
25921
|
-
fs19.mkdirSync(path20.dirname(dest), { recursive: true });
|
|
25922
|
-
fs19.copyFileSync(file.absPath, dest);
|
|
25923
25996
|
const top = file.relPath.split("/")[1];
|
|
25924
25997
|
if (top) profileDirs.add(top);
|
|
25925
|
-
} else
|
|
25926
|
-
const dest = path20.join(
|
|
25927
|
-
blueprintsDir,
|
|
25928
|
-
file.relPath.slice("blueprints/".length)
|
|
25929
|
-
);
|
|
25930
|
-
fs19.mkdirSync(path20.dirname(dest), { recursive: true });
|
|
25931
|
-
fs19.copyFileSync(file.absPath, dest);
|
|
25998
|
+
} else {
|
|
25932
25999
|
blueprintsDropped += 1;
|
|
25933
26000
|
}
|
|
25934
26001
|
}
|
|
25935
|
-
return { profilesDropped: profileDirs.size, blueprintsDropped };
|
|
26002
|
+
return { profilesDropped: profileDirs.size, blueprintsDropped, dropped };
|
|
25936
26003
|
}
|
|
25937
26004
|
function titleCase3(slug) {
|
|
25938
26005
|
return slug.split(/[-_]/).filter(Boolean).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
|
|
@@ -25947,6 +26014,145 @@ var init_install = __esm({
|
|
|
25947
26014
|
}
|
|
25948
26015
|
});
|
|
25949
26016
|
|
|
26017
|
+
// src/lib/packs/update.ts
|
|
26018
|
+
var update_exports = {};
|
|
26019
|
+
__export(update_exports, {
|
|
26020
|
+
PackNotInstalledError: () => PackNotInstalledError,
|
|
26021
|
+
packUpdateAvailability: () => packUpdateAvailability,
|
|
26022
|
+
updatePack: () => updatePack
|
|
26023
|
+
});
|
|
26024
|
+
import fs21 from "fs";
|
|
26025
|
+
import path22 from "path";
|
|
26026
|
+
import semver2 from "semver";
|
|
26027
|
+
function packUpdateAvailability(appId, opts2 = {}) {
|
|
26028
|
+
const appsDir = opts2.appsDir ?? getAinativeAppsDir();
|
|
26029
|
+
const installedVersion = readInstallState(appsDir, appId)?.packVersion ?? null;
|
|
26030
|
+
const template = findPackTemplate(appId, { templatesDir: opts2.templatesDir });
|
|
26031
|
+
const availableVersion = template?.meta?.version ?? null;
|
|
26032
|
+
const updateAvailable = availableVersion !== null && semver2.valid(availableVersion) !== null && (installedVersion === null || semver2.valid(installedVersion) === null || semver2.compare(availableVersion, installedVersion) > 0);
|
|
26033
|
+
return { installedVersion, availableVersion, updateAvailable };
|
|
26034
|
+
}
|
|
26035
|
+
async function updatePack(id, options = {}) {
|
|
26036
|
+
const appsDir = options.appsDir ?? getAinativeAppsDir();
|
|
26037
|
+
const profilesDir = options.profilesDir ?? getAinativeProfilesDir();
|
|
26038
|
+
const blueprintsDir = options.blueprintsDir ?? getAinativeBlueprintsDir();
|
|
26039
|
+
const installed = getApp(id, appsDir);
|
|
26040
|
+
if (!installed) {
|
|
26041
|
+
throw new PackNotInstalledError(
|
|
26042
|
+
`Pack "${id}" is not installed. Install it first with: relay pack add ${id}`
|
|
26043
|
+
);
|
|
26044
|
+
}
|
|
26045
|
+
const state = readInstallState(appsDir, id);
|
|
26046
|
+
const previousVersion = state?.packVersion ?? null;
|
|
26047
|
+
const { resolvePackSource: resolvePackSource2 } = await Promise.resolve().then(() => (init_catalog(), catalog_exports));
|
|
26048
|
+
const resolvedSource = resolvePackSource2(options.source ?? id, {
|
|
26049
|
+
templatesDir: options.templatesDir
|
|
26050
|
+
});
|
|
26051
|
+
const { dir: packDir, cleanup } = acquirePack(resolvedSource);
|
|
26052
|
+
try {
|
|
26053
|
+
const pack = parsePack(packDir);
|
|
26054
|
+
if (pack.meta.id !== id) {
|
|
26055
|
+
throw new PackValidationError(
|
|
26056
|
+
`Update source is pack "${pack.meta.id}", not "${id}" \u2014 refusing to cross-update.`
|
|
26057
|
+
);
|
|
26058
|
+
}
|
|
26059
|
+
const coreVersion = options.coreVersion ?? relayCoreVersion();
|
|
26060
|
+
if (pack.meta.relayCore && !semver2.satisfies(coreVersion, pack.meta.relayCore)) {
|
|
26061
|
+
throw new PackValidationError(
|
|
26062
|
+
`Pack ${pack.meta.id}@${pack.meta.version} requires relay-core ${pack.meta.relayCore}, but this install is ${coreVersion}.`
|
|
26063
|
+
);
|
|
26064
|
+
}
|
|
26065
|
+
const newVersion = pack.meta.version;
|
|
26066
|
+
if (previousVersion !== null && semver2.valid(previousVersion) && semver2.valid(newVersion) && semver2.compare(newVersion, previousVersion) <= 0) {
|
|
26067
|
+
return {
|
|
26068
|
+
packId: id,
|
|
26069
|
+
previousVersion,
|
|
26070
|
+
newVersion,
|
|
26071
|
+
upToDate: true,
|
|
26072
|
+
backedUp: []
|
|
26073
|
+
};
|
|
26074
|
+
}
|
|
26075
|
+
if (pack.meta.entitlement) {
|
|
26076
|
+
const { assertEntitled: assertEntitled2, PackLicenseError: PackLicenseError2 } = await Promise.resolve().then(() => (init_gate(), gate_exports));
|
|
26077
|
+
try {
|
|
26078
|
+
if (options.licenseUrl) {
|
|
26079
|
+
const { loadLicense: loadLicense2 } = await Promise.resolve().then(() => (init_load(), load_exports));
|
|
26080
|
+
const license = await loadLicense2(options.licenseUrl);
|
|
26081
|
+
assertEntitled2(pack.meta.entitlement, license);
|
|
26082
|
+
} else {
|
|
26083
|
+
const { findEntitledLicense: findEntitledLicense2 } = await Promise.resolve().then(() => (init_store(), store_exports));
|
|
26084
|
+
if (!findEntitledLicense2(pack.meta.entitlement)) {
|
|
26085
|
+
assertEntitled2(pack.meta.entitlement, void 0);
|
|
26086
|
+
}
|
|
26087
|
+
}
|
|
26088
|
+
} catch (err2) {
|
|
26089
|
+
if (err2 instanceof PackLicenseError2) {
|
|
26090
|
+
const renew = pack.meta.purchaseUrl ? `renew at ${pack.meta.purchaseUrl}` : `redeem one with: relay license add <path-or-url to your .license.json>`;
|
|
26091
|
+
throw new PackLicenseError2(
|
|
26092
|
+
`Your installed ${id} keeps working \u2014 nothing is locked. Updating to v${newVersion} needs an active license: ${renew}. (${err2.message})`,
|
|
26093
|
+
err2.reason
|
|
26094
|
+
);
|
|
26095
|
+
}
|
|
26096
|
+
throw err2;
|
|
26097
|
+
}
|
|
26098
|
+
}
|
|
26099
|
+
const resolved = resolvePackLayer(pack);
|
|
26100
|
+
const backupRoot = path22.join(
|
|
26101
|
+
appsDir,
|
|
26102
|
+
id,
|
|
26103
|
+
"backup",
|
|
26104
|
+
previousVersion ?? "unknown"
|
|
26105
|
+
);
|
|
26106
|
+
const backedUp = [];
|
|
26107
|
+
for (const file of resolved.files) {
|
|
26108
|
+
const dest = artifactDestPath(file.relPath, profilesDir, blueprintsDir);
|
|
26109
|
+
if (!dest || !fs21.existsSync(dest)) continue;
|
|
26110
|
+
const recorded = state?.files[file.relPath];
|
|
26111
|
+
if (recorded !== void 0 && hashFileSha256(dest) === recorded) continue;
|
|
26112
|
+
const backupPath = path22.join(backupRoot, file.relPath);
|
|
26113
|
+
fs21.mkdirSync(path22.dirname(backupPath), { recursive: true });
|
|
26114
|
+
fs21.copyFileSync(dest, backupPath);
|
|
26115
|
+
backedUp.push(file.relPath);
|
|
26116
|
+
}
|
|
26117
|
+
const install = await installPack(packDir, {
|
|
26118
|
+
appsDir,
|
|
26119
|
+
profilesDir,
|
|
26120
|
+
blueprintsDir,
|
|
26121
|
+
coreVersion: options.coreVersion,
|
|
26122
|
+
licenseUrl: options.licenseUrl,
|
|
26123
|
+
templatesDir: options.templatesDir
|
|
26124
|
+
});
|
|
26125
|
+
return {
|
|
26126
|
+
packId: id,
|
|
26127
|
+
previousVersion,
|
|
26128
|
+
newVersion,
|
|
26129
|
+
upToDate: false,
|
|
26130
|
+
backedUp,
|
|
26131
|
+
install
|
|
26132
|
+
};
|
|
26133
|
+
} finally {
|
|
26134
|
+
cleanup();
|
|
26135
|
+
}
|
|
26136
|
+
}
|
|
26137
|
+
var PackNotInstalledError;
|
|
26138
|
+
var init_update = __esm({
|
|
26139
|
+
"src/lib/packs/update.ts"() {
|
|
26140
|
+
"use strict";
|
|
26141
|
+
init_ainative_paths();
|
|
26142
|
+
init_registry();
|
|
26143
|
+
init_install();
|
|
26144
|
+
init_format();
|
|
26145
|
+
init_catalog();
|
|
26146
|
+
init_install_state();
|
|
26147
|
+
PackNotInstalledError = class extends Error {
|
|
26148
|
+
constructor(message) {
|
|
26149
|
+
super(message);
|
|
26150
|
+
this.name = "PackNotInstalledError";
|
|
26151
|
+
}
|
|
26152
|
+
};
|
|
26153
|
+
}
|
|
26154
|
+
});
|
|
26155
|
+
|
|
25950
26156
|
// src/lib/packs/cli.ts
|
|
25951
26157
|
var cli_exports = {};
|
|
25952
26158
|
__export(cli_exports, {
|
|
@@ -25980,7 +26186,7 @@ async function runPackCommand(argv, io) {
|
|
|
25980
26186
|
case "remove":
|
|
25981
26187
|
return runRemove(arg, io);
|
|
25982
26188
|
case "update":
|
|
25983
|
-
return runUpdate(arg, io);
|
|
26189
|
+
return runUpdate(arg, rest[1], licenseUrl, io);
|
|
25984
26190
|
default:
|
|
25985
26191
|
io.error(`Unknown pack action: ${action ?? "(none)"}`);
|
|
25986
26192
|
io.error(USAGE);
|
|
@@ -26020,9 +26226,15 @@ async function runList(io) {
|
|
|
26020
26226
|
io.log("No packs installed.");
|
|
26021
26227
|
return 0;
|
|
26022
26228
|
}
|
|
26229
|
+
const { packUpdateAvailability: packUpdateAvailability2 } = await Promise.resolve().then(() => (init_update(), update_exports));
|
|
26023
26230
|
for (const app of apps) {
|
|
26024
26231
|
const premium = app.entitlement ? " [premium]" : "";
|
|
26025
|
-
|
|
26232
|
+
const avail = packUpdateAvailability2(app.id, { appsDir });
|
|
26233
|
+
const version = avail.installedVersion ? ` installed v${avail.installedVersion}` : "";
|
|
26234
|
+
const update = avail.updateAvailable && avail.availableVersion ? ` [update available \u2192 v${avail.availableVersion}]` : "";
|
|
26235
|
+
io.log(
|
|
26236
|
+
`${app.id} ${app.name} ${app.primitivesSummary}${version}${update}${premium}`
|
|
26237
|
+
);
|
|
26026
26238
|
}
|
|
26027
26239
|
return 0;
|
|
26028
26240
|
} catch (err2) {
|
|
@@ -26062,11 +26274,47 @@ async function runRemove(id, io) {
|
|
|
26062
26274
|
return 1;
|
|
26063
26275
|
}
|
|
26064
26276
|
}
|
|
26065
|
-
async function runUpdate(id, io) {
|
|
26066
|
-
|
|
26067
|
-
|
|
26068
|
-
|
|
26069
|
-
|
|
26277
|
+
async function runUpdate(id, source, licenseUrl, io) {
|
|
26278
|
+
if (!id) {
|
|
26279
|
+
io.error(
|
|
26280
|
+
"Missing pack id. Usage: relay pack update <id> [source] [--license-url=<path|url>]"
|
|
26281
|
+
);
|
|
26282
|
+
return 1;
|
|
26283
|
+
}
|
|
26284
|
+
try {
|
|
26285
|
+
const { updatePack: updatePack2 } = await Promise.resolve().then(() => (init_update(), update_exports));
|
|
26286
|
+
const report = await updatePack2(id, {
|
|
26287
|
+
appsDir: io.appsDir,
|
|
26288
|
+
profilesDir: io.profilesDir,
|
|
26289
|
+
blueprintsDir: io.blueprintsDir,
|
|
26290
|
+
source,
|
|
26291
|
+
licenseUrl
|
|
26292
|
+
});
|
|
26293
|
+
if (report.upToDate) {
|
|
26294
|
+
io.log(
|
|
26295
|
+
`${report.packId} is already up to date (v${report.newVersion}).`
|
|
26296
|
+
);
|
|
26297
|
+
return 0;
|
|
26298
|
+
}
|
|
26299
|
+
const install = report.install;
|
|
26300
|
+
io.log(
|
|
26301
|
+
`Updated ${report.packId} v${report.previousVersion ?? "unknown"} \u2192 v${report.newVersion}: ${install.tablesCreated} table(s) added (${install.rowsSeeded} row(s)), ${install.profilesDropped} profile(s), ${install.blueprintsDropped} blueprint(s), ${install.schedulesRegistered} schedule(s).`
|
|
26302
|
+
);
|
|
26303
|
+
if (report.backedUp.length > 0) {
|
|
26304
|
+
io.log(
|
|
26305
|
+
`Backed up ${report.backedUp.length} user-modified file(s) to apps/${report.packId}/backup/${report.previousVersion ?? "unknown"}/ before overwriting:`
|
|
26306
|
+
);
|
|
26307
|
+
for (const relPath of report.backedUp) {
|
|
26308
|
+
io.log(` ${relPath}`);
|
|
26309
|
+
}
|
|
26310
|
+
}
|
|
26311
|
+
return 0;
|
|
26312
|
+
} catch (err2) {
|
|
26313
|
+
io.error(
|
|
26314
|
+
`Failed to update pack: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
26315
|
+
);
|
|
26316
|
+
return 1;
|
|
26317
|
+
}
|
|
26070
26318
|
}
|
|
26071
26319
|
var USAGE;
|
|
26072
26320
|
var init_cli = __esm({
|
|
@@ -26078,7 +26326,7 @@ var init_cli = __esm({
|
|
|
26078
26326
|
" add <name|path|git-url> [--license-url=<path|url>] install a pack",
|
|
26079
26327
|
" list list installed packs",
|
|
26080
26328
|
" remove <id> uninstall a pack",
|
|
26081
|
-
" update <id>
|
|
26329
|
+
" update <id> [source] [--license-url=<path|url>] update to a newer version"
|
|
26082
26330
|
].join("\n");
|
|
26083
26331
|
}
|
|
26084
26332
|
});
|
|
@@ -26548,10 +26796,10 @@ import { existsSync as existsSync4, renameSync, cpSync, rmSync as rmSync2, readF
|
|
|
26548
26796
|
import { join as join6 } from "path";
|
|
26549
26797
|
import { homedir as homedir2 } from "os";
|
|
26550
26798
|
import Database from "better-sqlite3";
|
|
26551
|
-
function hasSqliteHeader(
|
|
26799
|
+
function hasSqliteHeader(path23) {
|
|
26552
26800
|
const SQLITE_MAGIC = "SQLite format 3\0";
|
|
26553
26801
|
try {
|
|
26554
|
-
const header = readFileSync3(
|
|
26802
|
+
const header = readFileSync3(path23, { encoding: null });
|
|
26555
26803
|
return header.length >= 16 && header.subarray(0, 16).toString("binary") === SQLITE_MAGIC;
|
|
26556
26804
|
} catch {
|
|
26557
26805
|
return false;
|