@octonodes/cli 0.1.13 → 0.1.14

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.
@@ -346,10 +346,10 @@ var require_croner = __commonJS({
346
346
  if (t && typeof t == "object" || typeof t == "function") for (let s of E(t)) !M.call(n, s) && s !== e && D(n, s, { get: () => t[s], enumerable: !(r = x(t, s)) || r.enumerable });
347
347
  return n;
348
348
  };
349
- var z2 = (n) => A(D({}, "__esModule", { value: true }), n);
349
+ var z3 = (n) => A(D({}, "__esModule", { value: true }), n);
350
350
  var W = {};
351
351
  U(W, { Cron: () => N, CronDate: () => h, CronPattern: () => g, scheduledJobs: () => C });
352
- module2.exports = z2(W);
352
+ module2.exports = z3(W);
353
353
  function f(n, t, e, r, s, i, a, l) {
354
354
  return f.fromTZ(f.tp(n, t, e, r, s, i, a), l);
355
355
  }
@@ -2639,8 +2639,8 @@ var require_planning = __commonJS({
2639
2639
  version: collaboration_1.revisionSchema,
2640
2640
  createdAt: common_1.taskTimestampSchema,
2641
2641
  updatedAt: common_1.taskTimestampSchema
2642
- }).strict().superRefine((release, context) => {
2643
- if (release.state === "released" && release.releasedAt === null) {
2642
+ }).strict().superRefine((release2, context) => {
2643
+ if (release2.state === "released" && release2.releasedAt === null) {
2644
2644
  context.addIssue({
2645
2645
  code: zod_1.z.ZodIssueCode.custom,
2646
2646
  path: ["releasedAt"],
@@ -7719,10 +7719,10 @@ var require_build = __commonJS({
7719
7719
  else out += sub.appendTo();
7720
7720
  break;
7721
7721
  case Regexp2.Op.ALTERNATE: {
7722
- let sep = "";
7722
+ let sep2 = "";
7723
7723
  for (let sub of this.subs) {
7724
- out += sep;
7725
- sep = "|";
7724
+ out += sep2;
7725
+ sep2 = "|";
7726
7726
  out += sub.appendTo();
7727
7727
  }
7728
7728
  break;
@@ -11456,6 +11456,58 @@ var require_plugin_version = __commonJS({
11456
11456
  }
11457
11457
  });
11458
11458
 
11459
+ // packages/schema/dist/plugin/execution.constants.js
11460
+ var require_execution_constants = __commonJS({
11461
+ "packages/schema/dist/plugin/execution.constants.js"(exports2) {
11462
+ "use strict";
11463
+ Object.defineProperty(exports2, "__esModule", { value: true });
11464
+ exports2.PREPARED_RUNTIME_ARCHIVE = exports2.PREPARED_RUNTIME_MAX_FILES = exports2.PREPARED_RUNTIME_MAX_BYTES = exports2.PLUGIN_EXECUTION_TIMEOUT_MS = exports2.PLUGIN_EXECUTION_MAX_BYTES = exports2.PLUGIN_RUNNER_PORT = exports2.PLUGIN_RUNNER_ORIGIN = void 0;
11465
+ exports2.PLUGIN_RUNNER_ORIGIN = "http://plugin-runner.octonode.internal";
11466
+ exports2.PLUGIN_RUNNER_PORT = 4001;
11467
+ exports2.PLUGIN_EXECUTION_MAX_BYTES = 1024 * 1024;
11468
+ exports2.PLUGIN_EXECUTION_TIMEOUT_MS = 5 * 6e4;
11469
+ exports2.PREPARED_RUNTIME_MAX_BYTES = 256 * 1024 * 1024;
11470
+ exports2.PREPARED_RUNTIME_MAX_FILES = 5e4;
11471
+ exports2.PREPARED_RUNTIME_ARCHIVE = "octonode-runtime.tgz";
11472
+ }
11473
+ });
11474
+
11475
+ // packages/schema/dist/plugin/execution.js
11476
+ var require_execution = __commonJS({
11477
+ "packages/schema/dist/plugin/execution.js"(exports2) {
11478
+ "use strict";
11479
+ Object.defineProperty(exports2, "__esModule", { value: true });
11480
+ exports2.AuthorizedPluginRelease = exports2.PluginExecutionRequest = exports2.PluginExecutionReference = exports2.PreparedPluginRuntime = void 0;
11481
+ var zod_1 = require("zod");
11482
+ var ipc_envelope_1 = require_ipc_envelope();
11483
+ var plugin_1 = require_plugin();
11484
+ var execution_constants_1 = require_execution_constants();
11485
+ exports2.PreparedPluginRuntime = zod_1.z.object({
11486
+ format: zod_1.z.literal(1),
11487
+ nodeMajor: zod_1.z.literal(24),
11488
+ platform: zod_1.z.enum(["portable", "linux", "darwin"]),
11489
+ arch: zod_1.z.string().max(32).optional(),
11490
+ libc: zod_1.z.string().max(64).optional(),
11491
+ dependencies: zod_1.z.literal(execution_constants_1.PREPARED_RUNTIME_ARCHIVE).optional()
11492
+ }).strict();
11493
+ exports2.PluginExecutionReference = zod_1.z.object({
11494
+ installId: zod_1.z.string().uuid(),
11495
+ sha256: zod_1.z.string().regex(/^sha256:[a-f0-9]{64}$/),
11496
+ nodeId: zod_1.z.string().regex(/^[a-z0-9][a-z0-9_-]*$/i)
11497
+ }).strict();
11498
+ exports2.PluginExecutionRequest = zod_1.z.object({
11499
+ plugin: exports2.PluginExecutionReference,
11500
+ request: ipc_envelope_1.InvokeRequest,
11501
+ environment: zod_1.z.record(zod_1.z.string().regex(/^[a-z_][a-z0-9_]*$/i), zod_1.z.string().max(65536).refine((value) => !value.includes("\0"))).default({}),
11502
+ timeoutMs: zod_1.z.number().int().positive().max(execution_constants_1.PLUGIN_EXECUTION_TIMEOUT_MS).default(execution_constants_1.PLUGIN_EXECUTION_TIMEOUT_MS)
11503
+ }).strict();
11504
+ exports2.AuthorizedPluginRelease = zod_1.z.object({
11505
+ manifest: plugin_1.PluginManifest,
11506
+ archiveSha256: zod_1.z.string().regex(/^[a-f0-9]{64}$/)
11507
+ });
11508
+ }
11509
+ });
11510
+
11459
11511
  // packages/schema/dist/index.js
11460
11512
  var require_dist = __commonJS({
11461
11513
  "packages/schema/dist/index.js"(exports2) {
@@ -11518,6 +11570,8 @@ var require_dist = __commonJS({
11518
11570
  __exportStar(require_project_lifecycle(), exports2);
11519
11571
  __exportStar(require_project_jobs(), exports2);
11520
11572
  __exportStar(require_plugin_version(), exports2);
11573
+ __exportStar(require_execution(), exports2);
11574
+ __exportStar(require_execution_constants(), exports2);
11521
11575
  }
11522
11576
  });
11523
11577
 
@@ -11845,7 +11899,7 @@ var require_runner = __commonJS({
11845
11899
  let draining = false;
11846
11900
  let ended = false;
11847
11901
  let done;
11848
- const finished = new Promise((resolve5) => done = resolve5);
11902
+ const finished = new Promise((resolve7) => done = resolve7);
11849
11903
  const drain = async () => {
11850
11904
  if (draining)
11851
11905
  return;
@@ -11895,183 +11949,6 @@ var require_runner = __commonJS({
11895
11949
  }
11896
11950
  });
11897
11951
 
11898
- // packages/plugin-runtime/dist/plugin.js
11899
- var require_plugin2 = __commonJS({
11900
- "packages/plugin-runtime/dist/plugin.js"(exports2) {
11901
- "use strict";
11902
- Object.defineProperty(exports2, "__esModule", { value: true });
11903
- exports2.definePlugin = definePlugin;
11904
- exports2.startPlugin = startPlugin;
11905
- var schema_1 = require_dist();
11906
- var define_node_1 = require_define_node();
11907
- var runner_1 = require_runner();
11908
- function definePlugin(definition, handlers) {
11909
- const options = definition;
11910
- if (!handlers && (!options || !Array.isArray(options.nodes)))
11911
- throw new Error("plugin needs a nodes array");
11912
- if (!handlers) {
11913
- for (const node of options.nodes) {
11914
- if (typeof node.run !== "function")
11915
- throw new Error(`plugin node "${node.id}" needs a handler`);
11916
- if (node.kind && node.kind !== "function")
11917
- throw new Error("plugin nodes must be functions");
11918
- }
11919
- }
11920
- const manifest2 = schema_1.PluginManifest.parse(handlers ? definition : {
11921
- ...options,
11922
- nodes: options.nodes.map(({ run: _run, ...node }) => ({
11923
- ...node,
11924
- command: `node dist/index.js ${node.id}`,
11925
- language: "typescript"
11926
- }))
11927
- });
11928
- const nodeHandlers = handlers ?? Object.fromEntries(options.nodes.map((node) => [node.id, node.run]));
11929
- for (const node of manifest2.nodes) {
11930
- for (const field of ["inputs", "outputs", "defaults"]) {
11931
- const error = node[field] === void 0 ? void 0 : (0, runner_1.jsonSafetyError)(node[field]);
11932
- if (error)
11933
- throw new Error(`plugin node "${node.id}" ${field} must be JSON-serializable: ${error}`);
11934
- }
11935
- }
11936
- for (const id of Object.keys(nodeHandlers)) {
11937
- if (!manifest2.nodes.some((node) => node.id === id))
11938
- throw new Error(`handler "${id}" has no plugin node`);
11939
- }
11940
- return {
11941
- manifest: manifest2,
11942
- ...!handlers && options.assets ? { assets: options.assets } : {},
11943
- nodes: Object.fromEntries(manifest2.nodes.map((node) => {
11944
- if (!Object.hasOwn(nodeHandlers, node.id))
11945
- throw new Error(`plugin node "${node.id}" needs a handler`);
11946
- const fields = (node.connections ?? []).flatMap((id) => Object.entries(manifest2.connections?.[id]?.fields ?? {}));
11947
- return [
11948
- node.id,
11949
- (0, define_node_1.defineNode)({
11950
- ...node,
11951
- run: (inputs, context) => {
11952
- const missing = fields.filter(([name, field]) => field.required && !process.env[name]).map(([name]) => name);
11953
- if (missing.length)
11954
- throw new runner_1.NodeError(`Missing connection credentials: ${missing.join(", ")}`);
11955
- return nodeHandlers[node.id](inputs, context);
11956
- }
11957
- })
11958
- ];
11959
- }))
11960
- };
11961
- }
11962
- function startPlugin(plugin, nodeId = process.argv[2]) {
11963
- const id = nodeId ?? (plugin.manifest.nodes.length === 1 ? plugin.manifest.nodes[0].id : void 0);
11964
- if (!id || !Object.hasOwn(plugin.nodes, id))
11965
- throw new Error(`Choose a plugin node: ${Object.keys(plugin.nodes).join(", ")}`);
11966
- (0, runner_1.start)(plugin.nodes[id]);
11967
- }
11968
- }
11969
- });
11970
-
11971
- // packages/plugin-runtime/dist/plugin-file.js
11972
- var require_plugin_file = __commonJS({
11973
- "packages/plugin-runtime/dist/plugin-file.js"(exports2) {
11974
- "use strict";
11975
- Object.defineProperty(exports2, "__esModule", { value: true });
11976
- exports2.pluginDefinitionPath = pluginDefinitionPath;
11977
- exports2.loadPluginDefinition = loadPluginDefinition3;
11978
- var node_fs_1 = require("node:fs");
11979
- var node_path_1 = require("node:path");
11980
- var yaml_1 = require("yaml");
11981
- var schema_1 = require_dist();
11982
- function pluginDefinitionPath(dir) {
11983
- const files = schema_1.PLUGIN_DEFINITION_FILENAMES.map((name) => (0, node_path_1.join)(dir, name)).filter(node_fs_1.existsSync);
11984
- if (files.length !== 1)
11985
- throw new Error(files.length ? `Multiple plugin definitions in ${dir}; keep exactly one` : `No plugin definition in ${dir}; create octonode.yml or octonode.json`);
11986
- const file = files[0];
11987
- if ((0, node_path_1.dirname)((0, node_fs_1.realpathSync)(file)) !== (0, node_fs_1.realpathSync)(dir))
11988
- throw new Error("Plugin definition must stay inside its folder");
11989
- if (!(0, node_fs_1.statSync)(file).isFile() || (0, node_fs_1.statSync)(file).size > 1048576)
11990
- throw new Error("Plugin definition must be a file smaller than 1 MiB");
11991
- return file;
11992
- }
11993
- function loadPluginDefinition3(dir) {
11994
- const file = pluginDefinitionPath(dir);
11995
- const source = (0, node_fs_1.readFileSync)(file, "utf8");
11996
- const document = (0, yaml_1.parseDocument)(source, { version: "1.2", uniqueKeys: true });
11997
- (0, yaml_1.visit)(document, {
11998
- Alias() {
11999
- throw new Error("Plugin definitions cannot contain YAML aliases");
12000
- }
12001
- });
12002
- if (document.errors.length || document.warnings.length)
12003
- throw new Error(`${file}: ${[...document.errors, ...document.warnings].map((error) => error.message).join("; ")}`);
12004
- const raw = file.endsWith(".json") ? JSON.parse(source) : document.toJS({ maxAliasCount: 0 });
12005
- if (file.endsWith(schema_1.PLUGIN_MANIFEST_FILENAME))
12006
- return schema_1.PluginManifest.parse(raw);
12007
- const settings = schema_1.OctonodeSettingsDocument.parse(raw);
12008
- if (!settings.plugin)
12009
- throw new Error(`${file} has no plugin section`);
12010
- return settings.plugin;
12011
- }
12012
- }
12013
- });
12014
-
12015
- // packages/plugin-runtime/dist/index.js
12016
- var require_dist2 = __commonJS({
12017
- "packages/plugin-runtime/dist/index.js"(exports2) {
12018
- "use strict";
12019
- Object.defineProperty(exports2, "__esModule", { value: true });
12020
- exports2.PluginConnection = exports2.PluginNode = exports2.PluginManifest = exports2.pluginDefinitionPath = exports2.loadPluginDefinition = exports2.startPlugin = exports2.definePlugin = exports2.validate = exports2.NodeError = exports2.start = exports2.runNode = exports2.defineConst = exports2.defineClass = exports2.defineService = exports2.defineNode = void 0;
12021
- var define_node_1 = require_define_node();
12022
- Object.defineProperty(exports2, "defineNode", { enumerable: true, get: function() {
12023
- return define_node_1.defineNode;
12024
- } });
12025
- Object.defineProperty(exports2, "defineService", { enumerable: true, get: function() {
12026
- return define_node_1.defineService;
12027
- } });
12028
- Object.defineProperty(exports2, "defineClass", { enumerable: true, get: function() {
12029
- return define_node_1.defineClass;
12030
- } });
12031
- Object.defineProperty(exports2, "defineConst", { enumerable: true, get: function() {
12032
- return define_node_1.defineConst;
12033
- } });
12034
- var runner_1 = require_runner();
12035
- Object.defineProperty(exports2, "runNode", { enumerable: true, get: function() {
12036
- return runner_1.runNode;
12037
- } });
12038
- Object.defineProperty(exports2, "start", { enumerable: true, get: function() {
12039
- return runner_1.start;
12040
- } });
12041
- Object.defineProperty(exports2, "NodeError", { enumerable: true, get: function() {
12042
- return runner_1.NodeError;
12043
- } });
12044
- var json_schema_1 = require_json_schema2();
12045
- Object.defineProperty(exports2, "validate", { enumerable: true, get: function() {
12046
- return json_schema_1.validate;
12047
- } });
12048
- var plugin_1 = require_plugin2();
12049
- Object.defineProperty(exports2, "definePlugin", { enumerable: true, get: function() {
12050
- return plugin_1.definePlugin;
12051
- } });
12052
- Object.defineProperty(exports2, "startPlugin", { enumerable: true, get: function() {
12053
- return plugin_1.startPlugin;
12054
- } });
12055
- var plugin_file_1 = require_plugin_file();
12056
- Object.defineProperty(exports2, "loadPluginDefinition", { enumerable: true, get: function() {
12057
- return plugin_file_1.loadPluginDefinition;
12058
- } });
12059
- Object.defineProperty(exports2, "pluginDefinitionPath", { enumerable: true, get: function() {
12060
- return plugin_file_1.pluginDefinitionPath;
12061
- } });
12062
- var schema_1 = require_dist();
12063
- Object.defineProperty(exports2, "PluginManifest", { enumerable: true, get: function() {
12064
- return schema_1.PluginManifest;
12065
- } });
12066
- Object.defineProperty(exports2, "PluginNode", { enumerable: true, get: function() {
12067
- return schema_1.PluginNode;
12068
- } });
12069
- Object.defineProperty(exports2, "PluginConnection", { enumerable: true, get: function() {
12070
- return schema_1.PluginConnection;
12071
- } });
12072
- }
12073
- });
12074
-
12075
11952
  // packages/common/dist/constants.js
12076
11953
  var require_constants2 = __commonJS({
12077
11954
  "packages/common/dist/constants.js"(exports2) {
@@ -12089,8 +11966,8 @@ var require_constants2 = __commonJS({
12089
11966
  return environment;
12090
11967
  };
12091
11968
  exports2.workflowEnvironment = workflowEnvironment;
12092
- var childProcessEnvironment3 = (overrides = {}) => (0, exports2.workflowEnvironment)({ ...exports2.PROCESS_ENV, ...overrides });
12093
- exports2.childProcessEnvironment = childProcessEnvironment3;
11969
+ var childProcessEnvironment4 = (overrides = {}) => (0, exports2.workflowEnvironment)({ ...exports2.PROCESS_ENV, ...overrides });
11970
+ exports2.childProcessEnvironment = childProcessEnvironment4;
12094
11971
  var setEnvironmentVariable = (name, value) => {
12095
11972
  if (value === void 0)
12096
11973
  delete exports2.PROCESS_ENV[name];
@@ -12132,8 +12009,8 @@ var require_constants2 = __commonJS({
12132
12009
  exports2.OCTONODE_PACKAGE_CACHE = OCTONODE_PACKAGE_CACHE2;
12133
12010
  var OCTONODE_MARKETPLACE_TOKEN2 = () => exports2.PROCESS_ENV.OCTONODE_MARKETPLACE_TOKEN ?? exports2.PROCESS_ENV.VITE_OCTONODE_MARKETPLACE_TOKEN ?? exports2.PROCESS_ENV.VITE_PUBLIC_OCTONODE_MARKETPLACE_TOKEN;
12134
12011
  exports2.OCTONODE_MARKETPLACE_TOKEN = OCTONODE_MARKETPLACE_TOKEN2;
12135
- var OCTONODE_MARKETPLACE_URL2 = () => exports2.PROCESS_ENV.OCTONODE_MARKETPLACE_URL ?? exports2.PROCESS_ENV.VITE_OCTONODE_MARKETPLACE_URL ?? exports2.PROCESS_ENV.VITE_PUBLIC_OCTONODE_MARKETPLACE_URL;
12136
- exports2.OCTONODE_MARKETPLACE_URL = OCTONODE_MARKETPLACE_URL2;
12012
+ var OCTONODE_MARKETPLACE_URL3 = () => exports2.PROCESS_ENV.OCTONODE_MARKETPLACE_URL ?? exports2.PROCESS_ENV.VITE_OCTONODE_MARKETPLACE_URL ?? exports2.PROCESS_ENV.VITE_PUBLIC_OCTONODE_MARKETPLACE_URL;
12013
+ exports2.OCTONODE_MARKETPLACE_URL = OCTONODE_MARKETPLACE_URL3;
12137
12014
  var OCTONODE_RUN_CONCURRENCY = () => exports2.PROCESS_ENV.OCTONODE_RUN_CONCURRENCY;
12138
12015
  exports2.OCTONODE_RUN_CONCURRENCY = OCTONODE_RUN_CONCURRENCY;
12139
12016
  var OCTONODE_RUN_QUEUE = () => exports2.PROCESS_ENV.OCTONODE_RUN_QUEUE;
@@ -12391,38 +12268,248 @@ var require_graph_layout = __commonJS({
12391
12268
  }
12392
12269
  });
12393
12270
 
12394
- // packages/common/dist/index.js
12271
+ // packages/common/dist/plugin-nodes.js
12272
+ var require_plugin_nodes = __commonJS({
12273
+ "packages/common/dist/plugin-nodes.js"(exports2) {
12274
+ "use strict";
12275
+ Object.defineProperty(exports2, "__esModule", { value: true });
12276
+ exports2.installedPluginNodesPage = installedPluginNodesPage;
12277
+ function isCatalogPlugin(value) {
12278
+ if (!value || typeof value !== "object")
12279
+ return false;
12280
+ const plugin = value;
12281
+ return typeof plugin.id === "string" && typeof plugin.name === "string" && typeof plugin.version === "string" && Array.isArray(plugin.nodes) && plugin.nodes.every((node) => {
12282
+ if (!node || typeof node !== "object")
12283
+ return false;
12284
+ const item = node;
12285
+ return typeof item.id === "string" && (item.icon === void 0 || typeof item.icon === "string") && (item.description === void 0 || typeof item.description === "string");
12286
+ });
12287
+ }
12288
+ function installedPluginNodesPage(inventory, query) {
12289
+ if (!inventory.every(isCatalogPlugin))
12290
+ throw new Error("Plugin node inventory is incomplete");
12291
+ const q = query.q?.trim().toLowerCase();
12292
+ const nodes = inventory.flatMap((plugin) => plugin.nodes.filter((node) => !q || [node.id, node.description ?? "", plugin.id, plugin.name].join(" ").toLowerCase().includes(q)).map((node) => ({ ...node, pluginId: plugin.id, pluginName: plugin.name, pluginVersion: plugin.version }))).sort((a, b) => a.pluginName.localeCompare(b.pluginName) || a.id.localeCompare(b.id));
12293
+ const offset = Math.min(query.offset, nodes.length);
12294
+ return { items: nodes.slice(offset, offset + query.limit), total: nodes.length, offset, limit: query.limit };
12295
+ }
12296
+ }
12297
+ });
12298
+
12299
+ // packages/common/dist/index.js
12300
+ var require_dist2 = __commonJS({
12301
+ "packages/common/dist/index.js"(exports2) {
12302
+ "use strict";
12303
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {
12304
+ if (k2 === void 0) k2 = k;
12305
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12306
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12307
+ desc = { enumerable: true, get: function() {
12308
+ return m[k];
12309
+ } };
12310
+ }
12311
+ Object.defineProperty(o, k2, desc);
12312
+ }) : (function(o, m, k, k2) {
12313
+ if (k2 === void 0) k2 = k;
12314
+ o[k2] = m[k];
12315
+ }));
12316
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
12317
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
12318
+ };
12319
+ Object.defineProperty(exports2, "__esModule", { value: true });
12320
+ exports2.installedPluginNodesPage = exports2.layeredLayout = exports2.packageCacheEnvironment = void 0;
12321
+ __exportStar(require_constants2(), exports2);
12322
+ __exportStar(require_legal_constants(), exports2);
12323
+ var package_cache_1 = require_package_cache();
12324
+ Object.defineProperty(exports2, "packageCacheEnvironment", { enumerable: true, get: function() {
12325
+ return package_cache_1.packageCacheEnvironment;
12326
+ } });
12327
+ __exportStar(require_api_exposure(), exports2);
12328
+ var graph_layout_1 = require_graph_layout();
12329
+ Object.defineProperty(exports2, "layeredLayout", { enumerable: true, get: function() {
12330
+ return graph_layout_1.layeredLayout;
12331
+ } });
12332
+ var plugin_nodes_1 = require_plugin_nodes();
12333
+ Object.defineProperty(exports2, "installedPluginNodesPage", { enumerable: true, get: function() {
12334
+ return plugin_nodes_1.installedPluginNodesPage;
12335
+ } });
12336
+ }
12337
+ });
12338
+
12339
+ // packages/plugin-runtime/dist/plugin.js
12340
+ var require_plugin2 = __commonJS({
12341
+ "packages/plugin-runtime/dist/plugin.js"(exports2) {
12342
+ "use strict";
12343
+ Object.defineProperty(exports2, "__esModule", { value: true });
12344
+ exports2.definePlugin = definePlugin;
12345
+ exports2.startPlugin = startPlugin;
12346
+ var common_1 = require_dist2();
12347
+ var schema_1 = require_dist();
12348
+ var define_node_1 = require_define_node();
12349
+ var runner_1 = require_runner();
12350
+ function definePlugin(definition, handlers) {
12351
+ const options = definition;
12352
+ if (!handlers && (!options || !Array.isArray(options.nodes)))
12353
+ throw new Error("plugin needs a nodes array");
12354
+ if (!handlers) {
12355
+ for (const node of options.nodes) {
12356
+ if (typeof node.run !== "function")
12357
+ throw new Error(`plugin node "${node.id}" needs a handler`);
12358
+ if (node.kind && node.kind !== "function")
12359
+ throw new Error("plugin nodes must be functions");
12360
+ }
12361
+ }
12362
+ const manifest2 = schema_1.PluginManifest.parse(handlers ? definition : {
12363
+ ...options,
12364
+ nodes: options.nodes.map(({ run: _run, ...node }) => ({
12365
+ ...node,
12366
+ command: `node dist/index.js ${node.id}`,
12367
+ language: "typescript"
12368
+ }))
12369
+ });
12370
+ const nodeHandlers = handlers ?? Object.fromEntries(options.nodes.map((node) => [node.id, node.run]));
12371
+ for (const node of manifest2.nodes) {
12372
+ for (const field of ["inputs", "outputs", "defaults"]) {
12373
+ const error = node[field] === void 0 ? void 0 : (0, runner_1.jsonSafetyError)(node[field]);
12374
+ if (error)
12375
+ throw new Error(`plugin node "${node.id}" ${field} must be JSON-serializable: ${error}`);
12376
+ }
12377
+ }
12378
+ for (const id of Object.keys(nodeHandlers)) {
12379
+ if (!manifest2.nodes.some((node) => node.id === id))
12380
+ throw new Error(`handler "${id}" has no plugin node`);
12381
+ }
12382
+ return {
12383
+ manifest: manifest2,
12384
+ ...!handlers && options.assets ? { assets: options.assets } : {},
12385
+ nodes: Object.fromEntries(manifest2.nodes.map((node) => {
12386
+ if (!Object.hasOwn(nodeHandlers, node.id))
12387
+ throw new Error(`plugin node "${node.id}" needs a handler`);
12388
+ const fields = (node.connections ?? []).flatMap((id) => Object.entries(manifest2.connections?.[id]?.fields ?? {}));
12389
+ return [
12390
+ node.id,
12391
+ (0, define_node_1.defineNode)({
12392
+ ...node,
12393
+ run: (inputs, context) => {
12394
+ const missing = fields.filter(([name, field]) => field.required && !common_1.PROCESS_ENV[name]).map(([name]) => name);
12395
+ if (missing.length)
12396
+ throw new runner_1.NodeError(`Missing connection credentials: ${missing.join(", ")}`);
12397
+ return nodeHandlers[node.id](inputs, context);
12398
+ }
12399
+ })
12400
+ ];
12401
+ }))
12402
+ };
12403
+ }
12404
+ function startPlugin(plugin, nodeId = process.argv[2]) {
12405
+ const id = nodeId ?? (plugin.manifest.nodes.length === 1 ? plugin.manifest.nodes[0].id : void 0);
12406
+ if (!id || !Object.hasOwn(plugin.nodes, id))
12407
+ throw new Error(`Choose a plugin node: ${Object.keys(plugin.nodes).join(", ")}`);
12408
+ (0, runner_1.start)(plugin.nodes[id]);
12409
+ }
12410
+ }
12411
+ });
12412
+
12413
+ // packages/plugin-runtime/dist/plugin-file.js
12414
+ var require_plugin_file = __commonJS({
12415
+ "packages/plugin-runtime/dist/plugin-file.js"(exports2) {
12416
+ "use strict";
12417
+ Object.defineProperty(exports2, "__esModule", { value: true });
12418
+ exports2.pluginDefinitionPath = pluginDefinitionPath2;
12419
+ exports2.loadPluginDefinition = loadPluginDefinition3;
12420
+ var node_fs_1 = require("node:fs");
12421
+ var node_path_1 = require("node:path");
12422
+ var yaml_1 = require("yaml");
12423
+ var schema_1 = require_dist();
12424
+ function pluginDefinitionPath2(dir) {
12425
+ const files = schema_1.PLUGIN_DEFINITION_FILENAMES.map((name) => (0, node_path_1.join)(dir, name)).filter(node_fs_1.existsSync);
12426
+ if (files.length !== 1)
12427
+ throw new Error(files.length ? `Multiple plugin definitions in ${dir}; keep exactly one` : `No plugin definition in ${dir}; create octonode.yml or octonode.json`);
12428
+ const file = files[0];
12429
+ if ((0, node_path_1.dirname)((0, node_fs_1.realpathSync)(file)) !== (0, node_fs_1.realpathSync)(dir))
12430
+ throw new Error("Plugin definition must stay inside its folder");
12431
+ if (!(0, node_fs_1.statSync)(file).isFile() || (0, node_fs_1.statSync)(file).size > 1048576)
12432
+ throw new Error("Plugin definition must be a file smaller than 1 MiB");
12433
+ return file;
12434
+ }
12435
+ function loadPluginDefinition3(dir) {
12436
+ const file = pluginDefinitionPath2(dir);
12437
+ const source = (0, node_fs_1.readFileSync)(file, "utf8");
12438
+ const document = (0, yaml_1.parseDocument)(source, { version: "1.2", uniqueKeys: true });
12439
+ (0, yaml_1.visit)(document, {
12440
+ Alias() {
12441
+ throw new Error("Plugin definitions cannot contain YAML aliases");
12442
+ }
12443
+ });
12444
+ if (document.errors.length || document.warnings.length)
12445
+ throw new Error(`${file}: ${[...document.errors, ...document.warnings].map((error) => error.message).join("; ")}`);
12446
+ const raw = file.endsWith(".json") ? JSON.parse(source) : document.toJS({ maxAliasCount: 0 });
12447
+ if (file.endsWith(schema_1.PLUGIN_MANIFEST_FILENAME))
12448
+ return schema_1.PluginManifest.parse(raw);
12449
+ const settings = schema_1.OctonodeSettingsDocument.parse(raw);
12450
+ if (!settings.plugin)
12451
+ throw new Error(`${file} has no plugin section`);
12452
+ return settings.plugin;
12453
+ }
12454
+ }
12455
+ });
12456
+
12457
+ // packages/plugin-runtime/dist/index.js
12395
12458
  var require_dist3 = __commonJS({
12396
- "packages/common/dist/index.js"(exports2) {
12459
+ "packages/plugin-runtime/dist/index.js"(exports2) {
12397
12460
  "use strict";
12398
- var __createBinding = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {
12399
- if (k2 === void 0) k2 = k;
12400
- var desc = Object.getOwnPropertyDescriptor(m, k);
12401
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12402
- desc = { enumerable: true, get: function() {
12403
- return m[k];
12404
- } };
12405
- }
12406
- Object.defineProperty(o, k2, desc);
12407
- }) : (function(o, m, k, k2) {
12408
- if (k2 === void 0) k2 = k;
12409
- o[k2] = m[k];
12410
- }));
12411
- var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
12412
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
12413
- };
12414
12461
  Object.defineProperty(exports2, "__esModule", { value: true });
12415
- exports2.layeredLayout = exports2.packageCacheEnvironment = void 0;
12416
- __exportStar(require_constants2(), exports2);
12417
- __exportStar(require_legal_constants(), exports2);
12418
- var package_cache_1 = require_package_cache();
12419
- Object.defineProperty(exports2, "packageCacheEnvironment", { enumerable: true, get: function() {
12420
- return package_cache_1.packageCacheEnvironment;
12462
+ exports2.PluginConnection = exports2.PluginNode = exports2.PluginManifest = exports2.pluginDefinitionPath = exports2.loadPluginDefinition = exports2.startPlugin = exports2.definePlugin = exports2.validate = exports2.NodeError = exports2.start = exports2.runNode = exports2.defineConst = exports2.defineClass = exports2.defineService = exports2.defineNode = void 0;
12463
+ var define_node_1 = require_define_node();
12464
+ Object.defineProperty(exports2, "defineNode", { enumerable: true, get: function() {
12465
+ return define_node_1.defineNode;
12421
12466
  } });
12422
- __exportStar(require_api_exposure(), exports2);
12423
- var graph_layout_1 = require_graph_layout();
12424
- Object.defineProperty(exports2, "layeredLayout", { enumerable: true, get: function() {
12425
- return graph_layout_1.layeredLayout;
12467
+ Object.defineProperty(exports2, "defineService", { enumerable: true, get: function() {
12468
+ return define_node_1.defineService;
12469
+ } });
12470
+ Object.defineProperty(exports2, "defineClass", { enumerable: true, get: function() {
12471
+ return define_node_1.defineClass;
12472
+ } });
12473
+ Object.defineProperty(exports2, "defineConst", { enumerable: true, get: function() {
12474
+ return define_node_1.defineConst;
12475
+ } });
12476
+ var runner_1 = require_runner();
12477
+ Object.defineProperty(exports2, "runNode", { enumerable: true, get: function() {
12478
+ return runner_1.runNode;
12479
+ } });
12480
+ Object.defineProperty(exports2, "start", { enumerable: true, get: function() {
12481
+ return runner_1.start;
12482
+ } });
12483
+ Object.defineProperty(exports2, "NodeError", { enumerable: true, get: function() {
12484
+ return runner_1.NodeError;
12485
+ } });
12486
+ var json_schema_1 = require_json_schema2();
12487
+ Object.defineProperty(exports2, "validate", { enumerable: true, get: function() {
12488
+ return json_schema_1.validate;
12489
+ } });
12490
+ var plugin_1 = require_plugin2();
12491
+ Object.defineProperty(exports2, "definePlugin", { enumerable: true, get: function() {
12492
+ return plugin_1.definePlugin;
12493
+ } });
12494
+ Object.defineProperty(exports2, "startPlugin", { enumerable: true, get: function() {
12495
+ return plugin_1.startPlugin;
12496
+ } });
12497
+ var plugin_file_1 = require_plugin_file();
12498
+ Object.defineProperty(exports2, "loadPluginDefinition", { enumerable: true, get: function() {
12499
+ return plugin_file_1.loadPluginDefinition;
12500
+ } });
12501
+ Object.defineProperty(exports2, "pluginDefinitionPath", { enumerable: true, get: function() {
12502
+ return plugin_file_1.pluginDefinitionPath;
12503
+ } });
12504
+ var schema_1 = require_dist();
12505
+ Object.defineProperty(exports2, "PluginManifest", { enumerable: true, get: function() {
12506
+ return schema_1.PluginManifest;
12507
+ } });
12508
+ Object.defineProperty(exports2, "PluginNode", { enumerable: true, get: function() {
12509
+ return schema_1.PluginNode;
12510
+ } });
12511
+ Object.defineProperty(exports2, "PluginConnection", { enumerable: true, get: function() {
12512
+ return schema_1.PluginConnection;
12426
12513
  } });
12427
12514
  }
12428
12515
  });
@@ -12435,18 +12522,18 @@ __export(index_exports, {
12435
12522
  module.exports = __toCommonJS(index_exports);
12436
12523
 
12437
12524
  // packages/plugin/src/consumer/lifecycle.ts
12438
- var import_node_fs13 = require("node:fs");
12439
- var import_node_path13 = require("node:path");
12525
+ var import_node_fs15 = require("node:fs");
12526
+ var import_node_path15 = require("node:path");
12440
12527
 
12441
12528
  // packages/plugin/src/lifecycle.ts
12442
- var import_node_fs8 = require("node:fs");
12443
- var import_node_path8 = require("node:path");
12529
+ var import_node_fs10 = require("node:fs");
12530
+ var import_node_path10 = require("node:path");
12444
12531
 
12445
12532
  // packages/plugin/src/store.ts
12446
12533
  var import_node_fs2 = require("node:fs");
12447
12534
  var import_node_os = require("node:os");
12448
12535
  var import_node_path2 = require("node:path");
12449
- var import_plugin_runtime = __toESM(require_dist2());
12536
+ var import_plugin_runtime = __toESM(require_dist3());
12450
12537
 
12451
12538
  // packages/plugin/src/integrity.ts
12452
12539
  var import_node_crypto = require("node:crypto");
@@ -12538,7 +12625,7 @@ function addToStore(srcDir, opts = {}) {
12538
12625
  var import_node_fs4 = require("node:fs");
12539
12626
  var import_node_os2 = require("node:os");
12540
12627
  var import_node_path4 = require("node:path");
12541
- var import_plugin_runtime2 = __toESM(require_dist2());
12628
+ var import_plugin_runtime2 = __toESM(require_dist3());
12542
12629
  var import_schema2 = __toESM(require_dist());
12543
12630
 
12544
12631
  // packages/plugin/src/lock.ts
@@ -12551,6 +12638,8 @@ var LockEntry = import_zod.z.object({
12551
12638
  version: import_zod.z.string(),
12552
12639
  /** `sha256:<hex>` dir-content hash (hashPluginDir) — the store address + integrity check. */
12553
12640
  sha256: import_zod.z.string(),
12641
+ /** Registry archive checksum, distinct from the unpacked file-tree identity. */
12642
+ archiveSha256: import_zod.z.string().regex(/^[a-f0-9]{64}$/).optional(),
12554
12643
  /** Marketplace base URL the bundle came from (absent for local installs). */
12555
12644
  registry: import_zod.z.string().optional(),
12556
12645
  /** Marketplace tier it was resolved from. */
@@ -12625,12 +12714,12 @@ function isPluginDir(dir) {
12625
12714
 
12626
12715
  // packages/plugin/src/dependencies.ts
12627
12716
  var import_node_child_process = require("node:child_process");
12628
- var import_node_fs5 = require("node:fs");
12629
- var import_node_os3 = require("node:os");
12630
- var import_node_path5 = require("node:path");
12717
+ var import_node_fs6 = require("node:fs");
12718
+ var import_node_os4 = require("node:os");
12719
+ var import_node_path6 = require("node:path");
12631
12720
  var import_node_util = require("node:util");
12632
12721
  var import_yaml = require("yaml");
12633
- var import_common = __toESM(require_dist3());
12722
+ var import_common = __toESM(require_dist2());
12634
12723
 
12635
12724
  // packages/plugin/src/dependencies.constants.ts
12636
12725
  var DEFAULT_PACKAGE_MANAGER = "pnpm@12.3.4";
@@ -12644,43 +12733,291 @@ var PACKAGE_MANAGER_LOCKS = {
12644
12733
  bun: ["bun.lock", "bun.lockb"]
12645
12734
  };
12646
12735
 
12736
+ // packages/plugin/src/dependency/snapshot.ts
12737
+ var import_node_crypto2 = require("node:crypto");
12738
+ var import_node_fs5 = require("node:fs");
12739
+ var import_node_path5 = require("node:path");
12740
+ var import_node_os3 = require("node:os");
12741
+ var import_zod2 = require("zod");
12742
+
12743
+ // packages/plugin/src/dependency/snapshot.constants.ts
12744
+ var DEPENDENCY_SNAPSHOT_FORMAT = 1;
12745
+ var DEPENDENCY_SNAPSHOT_MAX_BYTES = 256 * 1024 * 1024;
12746
+ var DEPENDENCY_SNAPSHOT_MAX_FILES = 5e4;
12747
+ var DEPENDENCY_SNAPSHOT_OUTPUTS = [
12748
+ "node_modules",
12749
+ ".pnp.cjs",
12750
+ ".pnp.loader.mjs",
12751
+ ".pnp.data.json",
12752
+ ".yarn/cache",
12753
+ ".yarn/unplugged",
12754
+ ".yarn/install-state.gz"
12755
+ ];
12756
+
12757
+ // packages/plugin/src/dependency/snapshot.ts
12758
+ function inside(root, path) {
12759
+ const local = (0, import_node_path5.relative)(root, path);
12760
+ return local === "" || !(0, import_node_path5.isAbsolute)(local) && local !== ".." && !local.startsWith(`..${import_node_path5.sep}`);
12761
+ }
12762
+ function digestTree(root, paths, projectRoot) {
12763
+ const hash = (0, import_node_crypto2.createHash)("sha256");
12764
+ let bytes = 0;
12765
+ let count = 0;
12766
+ const visit2 = (path) => {
12767
+ if (++count > DEPENDENCY_SNAPSHOT_MAX_FILES) throw new Error("Dependency snapshot file limit");
12768
+ const file = (0, import_node_path5.join)(root, path);
12769
+ for (let parent = (0, import_node_path5.dirname)(file); inside(root, parent); parent = (0, import_node_path5.dirname)(parent)) {
12770
+ if ((0, import_node_fs5.lstatSync)(parent).isSymbolicLink()) throw new Error("Dependency snapshot ancestor is a link");
12771
+ if (parent === root) break;
12772
+ }
12773
+ const stat = (0, import_node_fs5.lstatSync)(file);
12774
+ hash.update(
12775
+ JSON.stringify([
12776
+ path,
12777
+ stat.mode & 511,
12778
+ stat.isDirectory() ? "directory" : stat.isSymbolicLink() ? "link" : "file"
12779
+ ])
12780
+ );
12781
+ if (stat.isSymbolicLink()) {
12782
+ const link = (0, import_node_fs5.readlinkSync)(file);
12783
+ if (!inside(projectRoot, (0, import_node_path5.resolve)((0, import_node_path5.dirname)((0, import_node_path5.join)(projectRoot, path)), link)))
12784
+ throw new Error("Dependency snapshot link leaves project");
12785
+ hash.update(JSON.stringify(link));
12786
+ } else if (stat.isDirectory()) {
12787
+ for (const name of (0, import_node_fs5.readdirSync)(file).sort()) visit2((0, import_node_path5.join)(path, name));
12788
+ } else if (stat.isFile()) {
12789
+ bytes += stat.size;
12790
+ if (bytes > DEPENDENCY_SNAPSHOT_MAX_BYTES) throw new Error("Dependency snapshot size limit");
12791
+ hash.update(String(stat.size)).update("\0").update((0, import_node_fs5.readFileSync)(file));
12792
+ } else throw new Error("Unsupported dependency snapshot file");
12793
+ };
12794
+ for (const path of [...paths].sort()) visit2(path);
12795
+ return hash.digest("hex");
12796
+ }
12797
+ function dependencySnapshot(project, cacheRoot, managerVersion, environment) {
12798
+ try {
12799
+ if (inside(cacheRoot, project.root)) return;
12800
+ if (!PACKAGE_MANAGER_LOCKS[project.manager].some((name) => (0, import_node_fs5.existsSync)((0, import_node_path5.join)(project.root, name)))) return;
12801
+ const outputs = new Set(DEPENDENCY_SNAPSHOT_OUTPUTS);
12802
+ let inputCount = 0;
12803
+ if (/--(?:require|import|loader|experimental-loader)(?:[=\s]|$)/.test(environment.NODE_OPTIONS ?? "")) return;
12804
+ const walk = (directory) => (0, import_node_fs5.readdirSync)(directory).sort().flatMap((name) => {
12805
+ const file = (0, import_node_path5.join)(directory, name);
12806
+ const local = (0, import_node_path5.relative)(project.root, file);
12807
+ if (inside(cacheRoot, file) || outputs.has(local) || name === "node_modules" || name === ".git" || name === ".octonode" || name === DEPENDENCY_MUTEX || name.startsWith(".octonode-recovery-"))
12808
+ return [];
12809
+ if (++inputCount > DEPENDENCY_SNAPSHOT_MAX_FILES) throw new Error("Dependency input file limit");
12810
+ const stat = (0, import_node_fs5.lstatSync)(file);
12811
+ if (stat.isSymbolicLink()) throw new Error("Linked source is not snapshot eligible");
12812
+ if (/^\.?pnpmfile\.[cm]?js$/.test(name))
12813
+ throw new Error("Dynamic package-manager hooks require installation");
12814
+ if (name === ".yarnrc.yml" && /^(?:plugins|yarnPath):/m.test((0, import_node_fs5.readFileSync)(file, "utf8")))
12815
+ throw new Error("Custom Yarn code requires installation");
12816
+ if (stat.isDirectory()) return walk(file);
12817
+ else {
12818
+ if (name === "package.json") {
12819
+ const manifest2 = JSON.parse((0, import_node_fs5.readFileSync)(file, "utf8"));
12820
+ for (const dependencies of [
12821
+ manifest2.dependencies,
12822
+ manifest2.devDependencies,
12823
+ manifest2.optionalDependencies
12824
+ ]) {
12825
+ for (const spec of Object.values(dependencies ?? {})) {
12826
+ if (typeof spec !== "string") throw new Error("Invalid dependency");
12827
+ const localSpec = /^(?:file:|link:|portal:)(.*)$/.exec(spec);
12828
+ if (localSpec) {
12829
+ const target = (0, import_node_path5.resolve)(directory, localSpec[1]);
12830
+ if (!inside(project.root, target) || inside(cacheRoot, target) || (0, import_node_path5.relative)(project.root, target).split(import_node_path5.sep).some((part) => ["node_modules", ".git", ".octonode"].includes(part)))
12831
+ throw new Error("External or excluded dependency is not snapshot eligible");
12832
+ }
12833
+ }
12834
+ }
12835
+ outputs.add((0, import_node_path5.relative)(project.root, (0, import_node_path5.join)(directory, "node_modules")));
12836
+ }
12837
+ return [local];
12838
+ }
12839
+ });
12840
+ const inputs = walk(project.root);
12841
+ const inputHash = digestTree(project.root, inputs, project.root);
12842
+ const userRoot = environment.HOME ?? (0, import_node_os3.homedir)();
12843
+ const configuration = new Set(
12844
+ [
12845
+ (0, import_node_path5.join)(userRoot, ".npmrc"),
12846
+ (0, import_node_path5.join)(userRoot, ".yarnrc"),
12847
+ (0, import_node_path5.join)(userRoot, ".yarnrc.yml"),
12848
+ (0, import_node_path5.join)(userRoot, ".config/pnpm/rc"),
12849
+ "/etc/npmrc",
12850
+ "/usr/local/etc/npmrc",
12851
+ environment.npm_config_userconfig,
12852
+ environment.NPM_CONFIG_USERCONFIG,
12853
+ environment.npm_config_globalconfig,
12854
+ environment.NPM_CONFIG_GLOBALCONFIG
12855
+ ].filter((path) => !!path)
12856
+ );
12857
+ for (let cursor = (0, import_node_path5.dirname)(project.root); ; cursor = (0, import_node_path5.dirname)(cursor)) {
12858
+ for (const name of [".npmrc", ".yarnrc", ".yarnrc.yml"]) configuration.add((0, import_node_path5.join)(cursor, name));
12859
+ if (cursor === (0, import_node_path5.dirname)(cursor)) break;
12860
+ }
12861
+ const configHash = [...configuration].sort().map((file) => {
12862
+ if (!(0, import_node_fs5.existsSync)(file)) return [file, null];
12863
+ if (/(?:yarnPath|plugins|pnpmfile)/.test((0, import_node_fs5.readFileSync)(file, "utf8")))
12864
+ throw new Error("Custom package-manager configuration requires installation");
12865
+ return [file, digestTree((0, import_node_path5.dirname)(file), [(0, import_node_path5.relative)((0, import_node_path5.dirname)(file), file)], (0, import_node_path5.dirname)(file))];
12866
+ });
12867
+ const yarnCache = (0, import_node_path5.join)(cacheRoot, "yarn");
12868
+ const nativeCache = project.manager === "yarn" && (0, import_node_fs5.existsSync)(yarnCache) ? digestTree(yarnCache, (0, import_node_fs5.readdirSync)(yarnCache), yarnCache) : null;
12869
+ const key = (0, import_node_crypto2.createHash)("sha256").update(
12870
+ JSON.stringify({
12871
+ format: DEPENDENCY_SNAPSHOT_FORMAT,
12872
+ root: project.root,
12873
+ cacheRoot,
12874
+ manager: project.manager,
12875
+ managerVersion,
12876
+ declared: project.declared,
12877
+ platform: process.platform,
12878
+ arch: process.arch,
12879
+ kernel: (0, import_node_os3.release)(),
12880
+ runtime: process.versions,
12881
+ environment: Object.entries(environment).sort(([a], [b]) => a.localeCompare(b)),
12882
+ inputHash,
12883
+ configHash,
12884
+ nativeCache
12885
+ })
12886
+ ).digest("hex");
12887
+ const projectKey = (0, import_node_crypto2.createHash)("sha256").update(project.root).digest("hex");
12888
+ return {
12889
+ root: project.root,
12890
+ cacheRoot,
12891
+ directory: (0, import_node_path5.join)(cacheRoot, "prepared-v1", projectKey),
12892
+ key,
12893
+ outputs: [...outputs].sort()
12894
+ };
12895
+ } catch {
12896
+ return void 0;
12897
+ }
12898
+ }
12899
+ function copy(source, destination) {
12900
+ (0, import_node_fs5.cpSync)(source, destination, {
12901
+ recursive: true,
12902
+ dereference: false,
12903
+ verbatimSymlinks: true,
12904
+ mode: import_node_fs5.constants.COPYFILE_FICLONE
12905
+ });
12906
+ }
12907
+ function restoreDependencySnapshot(snapshot) {
12908
+ let staging;
12909
+ let activated = [];
12910
+ let previous = [];
12911
+ try {
12912
+ if ((0, import_node_fs5.lstatSync)(snapshot.directory, { throwIfNoEntry: false })?.isSymbolicLink()) return false;
12913
+ const record = import_zod2.z.object({
12914
+ format: import_zod2.z.literal(DEPENDENCY_SNAPSHOT_FORMAT),
12915
+ key: import_zod2.z.literal(snapshot.key),
12916
+ sha256: import_zod2.z.string().regex(/^[a-f0-9]{64}$/),
12917
+ outputs: import_zod2.z.array(import_zod2.z.string()).refine(
12918
+ (paths) => new Set(paths).size === paths.length && paths.every((path) => snapshot.outputs.includes(path))
12919
+ )
12920
+ }).parse(JSON.parse((0, import_node_fs5.readFileSync)((0, import_node_path5.join)(snapshot.directory, "snapshot.json"), "utf8")));
12921
+ const stored = (0, import_node_path5.join)(snapshot.directory, "files");
12922
+ if (!record.outputs.length || digestTree(stored, record.outputs, snapshot.root) !== record.sha256) return false;
12923
+ for (const path of snapshot.outputs) {
12924
+ for (let cursor = (0, import_node_path5.dirname)((0, import_node_path5.join)(snapshot.root, path)); inside(snapshot.root, cursor); cursor = (0, import_node_path5.dirname)(cursor)) {
12925
+ if ((0, import_node_fs5.lstatSync)(cursor, { throwIfNoEntry: false })?.isSymbolicLink()) return false;
12926
+ if (cursor === snapshot.root) break;
12927
+ }
12928
+ }
12929
+ staging = (0, import_node_fs5.mkdtempSync)((0, import_node_path5.join)(snapshot.root, DEPENDENCY_MUTEX, "snapshot-"));
12930
+ for (const path of record.outputs) copy((0, import_node_path5.join)(stored, path), (0, import_node_path5.join)(staging, "next", path));
12931
+ if (digestTree((0, import_node_path5.join)(staging, "next"), record.outputs, snapshot.root) !== record.sha256) return false;
12932
+ for (const path of snapshot.outputs) {
12933
+ const target = (0, import_node_path5.join)(snapshot.root, path);
12934
+ if ((0, import_node_fs5.lstatSync)(target, { throwIfNoEntry: false })) {
12935
+ const backup = (0, import_node_path5.join)(staging, "previous", path);
12936
+ (0, import_node_fs5.mkdirSync)((0, import_node_path5.dirname)(backup), { recursive: true });
12937
+ (0, import_node_fs5.renameSync)(target, backup);
12938
+ previous = [...previous, path];
12939
+ }
12940
+ if (record.outputs.includes(path)) {
12941
+ (0, import_node_fs5.mkdirSync)((0, import_node_path5.dirname)(target), { recursive: true });
12942
+ (0, import_node_fs5.renameSync)((0, import_node_path5.join)(staging, "next", path), target);
12943
+ activated = [...activated, path];
12944
+ }
12945
+ }
12946
+ return true;
12947
+ } catch {
12948
+ try {
12949
+ for (const path of [...activated].reverse()) (0, import_node_fs5.rmSync)((0, import_node_path5.join)(snapshot.root, path), { recursive: true, force: true });
12950
+ for (const path of [...previous].reverse())
12951
+ (0, import_node_fs5.renameSync)((0, import_node_path5.join)(staging, "previous", path), (0, import_node_path5.join)(snapshot.root, path));
12952
+ } catch {
12953
+ const retained = staging;
12954
+ staging = void 0;
12955
+ throw new Error(`Dependency snapshot activation failed; previous files retained in ${retained}`);
12956
+ }
12957
+ return false;
12958
+ } finally {
12959
+ if (staging) (0, import_node_fs5.rmSync)(staging, { recursive: true, force: true });
12960
+ }
12961
+ }
12962
+ function saveDependencySnapshot(snapshot) {
12963
+ let staging;
12964
+ try {
12965
+ const outputs = snapshot.outputs.filter((path) => (0, import_node_fs5.lstatSync)((0, import_node_path5.join)(snapshot.root, path), { throwIfNoEntry: false }));
12966
+ if (!outputs.length) return;
12967
+ const sha256 = digestTree(snapshot.root, outputs, snapshot.root);
12968
+ (0, import_node_fs5.mkdirSync)((0, import_node_path5.dirname)(snapshot.directory), { recursive: true });
12969
+ staging = (0, import_node_fs5.mkdtempSync)((0, import_node_path5.join)((0, import_node_path5.dirname)(snapshot.directory), ".prepared-"));
12970
+ for (const path of outputs) copy((0, import_node_path5.join)(snapshot.root, path), (0, import_node_path5.join)(staging, "files", path));
12971
+ if (digestTree((0, import_node_path5.join)(staging, "files"), outputs, snapshot.root) !== sha256) return;
12972
+ (0, import_node_fs5.writeFileSync)(
12973
+ (0, import_node_path5.join)(staging, "snapshot.json"),
12974
+ JSON.stringify({ format: DEPENDENCY_SNAPSHOT_FORMAT, key: snapshot.key, sha256, outputs })
12975
+ );
12976
+ (0, import_node_fs5.rmSync)(snapshot.directory, { recursive: true, force: true });
12977
+ (0, import_node_fs5.renameSync)(staging, snapshot.directory);
12978
+ } catch {
12979
+ } finally {
12980
+ if (staging) (0, import_node_fs5.rmSync)(staging, { recursive: true, force: true });
12981
+ }
12982
+ }
12983
+
12647
12984
  // packages/plugin/src/dependencies.ts
12648
12985
  var execute = (0, import_node_util.promisify)(import_node_child_process.execFile);
12649
12986
  var installations = /* @__PURE__ */ new Map();
12650
12987
  function checkTransactionPath(root, file) {
12651
- const local = (0, import_node_path5.relative)(root, file);
12652
- if (!local || local.startsWith("../") || (0, import_node_path5.resolve)(root, local) !== file)
12988
+ const local = (0, import_node_path6.relative)(root, file);
12989
+ if (!local || local.startsWith("../") || (0, import_node_path6.resolve)(root, local) !== file)
12653
12990
  throw new Error("Transaction path must stay inside its project");
12654
- for (let cursor = file; cursor !== root; cursor = (0, import_node_path5.dirname)(cursor)) {
12655
- const stat = (0, import_node_fs5.lstatSync)(cursor, { throwIfNoEntry: false });
12991
+ for (let cursor = file; cursor !== root; cursor = (0, import_node_path6.dirname)(cursor)) {
12992
+ const stat = (0, import_node_fs6.lstatSync)(cursor, { throwIfNoEntry: false });
12656
12993
  if (stat?.isSymbolicLink()) throw new Error("Transaction path contains a symbolic link");
12657
12994
  }
12658
12995
  }
12659
12996
  function manifest(root) {
12660
- const file = (0, import_node_path5.join)(root, "package.json");
12661
- return (0, import_node_fs5.existsSync)(file) ? JSON.parse((0, import_node_fs5.readFileSync)(file, "utf8")) : {};
12997
+ const file = (0, import_node_path6.join)(root, "package.json");
12998
+ return (0, import_node_fs6.existsSync)(file) ? JSON.parse((0, import_node_fs6.readFileSync)(file, "utf8")) : {};
12662
12999
  }
12663
13000
  function dependencyCacheRoot(root) {
12664
- return (0, import_node_path5.resolve)(root ?? (0, import_common.OCTONODE_PACKAGE_CACHE)() ?? (0, import_node_path5.join)((0, import_node_os3.homedir)(), ".octonode", "package-cache"));
13001
+ return (0, import_node_path6.resolve)(root ?? (0, import_common.OCTONODE_PACKAGE_CACHE)() ?? (0, import_node_path6.join)((0, import_node_os4.homedir)(), ".octonode", "package-cache"));
12665
13002
  }
12666
13003
  function dependencyPaths(cwd) {
12667
- const start = (0, import_node_fs5.realpathSync)(cwd);
13004
+ const start = (0, import_node_fs6.realpathSync)(cwd);
12668
13005
  const ancestors = [];
12669
- for (let path = start; ; path = (0, import_node_path5.dirname)(path)) {
13006
+ for (let path = start; ; path = (0, import_node_path6.dirname)(path)) {
12670
13007
  ancestors.push(path);
12671
- if ((0, import_node_fs5.existsSync)((0, import_node_path5.join)(path, ".git")) || (0, import_node_path5.dirname)(path) === path) break;
13008
+ if ((0, import_node_fs6.existsSync)((0, import_node_path6.join)(path, ".git")) || (0, import_node_path6.dirname)(path) === path) break;
12672
13009
  }
12673
- const repository = ancestors.find((path) => (0, import_node_fs5.existsSync)((0, import_node_path5.join)(path, ".git")));
12674
- const target = (0, import_node_fs5.existsSync)((0, import_node_path5.join)(start, "package.json")) ? start : repository ? ancestors.find((path) => (0, import_node_fs5.existsSync)((0, import_node_path5.join)(path, "package.json"))) ?? start : start;
13010
+ const repository = ancestors.find((path) => (0, import_node_fs6.existsSync)((0, import_node_path6.join)(path, ".git")));
13011
+ const target = (0, import_node_fs6.existsSync)((0, import_node_path6.join)(start, "package.json")) ? start : repository ? ancestors.find((path) => (0, import_node_fs6.existsSync)((0, import_node_path6.join)(path, "package.json"))) ?? start : start;
12675
13012
  const root = ancestors.find((path) => {
12676
- if (path === target || !(0, import_node_path5.relative)(path, target) || (0, import_node_path5.relative)(path, target).startsWith("..")) return false;
13013
+ if (path === target || !(0, import_node_path6.relative)(path, target) || (0, import_node_path6.relative)(path, target).startsWith("..")) return false;
12677
13014
  const workspaces = manifest(path).workspaces;
12678
- const pnpmWorkspace = (0, import_node_path5.join)(path, "pnpm-workspace.yaml");
12679
- const patterns = (0, import_node_fs5.existsSync)(pnpmWorkspace) ? (0, import_yaml.parse)((0, import_node_fs5.readFileSync)(pnpmWorkspace, "utf8"))?.packages : Array.isArray(workspaces) ? workspaces : workspaces?.packages;
13015
+ const pnpmWorkspace = (0, import_node_path6.join)(path, "pnpm-workspace.yaml");
13016
+ const patterns = (0, import_node_fs6.existsSync)(pnpmWorkspace) ? (0, import_yaml.parse)((0, import_node_fs6.readFileSync)(pnpmWorkspace, "utf8"))?.packages : Array.isArray(workspaces) ? workspaces : workspaces?.packages;
12680
13017
  if (!Array.isArray(patterns)) return false;
12681
- const local = (0, import_node_path5.relative)(path, target).split("\\").join("/");
13018
+ const local = (0, import_node_path6.relative)(path, target).split("\\").join("/");
12682
13019
  const globs = patterns.filter((value) => typeof value === "string");
12683
- return globs.some((pattern) => !pattern.startsWith("!") && (0, import_node_path5.matchesGlob)(local, pattern.replace(/\/$/, ""))) && !globs.some((pattern) => pattern.startsWith("!") && (0, import_node_path5.matchesGlob)(local, pattern.slice(1).replace(/\/$/, "")));
13020
+ return globs.some((pattern) => !pattern.startsWith("!") && (0, import_node_path6.matchesGlob)(local, pattern.replace(/\/$/, ""))) && !globs.some((pattern) => pattern.startsWith("!") && (0, import_node_path6.matchesGlob)(local, pattern.slice(1).replace(/\/$/, "")));
12684
13021
  }) ?? target;
12685
13022
  return { root, target };
12686
13023
  }
@@ -12688,7 +13025,7 @@ function resolveDependencyProject(cwd) {
12688
13025
  const { root, target } = dependencyPaths(cwd);
12689
13026
  const declared = manifest(root).packageManager;
12690
13027
  const locked = Object.keys(PACKAGE_MANAGER_LOCKS).filter(
12691
- (manager2) => PACKAGE_MANAGER_LOCKS[manager2].some((file) => (0, import_node_fs5.existsSync)((0, import_node_path5.join)(root, file)))
13028
+ (manager2) => PACKAGE_MANAGER_LOCKS[manager2].some((file) => (0, import_node_fs6.existsSync)((0, import_node_path6.join)(root, file)))
12692
13029
  );
12693
13030
  const manager = declared?.split("@")[0];
12694
13031
  if (manager && !(manager in PACKAGE_MANAGER_LOCKS)) throw new Error(`unsupported package manager: ${declared}`);
@@ -12698,7 +13035,7 @@ function resolveDependencyProject(cwd) {
12698
13035
  return {
12699
13036
  target,
12700
13037
  root,
12701
- manager: manager ?? locked[0] ?? ((0, import_node_fs5.existsSync)((0, import_node_path5.join)(root, "pnpm-workspace.yaml")) ? "pnpm" : (0, import_node_fs5.existsSync)((0, import_node_path5.join)(target, "package.json")) ? "npm" : "pnpm"),
13038
+ manager: manager ?? locked[0] ?? ((0, import_node_fs6.existsSync)((0, import_node_path6.join)(root, "pnpm-workspace.yaml")) ? "pnpm" : (0, import_node_fs6.existsSync)((0, import_node_path6.join)(target, "package.json")) ? "npm" : "pnpm"),
12702
13039
  declared
12703
13040
  };
12704
13041
  }
@@ -12726,42 +13063,48 @@ function installCommand(project, frozen) {
12726
13063
  return ["npm", [frozen ? "ci" : "install", "--ignore-scripts", "--no-audit", "--no-fund"]];
12727
13064
  }
12728
13065
  }
13066
+ function installEnvironment(cacheRoot) {
13067
+ return (0, import_common.childProcessEnvironment)({
13068
+ ...(0, import_common.packageCacheEnvironment)(dependencyCacheRoot(cacheRoot)),
13069
+ YARN_ENABLE_SCRIPTS: "false",
13070
+ COREPACK_ENABLE_DOWNLOAD_PROMPT: "0",
13071
+ COREPACK_ENABLE_AUTO_PIN: "0"
13072
+ });
13073
+ }
13074
+ function isClassicYarn(project) {
13075
+ return project.manager === "yarn" && (project.declared?.startsWith("yarn@1.") || !project.declared && (0, import_node_fs6.existsSync)((0, import_node_path6.join)(project.root, "yarn.lock")) && (0, import_node_fs6.readFileSync)((0, import_node_path6.join)(project.root, "yarn.lock"), "utf8").includes("# yarn lockfile v1"));
13076
+ }
12729
13077
  async function run(project, command, cwd, cacheRoot) {
12730
13078
  const [file, args] = command;
12731
- const yarnClassic = project.manager === "yarn" && (project.declared?.startsWith("yarn@1.") || !project.declared && (0, import_node_fs5.existsSync)((0, import_node_path5.join)(project.root, "yarn.lock")) && (0, import_node_fs5.readFileSync)((0, import_node_path5.join)(project.root, "yarn.lock"), "utf8").includes("# yarn lockfile v1"));
13079
+ const yarnClassic = isClassicYarn(project);
12732
13080
  const flags = yarnClassic ? [
12733
13081
  ...args.filter((arg) => arg !== "--mode=skip-build").map((arg) => arg === "--immutable" ? "--frozen-lockfile" : arg),
12734
13082
  "--ignore-scripts"
12735
- ] : project.manager === "pnpm" && args[0] === "add" && project.root === cwd && (0, import_node_fs5.existsSync)((0, import_node_path5.join)(cwd, "pnpm-workspace.yaml")) ? [...args, "--workspace-root"] : args;
13083
+ ] : project.manager === "pnpm" && args[0] === "add" && project.root === cwd && (0, import_node_fs6.existsSync)((0, import_node_path6.join)(cwd, "pnpm-workspace.yaml")) ? [...args, "--workspace-root"] : args;
12736
13084
  const pinned = project.declared && file !== "bun" || yarnClassic;
12737
13085
  const executable = yarnClassic && !project.declared ? CLASSIC_YARN : file;
12738
13086
  await execute(pinned ? "corepack" : file, pinned ? [executable, ...flags] : flags, {
12739
13087
  cwd,
12740
- env: (0, import_common.childProcessEnvironment)({
12741
- ...(0, import_common.packageCacheEnvironment)(dependencyCacheRoot(cacheRoot)),
12742
- YARN_ENABLE_SCRIPTS: "false",
12743
- COREPACK_ENABLE_DOWNLOAD_PROMPT: "0",
12744
- COREPACK_ENABLE_AUTO_PIN: "0"
12745
- }),
13088
+ env: installEnvironment(cacheRoot),
12746
13089
  timeout: DEPENDENCY_INSTALL_TIMEOUT_MS,
12747
13090
  maxBuffer: 4 * 1024 * 1024
12748
13091
  });
12749
13092
  }
12750
13093
  async function verifyProjectDependencies(project, names) {
12751
13094
  if (!names.length) return;
12752
- const pnp = (0, import_node_path5.join)(project.root, ".pnp.cjs");
12753
- const loader = (0, import_node_path5.join)(project.root, ".pnp.loader.mjs");
13095
+ const pnp = (0, import_node_path6.join)(project.root, ".pnp.cjs");
13096
+ const loader = (0, import_node_path6.join)(project.root, ".pnp.loader.mjs");
12754
13097
  await execute(
12755
13098
  process.execPath,
12756
13099
  [
12757
- ...(0, import_node_fs5.existsSync)(pnp) ? ["--require", pnp] : [],
12758
- ...(0, import_node_fs5.existsSync)(loader) ? ["--loader", loader] : [],
13100
+ ...(0, import_node_fs6.existsSync)(pnp) ? ["--require", pnp] : [],
13101
+ ...(0, import_node_fs6.existsSync)(loader) ? ["--loader", loader] : [],
12759
13102
  "--input-type=module",
12760
13103
  "-e",
12761
13104
  `import { createRequire } from 'node:module';
12762
13105
  import { existsSync } from 'node:fs';
12763
13106
  import { fileURLToPath } from 'node:url';
12764
- const require = createRequire(${JSON.stringify((0, import_node_path5.join)(project.target, "package.json"))});
13107
+ const require = createRequire(${JSON.stringify((0, import_node_path6.join)(project.target, "package.json"))});
12765
13108
  for (const name of ${JSON.stringify(names)}) {
12766
13109
  try { require.resolve(name); } catch {
12767
13110
  const entry = import.meta.resolve(name);
@@ -12779,19 +13122,19 @@ async function withDependencyInstall(cwd, action) {
12779
13122
  const previous = installations.get(root) ?? Promise.resolve();
12780
13123
  const next = previous.catch(() => {
12781
13124
  }).then(async () => {
12782
- const mutex = (0, import_node_path5.join)(root, DEPENDENCY_MUTEX);
13125
+ const mutex = (0, import_node_path6.join)(root, DEPENDENCY_MUTEX);
12783
13126
  try {
12784
- (0, import_node_fs5.mkdirSync)(mutex);
13127
+ (0, import_node_fs6.mkdirSync)(mutex);
12785
13128
  } catch {
12786
13129
  throw new Error(
12787
13130
  "Another dependency installation is running or needs recovery; use octonodes plugin recover after it exits"
12788
13131
  );
12789
13132
  }
12790
- (0, import_node_fs5.writeFileSync)((0, import_node_path5.join)(mutex, "owner.json"), JSON.stringify({ pid: process.pid }));
13133
+ (0, import_node_fs6.writeFileSync)((0, import_node_path6.join)(mutex, "owner.json"), JSON.stringify({ pid: process.pid }));
12791
13134
  try {
12792
13135
  return await action();
12793
13136
  } finally {
12794
- if (!(0, import_node_fs5.existsSync)((0, import_node_path5.join)(mutex, "journal.json"))) (0, import_node_fs5.rmSync)(mutex, { recursive: true, force: true });
13137
+ if (!(0, import_node_fs6.existsSync)((0, import_node_path6.join)(mutex, "journal.json"))) (0, import_node_fs6.rmSync)(mutex, { recursive: true, force: true });
12795
13138
  }
12796
13139
  });
12797
13140
  installations.set(root, next);
@@ -12802,6 +13145,8 @@ async function withDependencyInstall(cwd, action) {
12802
13145
  }
12803
13146
  }
12804
13147
  async function reconcileDependencies(cwd, dependencies, options = {}) {
13148
+ if (options.metadataOnly && (dependencies.length || options.remove?.length || options.frozen))
13149
+ throw new Error("Metadata-only transactions cannot change or restore dependencies");
12805
13150
  if (options.frozen && (dependencies.length || options.remove?.length))
12806
13151
  throw new Error("Frozen installation cannot add or remove dependencies");
12807
13152
  for (const { name, spec, subpaths } of dependencies) {
@@ -12815,64 +13160,82 @@ async function reconcileDependencies(cwd, dependencies, options = {}) {
12815
13160
  }
12816
13161
  }
12817
13162
  const project = resolveDependencyProject(cwd);
12818
- const packageJson = (0, import_node_path5.join)(project.target, "package.json");
12819
- if (!dependencies.length && !(0, import_node_fs5.existsSync)(packageJson) && !options.commit) return;
12820
- const hasLock = PACKAGE_MANAGER_LOCKS[project.manager].some((file) => (0, import_node_fs5.existsSync)((0, import_node_path5.join)(project.root, file)));
13163
+ const packageJson = (0, import_node_path6.join)(project.target, "package.json");
13164
+ if (!dependencies.length && !(0, import_node_fs6.existsSync)(packageJson) && !options.commit) return;
13165
+ const hasLock = PACKAGE_MANAGER_LOCKS[project.manager].some((file) => (0, import_node_fs6.existsSync)((0, import_node_path6.join)(project.root, file)));
12821
13166
  if (options.frozen && !hasLock)
12822
13167
  throw new Error("commit the native package-manager lockfile before preparing this worktree");
12823
13168
  const files = [
12824
13169
  .../* @__PURE__ */ new Set([
12825
13170
  packageJson,
12826
- (0, import_node_path5.join)(project.root, "package.json"),
12827
- ...Object.values(PACKAGE_MANAGER_LOCKS).flat().map((file) => (0, import_node_path5.join)(project.root, file)),
12828
- (0, import_node_path5.join)(project.root, "pnpm-workspace.yaml"),
13171
+ (0, import_node_path6.join)(project.root, "package.json"),
13172
+ ...Object.values(PACKAGE_MANAGER_LOCKS).flat().map((file) => (0, import_node_path6.join)(project.root, file)),
13173
+ (0, import_node_path6.join)(project.root, "pnpm-workspace.yaml"),
12829
13174
  ...options.transactionFiles ?? []
12830
13175
  ])
12831
13176
  ];
12832
13177
  for (const path of files) checkTransactionPath(project.root, path);
12833
- const before = new Map(files.map((path) => [path, (0, import_node_fs5.existsSync)(path) ? (0, import_node_fs5.readFileSync)(path) : void 0]));
12834
- const journal = (0, import_node_path5.join)(project.root, DEPENDENCY_MUTEX, "journal.json");
12835
- const hadModules = (0, import_node_fs5.existsSync)((0, import_node_path5.join)(project.root, "node_modules"));
13178
+ const before = new Map(files.map((path) => [path, (0, import_node_fs6.existsSync)(path) ? (0, import_node_fs6.readFileSync)(path) : void 0]));
13179
+ const journal = (0, import_node_path6.join)(project.root, DEPENDENCY_MUTEX, "journal.json");
13180
+ const hadModules = (0, import_node_fs6.existsSync)((0, import_node_path6.join)(project.root, "node_modules"));
12836
13181
  const pnpFiles = [".pnp.cjs", ".pnp.loader.mjs", ".pnp.data.json"];
12837
13182
  const pnpBefore = new Map(
12838
13183
  pnpFiles.map((file) => {
12839
- const path = (0, import_node_path5.join)(project.root, file);
12840
- return [path, (0, import_node_fs5.existsSync)(path) ? (0, import_node_fs5.readFileSync)(path) : void 0];
13184
+ const path = (0, import_node_path6.join)(project.root, file);
13185
+ return [path, (0, import_node_fs6.existsSync)(path) ? (0, import_node_fs6.readFileSync)(path) : void 0];
12841
13186
  })
12842
13187
  );
12843
- const hadInstall = hadModules || (0, import_node_fs5.existsSync)((0, import_node_path5.join)(project.root, ".pnp.cjs"));
13188
+ const hadInstall = hadModules || (0, import_node_fs6.existsSync)((0, import_node_path6.join)(project.root, ".pnp.cjs"));
12844
13189
  let metadataTouched = false;
12845
13190
  const metadata = new Set(options.transactionFiles ?? []);
12846
13191
  const restoreBefore = () => {
12847
13192
  for (const [path, content] of before) {
12848
13193
  if (metadata.has(path) && !metadataTouched) continue;
12849
- if (content === void 0) (0, import_node_fs5.rmSync)(path, { force: true });
12850
- else (0, import_node_fs5.writeFileSync)(path, content);
13194
+ if (content === void 0) (0, import_node_fs6.rmSync)(path, { force: true });
13195
+ else (0, import_node_fs6.writeFileSync)(path, content);
12851
13196
  }
12852
13197
  };
12853
- if (hadInstall && !hasLock)
13198
+ if (hadInstall && !hasLock && !options.metadataOnly)
12854
13199
  throw new Error(
12855
13200
  "create a native lockfile before updating existing dependencies so failed installations can be recovered"
12856
13201
  );
12857
13202
  try {
12858
- if ((0, import_node_fs5.existsSync)((0, import_node_path5.dirname)(journal)))
12859
- (0, import_node_fs5.writeFileSync)(
13203
+ if (options.metadataOnly && (0, import_node_fs6.existsSync)((0, import_node_path6.dirname)(journal)))
13204
+ (0, import_node_fs6.writeFileSync)((0, import_node_path6.join)((0, import_node_path6.dirname)(journal), "metadata-only"), "1");
13205
+ if ((0, import_node_fs6.existsSync)((0, import_node_path6.dirname)(journal)))
13206
+ (0, import_node_fs6.writeFileSync)(
12860
13207
  journal,
12861
13208
  JSON.stringify(
12862
13209
  [...before].map(([path, content]) => ({
12863
- path: (0, import_node_path5.relative)(project.root, path).replaceAll("\\", "/"),
13210
+ path: (0, import_node_path6.relative)(project.root, path).replaceAll("\\", "/"),
12864
13211
  content: content?.toString("base64") ?? null
12865
13212
  }))
12866
13213
  )
12867
13214
  );
12868
- if (!(0, import_node_fs5.existsSync)(packageJson)) {
12869
- (0, import_node_fs5.mkdirSync)(project.target, { recursive: true });
12870
- (0, import_node_fs5.writeFileSync)(
13215
+ if (options.metadataOnly) {
13216
+ metadataTouched = true;
13217
+ options.commit?.();
13218
+ (0, import_node_fs6.rmSync)(journal, { force: true });
13219
+ (0, import_node_fs6.rmSync)((0, import_node_path6.join)((0, import_node_path6.dirname)(journal), "metadata-only"), { force: true });
13220
+ return;
13221
+ }
13222
+ if (!(0, import_node_fs6.existsSync)(packageJson)) {
13223
+ (0, import_node_fs6.mkdirSync)(project.target, { recursive: true });
13224
+ (0, import_node_fs6.writeFileSync)(
12871
13225
  packageJson,
12872
13226
  JSON.stringify({ private: true, packageManager: DEFAULT_PACKAGE_MANAGER }, null, 2) + "\n"
12873
13227
  );
12874
13228
  }
12875
13229
  const current = resolveDependencyProject(cwd);
13230
+ const snapshotEnvironment = installEnvironment(options.cacheRoot);
13231
+ const pinnedManager = current.declared && current.manager !== "bun" || isClassicYarn(current);
13232
+ const versionCommand = isClassicYarn(current) && !current.declared ? CLASSIC_YARN : current.manager;
13233
+ const managerVersion = options.frozen && (options.cacheRoot || (0, import_common.OCTONODE_PACKAGE_CACHE)()) ? await execute(
13234
+ pinnedManager ? "corepack" : current.manager,
13235
+ pinnedManager ? [versionCommand, "--version"] : ["--version"],
13236
+ { cwd: current.root, env: snapshotEnvironment, timeout: 3e4 }
13237
+ ).then(({ stdout }) => stdout.trim()).catch(() => void 0) : void 0;
13238
+ const snapshot = managerVersion ? dependencySnapshot(current, dependencyCacheRoot(options.cacheRoot), managerVersion, snapshotEnvironment) : void 0;
12876
13239
  if (options.remove?.length) {
12877
13240
  for (const name of options.remove)
12878
13241
  if (!/^(?:@[a-z0-9][a-z0-9._~-]*\/)?[a-z0-9][a-z0-9._~-]*$/i.test(name))
@@ -12880,81 +13243,92 @@ async function reconcileDependencies(cwd, dependencies, options = {}) {
12880
13243
  const args = current.manager === "npm" ? ["uninstall", "--ignore-scripts", "--no-audit", "--no-fund"] : current.manager === "yarn" ? ["remove", "--mode=skip-build"] : ["remove", "--ignore-scripts"];
12881
13244
  await run(current, [current.manager, [...args, ...options.remove]], current.target, options.cacheRoot);
12882
13245
  }
12883
- await run(
12884
- current,
12885
- dependencies.length ? packageManagerAdd(
12886
- current.manager,
12887
- ...dependencies.map(({ name, spec }) => spec.startsWith(`${name}@`) ? spec : `${name}@${spec}`)
12888
- ) : installCommand(current, options.frozen ?? false),
12889
- dependencies.length ? current.target : current.root,
12890
- options.cacheRoot
12891
- );
13246
+ const restored = snapshot ? restoreDependencySnapshot(snapshot) : false;
13247
+ if (!restored)
13248
+ await run(
13249
+ current,
13250
+ dependencies.length ? packageManagerAdd(
13251
+ current.manager,
13252
+ ...dependencies.map(({ name, spec }) => spec.startsWith(`${name}@`) ? spec : `${name}@${spec}`)
13253
+ ) : installCommand(current, options.frozen ?? false),
13254
+ dependencies.length ? current.target : current.root,
13255
+ options.cacheRoot
13256
+ );
12892
13257
  await verifyProjectDependencies(
12893
13258
  current,
12894
13259
  dependencies.flatMap(({ name, subpaths }) => subpaths ? subpaths.map((path) => name + path.slice(1)) : [name])
12895
13260
  );
12896
13261
  if (options.frozen) {
12897
13262
  for (const [path, content] of before) {
12898
- const after = (0, import_node_fs5.existsSync)(path) ? (0, import_node_fs5.readFileSync)(path) : void 0;
13263
+ const after = (0, import_node_fs6.existsSync)(path) ? (0, import_node_fs6.readFileSync)(path) : void 0;
12899
13264
  if (content?.equals(after ?? Buffer.alloc(0)) || !content && !after) continue;
12900
13265
  if (path.endsWith("package.json") && content && after && (0, import_node_util.isDeepStrictEqual)(JSON.parse(content.toString()), JSON.parse(after.toString()))) {
12901
- (0, import_node_fs5.writeFileSync)(path, content);
13266
+ (0, import_node_fs6.writeFileSync)(path, content);
12902
13267
  } else {
12903
- throw new Error(`frozen installation changed ${(0, import_node_path5.relative)(project.root, path)}`);
13268
+ throw new Error(`frozen installation changed ${(0, import_node_path6.relative)(project.root, path)}`);
12904
13269
  }
12905
13270
  }
12906
13271
  }
12907
13272
  for (const path of metadata) {
12908
13273
  const content = before.get(path);
12909
- const current2 = (0, import_node_fs5.existsSync)(path) ? (0, import_node_fs5.readFileSync)(path) : void 0;
13274
+ const current2 = (0, import_node_fs6.existsSync)(path) ? (0, import_node_fs6.readFileSync)(path) : void 0;
12910
13275
  if (!(content?.equals(current2 ?? Buffer.alloc(0)) || !content && !current2))
12911
13276
  throw new Error(
12912
- `Owner metadata changed during installation: ${(0, import_node_path5.relative)(project.root, path)}; refresh and retry`
13277
+ `Owner metadata changed during installation: ${(0, import_node_path6.relative)(project.root, path)}; refresh and retry`
12913
13278
  );
12914
13279
  }
12915
13280
  metadataTouched = true;
12916
13281
  options.commit?.();
12917
- (0, import_node_fs5.rmSync)(journal, { force: true });
13282
+ (0, import_node_fs6.rmSync)(journal, { force: true });
13283
+ if (snapshot && !restored) {
13284
+ const after = dependencySnapshot(
13285
+ current,
13286
+ dependencyCacheRoot(options.cacheRoot),
13287
+ managerVersion,
13288
+ snapshotEnvironment
13289
+ );
13290
+ if (after?.key === snapshot.key) saveDependencySnapshot(after);
13291
+ }
12918
13292
  } catch (error) {
12919
- const changed = [...before].filter(([path, content]) => (0, import_node_fs5.existsSync)(path) && !content?.equals((0, import_node_fs5.readFileSync)(path)));
13293
+ const changed = [...before].filter(([path, content]) => (0, import_node_fs6.existsSync)(path) && !content?.equals((0, import_node_fs6.readFileSync)(path)));
12920
13294
  if (changed.length) {
12921
- const backup = (0, import_node_path5.join)(project.root, `.octonode-recovery-${Date.now()}`);
13295
+ const backup = (0, import_node_path6.join)(project.root, `.octonode-recovery-${Date.now()}`);
12922
13296
  for (const [path] of changed) {
12923
13297
  checkTransactionPath(project.root, path);
12924
- const target = (0, import_node_path5.join)(backup, (0, import_node_path5.relative)(project.root, path));
12925
- (0, import_node_fs5.mkdirSync)((0, import_node_path5.dirname)(target), { recursive: true });
12926
- (0, import_node_fs5.writeFileSync)(target, (0, import_node_fs5.readFileSync)(path));
13298
+ const target = (0, import_node_path6.join)(backup, (0, import_node_path6.relative)(project.root, path));
13299
+ (0, import_node_fs6.mkdirSync)((0, import_node_path6.dirname)(target), { recursive: true });
13300
+ (0, import_node_fs6.writeFileSync)(target, (0, import_node_fs6.readFileSync)(path));
12927
13301
  }
12928
13302
  process.stderr.write(`Pre-rollback files preserved in ${backup}
12929
13303
  `);
12930
13304
  }
12931
13305
  restoreBefore();
12932
13306
  let recovery = "";
12933
- if (hadInstall && hasLock) {
13307
+ if (!options.metadataOnly && hadInstall && hasLock) {
12934
13308
  try {
12935
13309
  await run(project, installCommand(project, true), project.root, options.cacheRoot);
12936
13310
  } catch {
12937
13311
  recovery = "; manifests restored, but dependency recovery failed \u2014 run a frozen install before executing workflows";
12938
13312
  }
12939
13313
  restoreBefore();
12940
- } else if (!hadInstall) {
12941
- (0, import_node_fs5.rmSync)((0, import_node_path5.join)(project.root, "node_modules"), { recursive: true, force: true });
13314
+ } else if (!options.metadataOnly && !hadInstall) {
13315
+ (0, import_node_fs6.rmSync)((0, import_node_path6.join)(project.root, "node_modules"), { recursive: true, force: true });
12942
13316
  }
12943
13317
  for (const [path, content] of pnpBefore) {
12944
- if (content === void 0) (0, import_node_fs5.rmSync)(path, { force: true });
12945
- else (0, import_node_fs5.writeFileSync)(path, content);
13318
+ if (content === void 0) (0, import_node_fs6.rmSync)(path, { force: true });
13319
+ else (0, import_node_fs6.writeFileSync)(path, content);
12946
13320
  }
12947
13321
  const failure = error;
12948
- if (!recovery) (0, import_node_fs5.rmSync)(journal, { force: true });
13322
+ if (!recovery) (0, import_node_fs6.rmSync)(journal, { force: true });
12949
13323
  throw new Error(`package installation failed: ${failure.stderr?.trim() || failure.message}${recovery}`);
12950
13324
  }
12951
13325
  }
12952
13326
  async function recoverDependencyInstall(cwd) {
12953
13327
  const project = resolveDependencyProject(cwd);
12954
- const mutex = (0, import_node_path5.join)(project.root, DEPENDENCY_MUTEX);
12955
- if (!(0, import_node_fs5.existsSync)(mutex)) return;
12956
- checkTransactionPath(project.root, (0, import_node_path5.join)(mutex, "owner.json"));
12957
- const owner = JSON.parse((0, import_node_fs5.readFileSync)((0, import_node_path5.join)(mutex, "owner.json"), "utf8"));
13328
+ const mutex = (0, import_node_path6.join)(project.root, DEPENDENCY_MUTEX);
13329
+ if (!(0, import_node_fs6.existsSync)(mutex)) return;
13330
+ checkTransactionPath(project.root, (0, import_node_path6.join)(mutex, "owner.json"));
13331
+ const owner = JSON.parse((0, import_node_fs6.readFileSync)((0, import_node_path6.join)(mutex, "owner.json"), "utf8"));
12958
13332
  if (!Number.isInteger(owner.pid) || owner.pid < 1)
12959
13333
  throw new Error("Invalid installation owner; inspect the transaction manually");
12960
13334
  try {
@@ -12963,37 +13337,37 @@ async function recoverDependencyInstall(cwd) {
12963
13337
  } catch (error) {
12964
13338
  if (error.code !== "ESRCH") throw error;
12965
13339
  }
12966
- const journal = (0, import_node_path5.join)(mutex, "journal.json");
13340
+ const journal = (0, import_node_path6.join)(mutex, "journal.json");
12967
13341
  checkTransactionPath(project.root, journal);
12968
- if ((0, import_node_fs5.existsSync)(journal)) {
12969
- const records = JSON.parse((0, import_node_fs5.readFileSync)(journal, "utf8"));
13342
+ if ((0, import_node_fs6.existsSync)(journal)) {
13343
+ const records = JSON.parse((0, import_node_fs6.readFileSync)(journal, "utf8"));
12970
13344
  if (!Array.isArray(records)) throw new Error("Invalid recovery journal");
12971
13345
  for (const record of records) {
12972
13346
  if (!record || typeof record.path !== "string" || !record.path || record.path.includes("\\") || record.path.startsWith("/") || record.path.split("/").some((part) => part === ".." || part === "." || part.includes(":")) || record.content !== null && typeof record.content !== "string")
12973
13347
  throw new Error("Invalid recovery journal path");
12974
- checkTransactionPath(project.root, (0, import_node_path5.join)(project.root, record.path));
12975
- checkTransactionPath(project.root, (0, import_node_path5.join)(mutex, "recovery-backup", record.path));
13348
+ checkTransactionPath(project.root, (0, import_node_path6.join)(project.root, record.path));
13349
+ checkTransactionPath(project.root, (0, import_node_path6.join)(mutex, "recovery-backup", record.path));
12976
13350
  }
12977
13351
  for (const record of records) {
12978
- const path = (0, import_node_path5.join)(project.root, record.path);
12979
- if ((0, import_node_fs5.existsSync)(path)) {
12980
- const backup = (0, import_node_path5.join)(mutex, "recovery-backup", record.path);
12981
- (0, import_node_fs5.mkdirSync)((0, import_node_path5.dirname)(backup), { recursive: true });
12982
- if (!(0, import_node_fs5.existsSync)(backup)) (0, import_node_fs5.writeFileSync)(backup, (0, import_node_fs5.readFileSync)(path));
12983
- }
12984
- if (record.content === null) (0, import_node_fs5.rmSync)(path, { force: true });
12985
- else (0, import_node_fs5.writeFileSync)(path, Buffer.from(record.content, "base64"));
13352
+ const path = (0, import_node_path6.join)(project.root, record.path);
13353
+ if ((0, import_node_fs6.existsSync)(path)) {
13354
+ const backup = (0, import_node_path6.join)(mutex, "recovery-backup", record.path);
13355
+ (0, import_node_fs6.mkdirSync)((0, import_node_path6.dirname)(backup), { recursive: true });
13356
+ if (!(0, import_node_fs6.existsSync)(backup)) (0, import_node_fs6.writeFileSync)(backup, (0, import_node_fs6.readFileSync)(path));
13357
+ }
13358
+ if (record.content === null) (0, import_node_fs6.rmSync)(path, { force: true });
13359
+ else (0, import_node_fs6.writeFileSync)(path, Buffer.from(record.content, "base64"));
12986
13360
  }
12987
- if (PACKAGE_MANAGER_LOCKS[project.manager].some((file) => (0, import_node_fs5.existsSync)((0, import_node_path5.join)(project.root, file))))
13361
+ if (!(0, import_node_fs6.existsSync)((0, import_node_path6.join)(mutex, "metadata-only")) && PACKAGE_MANAGER_LOCKS[project.manager].some((file) => (0, import_node_fs6.existsSync)((0, import_node_path6.join)(project.root, file))))
12988
13362
  await run(project, installCommand(project, true), project.root);
12989
13363
  }
12990
- if ((0, import_node_fs5.existsSync)((0, import_node_path5.join)(mutex, "recovery-backup"))) {
12991
- const backup = (0, import_node_path5.join)(project.root, `.octonode-recovery-${Date.now()}`);
12992
- (0, import_node_fs5.renameSync)((0, import_node_path5.join)(mutex, "recovery-backup"), backup);
13364
+ if ((0, import_node_fs6.existsSync)((0, import_node_path6.join)(mutex, "recovery-backup"))) {
13365
+ const backup = (0, import_node_path6.join)(project.root, `.octonode-recovery-${Date.now()}`);
13366
+ (0, import_node_fs6.renameSync)((0, import_node_path6.join)(mutex, "recovery-backup"), backup);
12993
13367
  process.stderr.write(`Pre-recovery files preserved in ${backup}
12994
13368
  `);
12995
13369
  }
12996
- (0, import_node_fs5.rmSync)(mutex, { recursive: true, force: true });
13370
+ (0, import_node_fs6.rmSync)(mutex, { recursive: true, force: true });
12997
13371
  }
12998
13372
  function installProjectDependencies(cwd, dependencies = [], options = {}) {
12999
13373
  return withDependencyInstall(cwd, () => reconcileDependencies(cwd, dependencies, options));
@@ -13002,15 +13376,15 @@ function installProjectDependencies(cwd, dependencies = [], options = {}) {
13002
13376
  // packages/plugin/src/generated-package.ts
13003
13377
  var import_tar = require("tar");
13004
13378
  var import_node_zlib = require("node:zlib");
13379
+ var import_node_crypto4 = require("node:crypto");
13380
+ var import_node_fs8 = require("node:fs");
13381
+ var import_node_os5 = require("node:os");
13382
+ var import_node_path8 = require("node:path");
13383
+
13384
+ // packages/plugin/src/authoring/artifact.ts
13005
13385
  var import_node_crypto3 = require("node:crypto");
13006
13386
  var import_node_fs7 = require("node:fs");
13007
- var import_node_os4 = require("node:os");
13008
13387
  var import_node_path7 = require("node:path");
13009
-
13010
- // packages/plugin/src/authoring/artifact.ts
13011
- var import_node_crypto2 = require("node:crypto");
13012
- var import_node_fs6 = require("node:fs");
13013
- var import_node_path6 = require("node:path");
13014
13388
  var import_schema3 = __toESM(require_dist());
13015
13389
  var import_yaml2 = require("yaml");
13016
13390
 
@@ -13030,18 +13404,18 @@ var RESERVED_ASSETS = /* @__PURE__ */ new Set([
13030
13404
  ]);
13031
13405
 
13032
13406
  // packages/plugin/src/authoring/artifact.ts
13033
- var fileHash = (path) => (0, import_node_crypto2.createHash)("sha256").update((0, import_node_fs6.readFileSync)(path)).digest("hex");
13407
+ var fileHash = (path) => (0, import_node_crypto3.createHash)("sha256").update((0, import_node_fs7.readFileSync)(path)).digest("hex");
13034
13408
  function safePath(path) {
13035
- if (!path || (0, import_node_path6.isAbsolute)(path) || path.includes("\\") || path.split("/").some((part) => !part || part === "." || part === ".." || part.includes(":") || FORBIDDEN_PART.test(part))) {
13409
+ if (!path || (0, import_node_path7.isAbsolute)(path) || path.includes("\\") || path.split("/").some((part) => !part || part === "." || part === ".." || part.includes(":") || FORBIDDEN_PART.test(part))) {
13036
13410
  throw new Error(`Unsafe plugin file: ${path}`);
13037
13411
  }
13038
13412
  }
13039
13413
  function pluginFiles(root, prefix = "") {
13040
- if (!(0, import_node_fs6.lstatSync)((0, import_node_path6.join)(root, prefix)).isDirectory()) throw new Error(`Not a plugin directory: ${root}`);
13041
- return (0, import_node_fs6.readdirSync)((0, import_node_path6.join)(root, prefix)).sort().flatMap((name) => {
13414
+ if (!(0, import_node_fs7.lstatSync)((0, import_node_path7.join)(root, prefix)).isDirectory()) throw new Error(`Not a plugin directory: ${root}`);
13415
+ return (0, import_node_fs7.readdirSync)((0, import_node_path7.join)(root, prefix)).sort().flatMap((name) => {
13042
13416
  const path = prefix ? `${prefix}/${name}` : name;
13043
13417
  safePath(path);
13044
- const stat = (0, import_node_fs6.lstatSync)((0, import_node_path6.join)(root, path));
13418
+ const stat = (0, import_node_fs7.lstatSync)((0, import_node_path7.join)(root, path));
13045
13419
  if (stat.isSymbolicLink()) throw new Error(`Plugin files cannot be symbolic links: ${path}`);
13046
13420
  if (stat.isDirectory()) return pluginFiles(root, path);
13047
13421
  if (!stat.isFile()) throw new Error(`Plugin asset must be a regular file: ${path}`);
@@ -13049,14 +13423,14 @@ function pluginFiles(root, prefix = "") {
13049
13423
  });
13050
13424
  }
13051
13425
  function loadManifest(directory) {
13052
- if ((0, import_node_fs6.lstatSync)(directory).isSymbolicLink()) throw new Error("Plugin directory cannot be a symbolic link");
13053
- const definitions = DEFINITION_FILES.filter((name) => (0, import_node_fs6.existsSync)((0, import_node_path6.join)(directory, name)));
13426
+ if ((0, import_node_fs7.lstatSync)(directory).isSymbolicLink()) throw new Error("Plugin directory cannot be a symbolic link");
13427
+ const definitions = DEFINITION_FILES.filter((name) => (0, import_node_fs7.existsSync)((0, import_node_path7.join)(directory, name)));
13054
13428
  if (definitions.length !== 1) throw new Error("Keep exactly one plugin definition in the package");
13055
- const path = (0, import_node_path6.join)(directory, definitions[0]);
13056
- const stat = (0, import_node_fs6.lstatSync)(path);
13429
+ const path = (0, import_node_path7.join)(directory, definitions[0]);
13430
+ const stat = (0, import_node_fs7.lstatSync)(path);
13057
13431
  if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1048576)
13058
13432
  throw new Error("Invalid plugin definition file");
13059
- const document = (0, import_yaml2.parseDocument)((0, import_node_fs6.readFileSync)(path, "utf8"), { uniqueKeys: true, version: "1.2" });
13433
+ const document = (0, import_yaml2.parseDocument)((0, import_node_fs7.readFileSync)(path, "utf8"), { uniqueKeys: true, version: "1.2" });
13060
13434
  (0, import_yaml2.visit)(document, {
13061
13435
  Alias() {
13062
13436
  throw new Error("Plugin definitions cannot contain YAML aliases");
@@ -13072,7 +13446,16 @@ function verifyBuild(directory) {
13072
13446
  const manifest2 = loadManifest(directory);
13073
13447
  const files = pluginFiles(directory);
13074
13448
  if (!files.includes(BUILD_RECORD)) throw new Error("Missing build record; run octonodes plugin build first");
13075
- const record = JSON.parse((0, import_node_fs6.readFileSync)((0, import_node_path6.join)(directory, BUILD_RECORD), "utf8"));
13449
+ const record = JSON.parse((0, import_node_fs7.readFileSync)((0, import_node_path7.join)(directory, BUILD_RECORD), "utf8"));
13450
+ if (record.runtime) {
13451
+ const runtime = import_schema3.PreparedPluginRuntime.parse(record.runtime);
13452
+ if ((manifest2.integration?.npm || manifest2.integration?.npmDependencies?.length) && !runtime.dependencies)
13453
+ throw new Error("Prepared npm plugins must include their dependency runtime");
13454
+ if (runtime.dependencies && !files.includes(runtime.dependencies))
13455
+ throw new Error("Missing prepared dependency archive");
13456
+ if (runtime.dependencies && (runtime.platform === "portable" || !runtime.arch || runtime.platform === "linux" && !runtime.libc))
13457
+ throw new Error("Prepared dependencies require a platform, architecture and libc identity");
13458
+ }
13076
13459
  if (record.format !== 1 || !record.files || typeof record.files !== "object" || Array.isArray(record.files)) {
13077
13460
  throw new Error("Invalid plugin build record");
13078
13461
  }
@@ -13081,7 +13464,7 @@ function verifyBuild(directory) {
13081
13464
  throw new Error("Plugin files changed since build; rebuild before publishing");
13082
13465
  }
13083
13466
  for (const file of expected) {
13084
- if (record.files[file] !== fileHash((0, import_node_path6.join)(directory, file)))
13467
+ if (record.files[file] !== fileHash((0, import_node_path7.join)(directory, file)))
13085
13468
  throw new Error(`Plugin file changed since build: ${file}`);
13086
13469
  }
13087
13470
  if (!expected.includes("dist/index.js") || !manifest2.nodes.length || manifest2.nodes.some(
@@ -13102,14 +13485,14 @@ function verifyBuild(directory) {
13102
13485
  )
13103
13486
  );
13104
13487
  for (const entry of new Set(ui.map(({ path }) => path))) {
13105
- if (!expected.includes(entry) || (0, import_node_fs6.lstatSync)((0, import_node_path6.join)(directory, entry)).size > import_schema3.PLUGIN_UI_BUNDLE_MAX_BYTES)
13488
+ if (!expected.includes(entry) || (0, import_node_fs7.lstatSync)((0, import_node_path7.join)(directory, entry)).size > import_schema3.PLUGIN_UI_BUNDLE_MAX_BYTES)
13106
13489
  throw new Error(`Invalid plugin UI bundle: ${entry}`);
13107
13490
  }
13108
13491
  if (JSON.stringify(record.ui ?? []) !== JSON.stringify(
13109
13492
  ui.map((declaration) => ({
13110
13493
  ...declaration,
13111
- size: (0, import_node_fs6.lstatSync)((0, import_node_path6.join)(directory, declaration.path)).size,
13112
- sha256: fileHash((0, import_node_path6.join)(directory, declaration.path))
13494
+ size: (0, import_node_fs7.lstatSync)((0, import_node_path7.join)(directory, declaration.path)).size,
13495
+ sha256: fileHash((0, import_node_path7.join)(directory, declaration.path))
13113
13496
  }))
13114
13497
  ))
13115
13498
  throw new Error("Invalid plugin UI build record");
@@ -13134,41 +13517,41 @@ async function generatePluginPackage(cwd, selections, expectedPacker) {
13134
13517
  const packer = "tar@7.5.22/portable-v1";
13135
13518
  if (expectedPacker && expectedPacker !== packer)
13136
13519
  throw new Error(`Plugin package restore requires ${expectedPacker}; found ${packer}`);
13137
- const digest = (0, import_node_crypto3.createHash)("sha256").update(
13520
+ const digest = (0, import_node_crypto4.createHash)("sha256").update(
13138
13521
  JSON.stringify({
13139
13522
  format: GENERATED_PLUGIN_FORMAT,
13140
13523
  packer,
13141
13524
  selections: selected.map(({ alias, sha256 }) => ({ alias, sha256 }))
13142
13525
  })
13143
13526
  ).digest("hex");
13144
- const stage = (0, import_node_fs7.mkdtempSync)((0, import_node_path7.join)((0, import_node_os4.tmpdir)(), "octonode-package-"));
13527
+ const stage = (0, import_node_fs8.mkdtempSync)((0, import_node_path8.join)((0, import_node_os5.tmpdir)(), "octonode-package-"));
13145
13528
  try {
13146
- const packageRoot = (0, import_node_path7.join)(stage, "package");
13147
- (0, import_node_fs7.mkdirSync)(packageRoot);
13529
+ const packageRoot = (0, import_node_path8.join)(stage, "package");
13530
+ (0, import_node_fs8.mkdirSync)(packageRoot);
13148
13531
  for (const { alias, directory, sha256 } of selected) {
13149
- if ((0, import_node_fs7.lstatSync)(directory).isSymbolicLink())
13532
+ if ((0, import_node_fs8.lstatSync)(directory).isSymbolicLink())
13150
13533
  throw new Error(`Plugin directory cannot be a symbolic link: ${alias}`);
13151
- const snapshot = (0, import_node_path7.join)(stage, "snapshots", alias);
13152
- (0, import_node_fs7.mkdirSync)(snapshot, { recursive: true });
13534
+ const snapshot = (0, import_node_path8.join)(stage, "snapshots", alias);
13535
+ (0, import_node_fs8.mkdirSync)(snapshot, { recursive: true });
13153
13536
  for (const file of pluginBundleFiles(directory)) {
13154
13537
  safePath(file);
13155
- (0, import_node_fs7.mkdirSync)((0, import_node_path7.dirname)((0, import_node_path7.join)(snapshot, file)), { recursive: true });
13156
- (0, import_node_fs7.writeFileSync)((0, import_node_path7.join)(snapshot, file), (0, import_node_fs7.readFileSync)((0, import_node_path7.join)(directory, file)));
13538
+ (0, import_node_fs8.mkdirSync)((0, import_node_path8.dirname)((0, import_node_path8.join)(snapshot, file)), { recursive: true });
13539
+ (0, import_node_fs8.writeFileSync)((0, import_node_path8.join)(snapshot, file), (0, import_node_fs8.readFileSync)((0, import_node_path8.join)(directory, file)));
13157
13540
  }
13158
13541
  if (hashPluginDir(snapshot) !== sha256) throw new Error(`Plugin integrity mismatch: ${alias}`);
13159
- const library = (0, import_node_path7.join)(snapshot, "library");
13160
- if (!(0, import_node_fs7.existsSync)((0, import_node_path7.join)(library, "index.js")) || !(0, import_node_fs7.existsSync)((0, import_node_path7.join)(library, "index.d.ts")))
13542
+ const library = (0, import_node_path8.join)(snapshot, "library");
13543
+ if (!(0, import_node_fs8.existsSync)((0, import_node_path8.join)(library, "index.js")) || !(0, import_node_fs8.existsSync)((0, import_node_path8.join)(library, "index.d.ts")))
13161
13544
  throw new Error(`Plugin ${alias} has no importable library; rebuild with a compatible CLI`);
13162
13545
  for (const file of pluginFiles(library)) {
13163
- const target = (0, import_node_path7.join)(packageRoot, alias, file);
13164
- (0, import_node_fs7.mkdirSync)((0, import_node_path7.dirname)(target), { recursive: true });
13165
- (0, import_node_fs7.writeFileSync)(target, (0, import_node_fs7.readFileSync)((0, import_node_path7.join)(library, file)));
13166
- (0, import_node_fs7.chmodSync)(target, 420);
13546
+ const target = (0, import_node_path8.join)(packageRoot, alias, file);
13547
+ (0, import_node_fs8.mkdirSync)((0, import_node_path8.dirname)(target), { recursive: true });
13548
+ (0, import_node_fs8.writeFileSync)(target, (0, import_node_fs8.readFileSync)((0, import_node_path8.join)(library, file)));
13549
+ (0, import_node_fs8.chmodSync)(target, 420);
13167
13550
  }
13168
13551
  }
13169
13552
  const subpaths = selected.map(({ alias }) => `./${alias}`);
13170
- (0, import_node_fs7.writeFileSync)(
13171
- (0, import_node_path7.join)(packageRoot, "package.json"),
13553
+ (0, import_node_fs8.writeFileSync)(
13554
+ (0, import_node_path8.join)(packageRoot, "package.json"),
13172
13555
  JSON.stringify(
13173
13556
  {
13174
13557
  name: GENERATED_PLUGIN_PACKAGE,
@@ -13183,8 +13566,8 @@ async function generatePluginPackage(cwd, selections, expectedPacker) {
13183
13566
  2
13184
13567
  ) + "\n"
13185
13568
  );
13186
- (0, import_node_fs7.chmodSync)((0, import_node_path7.join)(packageRoot, "package.json"), 420);
13187
- const archive = (0, import_node_path7.join)(stage, "package.tar");
13569
+ (0, import_node_fs8.chmodSync)((0, import_node_path8.join)(packageRoot, "package.json"), 420);
13570
+ const archive = (0, import_node_path8.join)(stage, "package.tar");
13188
13571
  (0, import_tar.create)(
13189
13572
  {
13190
13573
  file: archive,
@@ -13197,24 +13580,24 @@ async function generatePluginPackage(cwd, selections, expectedPacker) {
13197
13580
  },
13198
13581
  pluginFiles(packageRoot)
13199
13582
  );
13200
- const bytes = (0, import_node_zlib.gzipSync)((0, import_node_fs7.readFileSync)(archive), { level: 0 });
13583
+ const bytes = (0, import_node_zlib.gzipSync)((0, import_node_fs8.readFileSync)(archive), { level: 0 });
13201
13584
  bytes[9] = 255;
13202
- const output = (0, import_node_path7.join)(cwd, GENERATED_PLUGIN_DIRECTORY);
13203
- (0, import_node_fs7.mkdirSync)(output, { recursive: true });
13204
- if ((0, import_node_fs7.lstatSync)(output).isSymbolicLink()) throw new Error("Generated plugin directory cannot be a symbolic link");
13205
- const ignore = (0, import_node_path7.join)(output, ".gitignore");
13206
- if (!(0, import_node_fs7.existsSync)(ignore)) (0, import_node_fs7.writeFileSync)(ignore, "*\n", { flag: "wx" });
13207
- const destination = (0, import_node_path7.join)(output, `plugin-${digest}.tgz`);
13208
- if ((0, import_node_fs7.existsSync)(destination)) {
13209
- if ((0, import_node_fs7.lstatSync)(destination).isSymbolicLink() || !(0, import_node_fs7.readFileSync)(destination).equals(bytes))
13585
+ const output = (0, import_node_path8.join)(cwd, GENERATED_PLUGIN_DIRECTORY);
13586
+ (0, import_node_fs8.mkdirSync)(output, { recursive: true });
13587
+ if ((0, import_node_fs8.lstatSync)(output).isSymbolicLink()) throw new Error("Generated plugin directory cannot be a symbolic link");
13588
+ const ignore = (0, import_node_path8.join)(output, ".gitignore");
13589
+ if (!(0, import_node_fs8.existsSync)(ignore)) (0, import_node_fs8.writeFileSync)(ignore, "*\n", { flag: "wx" });
13590
+ const destination = (0, import_node_path8.join)(output, `plugin-${digest}.tgz`);
13591
+ if ((0, import_node_fs8.existsSync)(destination)) {
13592
+ if ((0, import_node_fs8.lstatSync)(destination).isSymbolicLink() || !(0, import_node_fs8.readFileSync)(destination).equals(bytes))
13210
13593
  throw new Error("Generated plugin package changed; remove the corrupt generated file and restore again");
13211
13594
  } else {
13212
- const temporary = (0, import_node_fs7.mkdtempSync)((0, import_node_path7.join)(output, ".pack-"));
13595
+ const temporary = (0, import_node_fs8.mkdtempSync)((0, import_node_path8.join)(output, ".pack-"));
13213
13596
  try {
13214
- (0, import_node_fs7.writeFileSync)((0, import_node_path7.join)(temporary, "package.tgz"), bytes);
13215
- (0, import_node_fs7.renameSync)((0, import_node_path7.join)(temporary, "package.tgz"), destination);
13597
+ (0, import_node_fs8.writeFileSync)((0, import_node_path8.join)(temporary, "package.tgz"), bytes);
13598
+ (0, import_node_fs8.renameSync)((0, import_node_path8.join)(temporary, "package.tgz"), destination);
13216
13599
  } finally {
13217
- (0, import_node_fs7.rmSync)(temporary, { recursive: true, force: true });
13600
+ (0, import_node_fs8.rmSync)(temporary, { recursive: true, force: true });
13218
13601
  }
13219
13602
  }
13220
13603
  return {
@@ -13222,10 +13605,10 @@ async function generatePluginPackage(cwd, selections, expectedPacker) {
13222
13605
  spec: `file:./${GENERATED_PLUGIN_DIRECTORY}/plugin-${digest}.tgz`,
13223
13606
  subpaths,
13224
13607
  packer,
13225
- sha256: `sha256:${(0, import_node_crypto3.createHash)("sha256").update(bytes).digest("hex")}`
13608
+ sha256: `sha256:${(0, import_node_crypto4.createHash)("sha256").update(bytes).digest("hex")}`
13226
13609
  };
13227
13610
  } finally {
13228
- (0, import_node_fs7.rmSync)(stage, { recursive: true, force: true });
13611
+ (0, import_node_fs8.rmSync)(stage, { recursive: true, force: true });
13229
13612
  }
13230
13613
  }
13231
13614
 
@@ -13234,6 +13617,42 @@ function pluginNpmDependencies(manifest2) {
13234
13617
  return manifest2.integration?.npmDependencies ?? (manifest2.integration?.npm ? [manifest2.integration.npm] : []);
13235
13618
  }
13236
13619
 
13620
+ // packages/plugin/src/prepared/invocation.ts
13621
+ var import_common3 = __toESM(require_dist2());
13622
+ var import_schema5 = __toESM(require_dist());
13623
+
13624
+ // packages/plugin/src/prepared/runtime.ts
13625
+ var import_node_fs9 = require("node:fs");
13626
+ var import_node_path9 = require("node:path");
13627
+ var import_tar2 = require("tar");
13628
+ var import_common2 = __toESM(require_dist2());
13629
+ var import_schema4 = __toESM(require_dist());
13630
+ function preparedRuntime(directory) {
13631
+ const path = (0, import_node_path9.join)(directory, BUILD_RECORD);
13632
+ if (!(0, import_node_fs9.existsSync)(path)) return;
13633
+ const record = JSON.parse((0, import_node_fs9.readFileSync)(path, "utf8"));
13634
+ if (record.runtime === void 0) return;
13635
+ return import_schema4.PreparedPluginRuntime.parse(record.runtime);
13636
+ }
13637
+ function assertPreparedRuntime(runtime) {
13638
+ const libc = process.platform === "linux" && process.report.getReport().header?.glibcVersionRuntime ? "glibc" : "musl";
13639
+ if (Number(process.versions.node.split(".")[0]) !== runtime.nodeMajor || runtime.platform !== "portable" && (runtime.platform !== process.platform || runtime.arch !== process.arch || runtime.platform === "linux" && runtime.libc !== libc))
13640
+ throw new Error("Prepared plugin runtime is incompatible; rebuild for this Node/platform/architecture/libc");
13641
+ }
13642
+
13643
+ // packages/plugin/src/prepared/invocation.ts
13644
+ function usesPreparedRunner(directory) {
13645
+ if (import_common3.PROCESS_ENV.OCTONODE_PLUGIN_RUNNER !== "true") return false;
13646
+ const runtime = preparedRuntime(directory);
13647
+ if (!runtime) return false;
13648
+ assertPreparedRuntime(runtime);
13649
+ const { manifest: manifest2 } = verifyBuild(directory);
13650
+ return !manifest2.permissions.some((permission) => permission.resource === "project_data");
13651
+ }
13652
+ function preparedPluginPin(directory, pin) {
13653
+ return !!pin?.installId && !!pin.registry && pin.registry.replace(/\/$/, "") === (0, import_common3.OCTONODE_MARKETPLACE_URL)()?.replace(/\/$/, "") && usesPreparedRunner(directory);
13654
+ }
13655
+
13237
13656
  // packages/plugin/src/lifecycle.ts
13238
13657
  async function reconcilePluginLock(cwd, next, options = {}) {
13239
13658
  const project = resolveDependencyProject(cwd);
@@ -13243,21 +13662,21 @@ async function reconcilePluginLock(cwd, next, options = {}) {
13243
13662
  const manifest2 = loadPluginManifest(directory);
13244
13663
  if (manifest2.id !== (pin.pluginId ?? alias) || manifest2.version !== pin.version || hashPluginDir(directory) !== pin.sha256)
13245
13664
  throw new Error(`Plugin identity or integrity mismatch: ${alias}`);
13246
- return { alias, directory, sha256: pin.sha256, manifest: manifest2 };
13665
+ return { alias, directory, sha256: pin.sha256, manifest: manifest2, remote: preparedPluginPin(directory, pin) };
13247
13666
  });
13248
13667
  const libraries = loaded.filter((item) => item.manifest.library);
13249
13668
  const generated = libraries.length ? await generatePluginPackage(project.target, libraries) : void 0;
13250
- const packageFile = (0, import_node_path8.join)(project.target, "package.json");
13251
- const packageJson = (0, import_node_fs8.existsSync)(packageFile) ? JSON.parse((0, import_node_fs8.readFileSync)(packageFile, "utf8")) : {};
13669
+ const packageFile = (0, import_node_path10.join)(project.target, "package.json");
13670
+ const packageJson = (0, import_node_fs10.existsSync)(packageFile) ? JSON.parse((0, import_node_fs10.readFileSync)(packageFile, "utf8")) : {};
13252
13671
  const declared = { ...packageJson.devDependencies, ...packageJson.optionalDependencies, ...packageJson.dependencies };
13253
13672
  if (generated && declared[generated.name] && declared[generated.name].replace(/^file:\.\//, "file:") !== before.generated?.spec.replace(/^file:\.\//, "file:") && !options.migrate)
13254
13673
  throw new Error(
13255
13674
  "Existing @octonodes/plugin dependency is not managed by this lock; pass --migrate to replace it explicitly"
13256
13675
  );
13257
- const dependencies = loaded.flatMap(
13676
+ const dependencies = loaded.filter((item) => !item.remote || item.manifest.library).flatMap(
13258
13677
  ({ manifest: manifest2 }) => pluginNpmDependencies(manifest2).map((npm) => {
13259
13678
  const spec = npm.spec.startsWith(`${npm.package}@`) ? npm.spec.slice(npm.package.length + 1) : npm.spec;
13260
- const sameLocal = typeof declared[npm.package] === "string" && declared[npm.package].startsWith("file:") && spec.startsWith("file:") && (0, import_node_path8.resolve)(project.target, declared[npm.package].slice(5)) === (0, import_node_path8.resolve)(project.target, spec.slice(5));
13679
+ const sameLocal = typeof declared[npm.package] === "string" && declared[npm.package].startsWith("file:") && spec.startsWith("file:") && (0, import_node_path10.resolve)(project.target, declared[npm.package].slice(5)) === (0, import_node_path10.resolve)(project.target, spec.slice(5));
13261
13680
  if (declared[npm.package] && declared[npm.package] !== spec && !sameLocal)
13262
13681
  throw new Error(
13263
13682
  `Dependency conflict: ${npm.package} is ${declared[npm.package]}, plugin requires ${spec}; reconcile it explicitly first`
@@ -13276,6 +13695,7 @@ async function reconcilePluginLock(cwd, next, options = {}) {
13276
13695
  if (generated || before.generated || unique.length || options.commit) {
13277
13696
  await reconcileDependencies(project.target, [...unique, ...generated ? [generated] : []], {
13278
13697
  cacheRoot: options.cacheRoot,
13698
+ metadataOnly: !generated && !before.generated && !unique.length,
13279
13699
  remove: !generated && before.generated ? [before.generated.name] : void 0,
13280
13700
  transactionFiles: [lockfilePath(cwd), ...options.transactionFiles ?? []],
13281
13701
  commit: () => {
@@ -13318,20 +13738,20 @@ async function removePluginPin(alias, options = {}) {
13318
13738
  }
13319
13739
 
13320
13740
  // packages/plugin/src/restore.ts
13321
- var import_node_fs12 = require("node:fs");
13322
- var import_node_path12 = require("node:path");
13741
+ var import_node_fs14 = require("node:fs");
13742
+ var import_node_path14 = require("node:path");
13323
13743
 
13324
- // packages/plugin/src/remote-registry.ts
13325
- var import_node_fs11 = require("node:fs");
13326
- var import_node_os5 = require("node:os");
13327
- var import_node_path11 = require("node:path");
13744
+ // packages/plugin/src/remote/registry.ts
13745
+ var import_node_fs13 = require("node:fs");
13746
+ var import_node_os6 = require("node:os");
13747
+ var import_node_path13 = require("node:path");
13328
13748
 
13329
13749
  // packages/plugin/src/install.ts
13330
- var import_node_fs9 = require("node:fs");
13331
- var import_node_path9 = require("node:path");
13750
+ var import_node_fs11 = require("node:fs");
13751
+ var import_node_path11 = require("node:path");
13332
13752
  var import_node_child_process2 = require("node:child_process");
13333
13753
  var import_node_util2 = require("node:util");
13334
- var import_common2 = __toESM(require_dist3());
13754
+ var import_common4 = __toESM(require_dist2());
13335
13755
  function commandError(err) {
13336
13756
  const error = err;
13337
13757
  return [error.stderr, error.stdout].map((output) => output?.toString().trim()).find(Boolean) ?? error.message;
@@ -13347,7 +13767,7 @@ async function installNodeDeps(dir, opts = {}) {
13347
13767
  if (opts.cacheOnly) {
13348
13768
  for (const npm of dependencies)
13349
13769
  await (0, import_node_util2.promisify)(import_node_child_process2.execFile)("npm", ["cache", "add", "--ignore-scripts", "--", npm.spec], {
13350
- env: (0, import_common2.childProcessEnvironment)((0, import_common2.packageCacheEnvironment)(dependencyCacheRoot(opts.cacheRoot))),
13770
+ env: (0, import_common4.childProcessEnvironment)((0, import_common4.packageCacheEnvironment)(dependencyCacheRoot(opts.cacheRoot))),
13351
13771
  timeout: 10 * 6e4
13352
13772
  });
13353
13773
  return {};
@@ -13364,9 +13784,9 @@ async function installNodeDeps(dir, opts = {}) {
13364
13784
  return { depsInstalled: false, depsError: commandError(err) };
13365
13785
  }
13366
13786
  }
13367
- const pjPath = (0, import_node_path9.join)(dir, "package.json");
13368
- if (!(0, import_node_fs9.existsSync)(pjPath)) return {};
13369
- const pj = JSON.parse((0, import_node_fs9.readFileSync)(pjPath, "utf8"));
13787
+ const pjPath = (0, import_node_path11.join)(dir, "package.json");
13788
+ if (!(0, import_node_fs11.existsSync)(pjPath)) return {};
13789
+ const pj = JSON.parse((0, import_node_fs11.readFileSync)(pjPath, "utf8"));
13370
13790
  if (!pj.dependencies && !pj.optionalDependencies) return {};
13371
13791
  try {
13372
13792
  await (0, import_node_util2.promisify)(import_node_child_process2.execFile)(
@@ -13382,7 +13802,7 @@ async function installNodeDeps(dir, opts = {}) {
13382
13802
  ],
13383
13803
  {
13384
13804
  cwd: dir,
13385
- env: (0, import_common2.childProcessEnvironment)((0, import_common2.packageCacheEnvironment)(dependencyCacheRoot(opts.cacheRoot))),
13805
+ env: (0, import_common4.childProcessEnvironment)((0, import_common4.packageCacheEnvironment)(dependencyCacheRoot(opts.cacheRoot))),
13386
13806
  timeout: 10 * 6e4
13387
13807
  }
13388
13808
  );
@@ -13392,7 +13812,7 @@ async function installNodeDeps(dir, opts = {}) {
13392
13812
  }
13393
13813
  }
13394
13814
  async function installPlugin(src, opts = {}) {
13395
- if (!(0, import_node_fs9.existsSync)(src) || !(0, import_node_fs9.statSync)(src).isDirectory()) {
13815
+ if (!(0, import_node_fs11.existsSync)(src) || !(0, import_node_fs11.statSync)(src).isDirectory()) {
13396
13816
  throw new Error(`source "${src}" is not a directory`);
13397
13817
  }
13398
13818
  if (!isPluginDir(src)) {
@@ -13400,17 +13820,17 @@ async function installPlugin(src, opts = {}) {
13400
13820
  }
13401
13821
  const { manifest: manifest2 } = loadPlugin(src);
13402
13822
  const { root, source } = installRoot(opts);
13403
- const dest = (0, import_node_path9.join)(root, manifest2.id);
13404
- if ((0, import_node_fs9.existsSync)(dest)) {
13823
+ const dest = (0, import_node_path11.join)(root, manifest2.id);
13824
+ if ((0, import_node_fs11.existsSync)(dest)) {
13405
13825
  if (!opts.force) {
13406
13826
  throw new Error(`plugin "${manifest2.id}" is already installed at ${dest} (use --force to overwrite)`);
13407
13827
  }
13408
13828
  }
13409
13829
  const deps = pluginNpmDependencies(manifest2).length ? await installNodeDeps(src, { ...opts, cacheOnly: opts.cacheOnly ?? !opts.project }) : {};
13410
13830
  if (deps.depsError) return { manifest: manifest2, dir: dest, source, ...deps };
13411
- if ((0, import_node_fs9.existsSync)(dest)) (0, import_node_fs9.rmSync)(dest, { recursive: true, force: true });
13412
- (0, import_node_fs9.mkdirSync)(root, { recursive: true });
13413
- (0, import_node_fs9.cpSync)(src, dest, { recursive: true });
13831
+ if ((0, import_node_fs11.existsSync)(dest)) (0, import_node_fs11.rmSync)(dest, { recursive: true, force: true });
13832
+ (0, import_node_fs11.mkdirSync)(root, { recursive: true });
13833
+ (0, import_node_fs11.cpSync)(src, dest, { recursive: true });
13414
13834
  return {
13415
13835
  manifest: manifest2,
13416
13836
  dir: dest,
@@ -13420,14 +13840,14 @@ async function installPlugin(src, opts = {}) {
13420
13840
  };
13421
13841
  }
13422
13842
 
13423
- // packages/plugin/src/remote-registry.ts
13424
- var import_common3 = __toESM(require_dist3());
13843
+ // packages/plugin/src/remote/registry.ts
13844
+ var import_common5 = __toESM(require_dist2());
13425
13845
 
13426
13846
  // packages/plugin/src/archive.ts
13427
13847
  var import_node_zlib2 = require("node:zlib");
13428
- var import_node_fs10 = require("node:fs");
13429
- var import_node_path10 = require("node:path");
13430
- var import_tar2 = require("tar");
13848
+ var import_node_fs12 = require("node:fs");
13849
+ var import_node_path12 = require("node:path");
13850
+ var import_tar3 = require("tar");
13431
13851
 
13432
13852
  // packages/plugin/src/archive.constants.ts
13433
13853
  var PLUGIN_ARCHIVE_MAX_BYTES = 64 * 1024 * 1024;
@@ -13437,11 +13857,11 @@ var PLUGIN_ARCHIVE_MAX_FILES = 1e4;
13437
13857
  function extractPluginArchive(bytes, stage) {
13438
13858
  if (bytes.length > PLUGIN_ARCHIVE_MAX_BYTES) throw new Error("Plugin archive exceeds download limit");
13439
13859
  const decoded = (0, import_node_zlib2.gunzipSync)(bytes, { maxOutputLength: PLUGIN_ARCHIVE_MAX_BYTES });
13440
- const archive = (0, import_node_path10.join)(stage, "bundle.tar");
13441
- (0, import_node_fs10.writeFileSync)(archive, decoded);
13860
+ const archive = (0, import_node_path12.join)(stage, "bundle.tar");
13861
+ (0, import_node_fs12.writeFileSync)(archive, decoded);
13442
13862
  const seen = /* @__PURE__ */ new Set();
13443
13863
  let total = 0;
13444
- (0, import_tar2.list)({
13864
+ (0, import_tar3.list)({
13445
13865
  file: archive,
13446
13866
  sync: true,
13447
13867
  strict: true,
@@ -13458,9 +13878,9 @@ function extractPluginArchive(bytes, stage) {
13458
13878
  throw new Error("Plugin archive exceeds extraction limits");
13459
13879
  }
13460
13880
  });
13461
- const output = (0, import_node_path10.join)(stage, "plugin");
13462
- (0, import_node_fs10.mkdirSync)(output);
13463
- (0, import_tar2.extract)({
13881
+ const output = (0, import_node_path12.join)(stage, "plugin");
13882
+ (0, import_node_fs12.mkdirSync)(output);
13883
+ (0, import_tar3.extract)({
13464
13884
  file: archive,
13465
13885
  cwd: output,
13466
13886
  sync: true,
@@ -13473,11 +13893,12 @@ function extractPluginArchive(bytes, stage) {
13473
13893
  return output;
13474
13894
  }
13475
13895
 
13476
- // packages/plugin/src/remote-registry.ts
13477
- var import_tar3 = require("tar");
13896
+ // packages/plugin/src/remote/registry.ts
13897
+ var import_tar4 = require("tar");
13898
+ var import_node_crypto5 = require("node:crypto");
13478
13899
  var RemoteRegistry = class {
13479
13900
  constructor(opts = {}) {
13480
- const baseUrl = opts.baseUrl ?? (0, import_common3.OCTONODE_MARKETPLACE_URL)();
13901
+ const baseUrl = opts.baseUrl ?? (0, import_common5.OCTONODE_MARKETPLACE_URL)();
13481
13902
  if (!baseUrl) {
13482
13903
  throw new Error("marketplace URL is not configured (set OCTONODE_MARKETPLACE_URL or pass baseUrl)");
13483
13904
  }
@@ -13487,7 +13908,7 @@ var RemoteRegistry = class {
13487
13908
  );
13488
13909
  }
13489
13910
  this.baseUrl = baseUrl.replace(/\/$/, "");
13490
- this.token = opts.token ?? (0, import_common3.OCTONODE_MARKETPLACE_TOKEN)();
13911
+ this.token = opts.token ?? (0, import_common5.OCTONODE_MARKETPLACE_TOKEN)();
13491
13912
  }
13492
13913
  async request(path, init = {}) {
13493
13914
  const headers = new Headers(init.headers);
@@ -13504,19 +13925,49 @@ var RemoteRegistry = class {
13504
13925
  }
13505
13926
  return res;
13506
13927
  }
13928
+ async searchPage(filter = {}, offset = 0, limit = 24) {
13929
+ const params = new URLSearchParams({ offset: String(offset), limit: String(limit) });
13930
+ for (const [key, value] of Object.entries(filter)) if (value !== void 0) params.set(key, value);
13931
+ const res = await this.request(`/marketplace/plugins?${params}`);
13932
+ return await res.json();
13933
+ }
13507
13934
  async search(filter = {}) {
13508
- const params = new URLSearchParams();
13509
- for (const [key, value] of Object.entries(filter)) if (value) params.set(key, value);
13510
- const query = params.size > 0 ? `?${params}` : "";
13511
- const res = await this.request(`/marketplace/plugins${query}`);
13512
- const body = await res.json();
13513
- return body.entries;
13935
+ let entries = [];
13936
+ for (; ; ) {
13937
+ const page = await this.searchPage(filter, entries.length, 100);
13938
+ entries = [...entries, ...page.entries];
13939
+ if (!page.entries.length || page.total === void 0 || entries.length >= page.total) return entries;
13940
+ }
13514
13941
  }
13515
13942
  async detail(id, scope) {
13516
13943
  const query = scope ? `?scope=${encodeURIComponent(scope)}` : "";
13517
13944
  const res = await this.request(`/marketplace/plugins/${encodeURIComponent(id)}${query}`);
13518
13945
  return await res.json();
13519
13946
  }
13947
+ /** Reauthorize an immutable pin, including older locks that only recorded the extracted tree hash. */
13948
+ async matchesLockedRelease(id, pin) {
13949
+ const remoteId = pin.remoteId ?? id;
13950
+ const detail = await this.detail(remoteId, pin.scope);
13951
+ const release2 = detail.versions.find((entry) => entry.version === pin.version);
13952
+ if (!release2 || pin.publisher && release2.publishedBy !== pin.publisher) return false;
13953
+ const checksum = release2.archiveSha256 ?? release2.sha256;
13954
+ if (pin.archiveSha256 || checksum?.startsWith("sha256:")) return checksum === (pin.archiveSha256 ?? pin.sha256);
13955
+ if (!/^[a-f0-9]{64}$/.test(checksum)) return false;
13956
+ const directory = await this.downloadBundle(remoteId, pin.version, pin.scope, id, checksum);
13957
+ try {
13958
+ return hashPluginDir(directory) === pin.sha256;
13959
+ } finally {
13960
+ (0, import_node_fs13.rmSync)((0, import_node_path13.dirname)(directory), { recursive: true, force: true });
13961
+ }
13962
+ }
13963
+ async registerInstall(id, version, scope, opts) {
13964
+ const response = await this.request(`/marketplace/plugins/${encodeURIComponent(id)}/install`, {
13965
+ method: "POST",
13966
+ headers: { "content-type": "application/json" },
13967
+ body: JSON.stringify({ version, scope, ownerId: opts.ownerId, environment: opts.environment ?? "self_hosted" })
13968
+ });
13969
+ return (await response.json()).installId;
13970
+ }
13520
13971
  /**
13521
13972
  * Pack a plugin folder into a tarball and publish it (metadata + bundle).
13522
13973
  * `orgId` names the org an org/group-scoped version belongs to; `teamId`
@@ -13526,6 +13977,13 @@ var RemoteRegistry = class {
13526
13977
  */
13527
13978
  async publish(pluginDir, opts = {}) {
13528
13979
  const manifest2 = loadPluginManifest(pluginDir);
13980
+ const packageFile = (0, import_node_path13.join)(pluginDir, "package.json");
13981
+ if ((0, import_node_fs13.existsSync)(packageFile)) {
13982
+ const metadata = JSON.parse((0, import_node_fs13.readFileSync)(packageFile, "utf8"));
13983
+ if (metadata.version && metadata.version !== manifest2.version) {
13984
+ throw new Error("package.json version must match the plugin version before publishing");
13985
+ }
13986
+ }
13529
13987
  const bundle = packPluginDir(pluginDir);
13530
13988
  const form = new FormData();
13531
13989
  form.set("manifest", JSON.stringify(manifest2));
@@ -13536,10 +13994,14 @@ var RemoteRegistry = class {
13536
13994
  method: "POST",
13537
13995
  body: form
13538
13996
  });
13539
- return await res.json();
13997
+ const release2 = await res.json();
13998
+ const digest = (0, import_node_crypto5.createHash)("sha256").update(bundle).digest("hex");
13999
+ if (release2.sha256 !== digest || release2.archiveSha256 !== void 0 && release2.archiveSha256 !== digest)
14000
+ throw new Error("Marketplace published archive checksum mismatch; check the release before publishing again");
14001
+ return release2;
13540
14002
  }
13541
14003
  /** Download a version's bundle and extract it to a fresh temp folder. */
13542
- async downloadBundle(id, version, scope, expectedId = id) {
14004
+ async downloadBundle(id, version, scope, expectedId = id, expectedChecksum) {
13543
14005
  const query = scope ? `?scope=${encodeURIComponent(scope)}` : "";
13544
14006
  const res = await this.request(
13545
14007
  `/marketplace/plugins/${encodeURIComponent(id)}/versions/${encodeURIComponent(version)}/bundle${query}`
@@ -13560,17 +14022,27 @@ var RemoteRegistry = class {
13560
14022
  await reader.cancel();
13561
14023
  }
13562
14024
  const bytes = Buffer.concat(chunks);
13563
- const dir = (0, import_node_fs11.mkdtempSync)((0, import_node_path11.join)((0, import_node_os5.tmpdir)(), "octo-bundle-"));
14025
+ const archiveChecksum = res.headers.get("x-octonode-archive-sha256");
14026
+ if (archiveChecksum !== null && !/^[a-f0-9]{64}$/.test(archiveChecksum))
14027
+ throw new Error("Plugin registry archive checksum is invalid");
14028
+ const checksums = [archiveChecksum, res.headers.get("x-octonode-sha256"), expectedChecksum].filter(
14029
+ (checksum) => !!checksum
14030
+ );
14031
+ const digest = (0, import_node_crypto5.createHash)("sha256").update(bytes).digest("hex");
14032
+ for (const expected of checksums)
14033
+ if (/^[a-f0-9]{64}$/.test(expected) && expected !== digest) throw new Error("Plugin registry checksum mismatch");
14034
+ const dir = (0, import_node_fs13.mkdtempSync)((0, import_node_path13.join)((0, import_node_os6.tmpdir)(), "octo-bundle-"));
13564
14035
  try {
13565
14036
  const extracted = extractPluginArchive(bytes, dir);
13566
14037
  const manifest2 = loadPluginManifest(extracted);
13567
14038
  if (manifest2.id !== expectedId || manifest2.version !== version)
13568
14039
  throw new Error(`Downloaded plugin does not match requested ${id}@${version}`);
13569
- const checksum = res.headers.get("x-octonode-sha256");
13570
- if (checksum && hashPluginDir(extracted) !== checksum) throw new Error("Plugin registry checksum mismatch");
14040
+ for (const expected of checksums)
14041
+ if (!/^[a-f0-9]{64}$/.test(expected) && hashPluginDir(extracted) !== expected)
14042
+ throw new Error("Plugin registry checksum mismatch");
13571
14043
  return extracted;
13572
14044
  } catch (error) {
13573
- (0, import_node_fs11.rmSync)(dir, { recursive: true, force: true });
14045
+ (0, import_node_fs13.rmSync)(dir, { recursive: true, force: true });
13574
14046
  throw error;
13575
14047
  }
13576
14048
  }
@@ -13582,7 +14054,14 @@ var RemoteRegistry = class {
13582
14054
  async install(id, opts = {}) {
13583
14055
  const detail = await this.detail(id, opts.scope);
13584
14056
  const version = opts.version ?? detail.version;
13585
- const dir = await this.downloadBundle(id, version, opts.scope);
14057
+ const release2 = detail.versions?.find((entry) => entry.version === version);
14058
+ const dir = await this.downloadBundle(
14059
+ id,
14060
+ version,
14061
+ opts.scope,
14062
+ id,
14063
+ release2?.archiveSha256 ?? release2?.sha256
14064
+ );
13586
14065
  const plugin = await installPlugin(dir, opts);
13587
14066
  const res = await this.request(`/marketplace/plugins/${encodeURIComponent(id)}/install`, {
13588
14067
  method: "POST",
@@ -13608,19 +14087,21 @@ var RemoteRegistry = class {
13608
14087
  const detail = await this.detail(id, opts.scope);
13609
14088
  const version = opts.version ?? detail.version;
13610
14089
  const versionMeta = detail.versions?.find((v) => v.version === version);
13611
- if (!opts.cacheOnly && !opts.noDeps && !versionMeta?.sha256)
14090
+ const releaseChecksum = versionMeta?.archiveSha256 ?? versionMeta?.sha256;
14091
+ if (!opts.cacheOnly && !opts.noDeps && !releaseChecksum)
13612
14092
  throw new Error("Marketplace release is missing its immutable checksum");
13613
14093
  const availableScopes = versionMeta?.scope ?? detail.scope;
13614
14094
  const scope = opts.scope && availableScopes.includes(opts.scope) ? opts.scope : availableScopes[0];
13615
- const dir = await this.downloadBundle(id, version, scope);
14095
+ const dir = await this.downloadBundle(id, version, scope, id, releaseChecksum);
13616
14096
  const entry = (() => {
13617
14097
  try {
13618
14098
  return addToStore(dir, { storeRoot: opts.storeRoot });
13619
14099
  } finally {
13620
- (0, import_node_fs11.rmSync)((0, import_node_path11.dirname)(dir), { recursive: true, force: true });
14100
+ (0, import_node_fs13.rmSync)((0, import_node_path13.dirname)(dir), { recursive: true, force: true });
13621
14101
  }
13622
14102
  })();
13623
- if (versionMeta?.sha256 && entry.sha256 !== versionMeta.sha256) throw new Error("Plugin release checksum mismatch");
14103
+ const archiveSha256 = releaseChecksum && /^[a-f0-9]{64}$/.test(releaseChecksum) ? releaseChecksum : void 0;
14104
+ const prepared = this.baseUrl === (0, import_common5.OCTONODE_MARKETPLACE_URL)()?.replace(/\/$/, "") && usesPreparedRunner(entry.dir);
13624
14105
  if (entry.manifest.library && opts.noDeps && !opts.cacheOnly)
13625
14106
  throw new Error(
13626
14107
  "Library installation requires native dependency activation; use frozen --artifacts-only for CI restore"
@@ -13632,26 +14113,29 @@ var RemoteRegistry = class {
13632
14113
  remoteId: id,
13633
14114
  version: entry.version,
13634
14115
  sha256: entry.sha256,
14116
+ archiveSha256,
13635
14117
  registry: this.baseUrl,
13636
14118
  scope,
13637
14119
  permissions: versionMeta?.permissions ?? detail.permissions,
13638
14120
  publisher: versionMeta?.publishedBy
13639
14121
  };
13640
- await activatePluginPin(alias2, pin2, opts);
13641
14122
  let installId2 = "";
13642
- if (!opts.dryRun) {
14123
+ if (prepared && !opts.dryRun) {
14124
+ installId2 = await this.registerInstall(id, version, scope, { ...opts, environment: "cloud" });
14125
+ if (!installId2 || !/^[a-f0-9-]{36}$/.test(installId2))
14126
+ throw new Error("Marketplace did not authorize the prepared installation");
14127
+ pin2.installId = installId2;
14128
+ }
14129
+ try {
14130
+ await activatePluginPin(alias2, pin2, opts);
14131
+ } catch (error) {
14132
+ if (installId2) await this.postEvent(installId2, "uninstall").catch(() => {
14133
+ });
14134
+ throw error;
14135
+ }
14136
+ if (!opts.dryRun && !prepared) {
13643
14137
  try {
13644
- const response = await this.request(`/marketplace/plugins/${encodeURIComponent(id)}/install`, {
13645
- method: "POST",
13646
- headers: { "content-type": "application/json" },
13647
- body: JSON.stringify({
13648
- version,
13649
- scope,
13650
- ownerId: opts.ownerId,
13651
- environment: opts.environment ?? "self_hosted"
13652
- })
13653
- });
13654
- installId2 = (await response.json()).installId;
14138
+ installId2 = await this.registerInstall(id, version, scope, opts);
13655
14139
  if (installId2)
13656
14140
  await withDependencyInstall(opts.cwd ?? process.cwd(), async () => {
13657
14141
  const current = readLockfile(opts.cwd).plugins[alias2];
@@ -13665,10 +14149,10 @@ var RemoteRegistry = class {
13665
14149
  plugin: { manifest: entry.manifest, dir: entry.dir, source: "store" },
13666
14150
  entry,
13667
14151
  installId: installId2,
13668
- depsInstalled: !opts.dryRun
14152
+ depsInstalled: !opts.dryRun && (!prepared || !!entry.manifest.library)
13669
14153
  };
13670
14154
  }
13671
- const deps = entry.created || entry.manifest.integration?.npm ? await installNodeDeps(entry.dir, {
14155
+ const deps = !prepared && (entry.created || entry.manifest.integration?.npm) ? await installNodeDeps(entry.dir, {
13672
14156
  noDeps: opts.noDeps,
13673
14157
  cwd: opts.cwd,
13674
14158
  cacheRoot: opts.cacheRoot,
@@ -13681,25 +14165,36 @@ var RemoteRegistry = class {
13681
14165
  remoteId: id,
13682
14166
  version: entry.version,
13683
14167
  sha256: entry.sha256,
14168
+ archiveSha256,
13684
14169
  registry: this.baseUrl,
13685
14170
  scope,
13686
14171
  publisher: versionMeta?.publishedBy,
13687
14172
  permissions: versionMeta?.permissions ?? detail.permissions
13688
14173
  };
13689
- await withDependencyInstall(opts.cwd ?? process.cwd(), async () => {
13690
- const previous = readLockfile(opts.cwd).plugins[alias];
13691
- if (previous && ((previous.pluginId ?? alias) !== entry.id || previous.registry !== this.baseUrl || previous.publisher !== pin.publisher))
13692
- throw new Error("Plugin alias belongs to another publisher or registry");
13693
- upsertLockEntry(opts.cwd ?? process.cwd(), alias, pin);
13694
- });
14174
+ if (opts.dryRun)
14175
+ return { plugin: { manifest: entry.manifest, dir: entry.dir, source: "store" }, entry, installId: "" };
13695
14176
  let installId = "";
14177
+ if (prepared) {
14178
+ installId = await this.registerInstall(id, version, scope, { ...opts, environment: "cloud" });
14179
+ if (!installId || !/^[a-f0-9-]{36}$/.test(installId))
14180
+ throw new Error("Marketplace did not authorize the prepared installation");
14181
+ pin.installId = installId;
14182
+ }
13696
14183
  try {
13697
- const response = await this.request(`/marketplace/plugins/${encodeURIComponent(id)}/install`, {
13698
- method: "POST",
13699
- headers: { "content-type": "application/json" },
13700
- body: JSON.stringify({ version, scope, ownerId: opts.ownerId, environment: opts.environment ?? "self_hosted" })
14184
+ await withDependencyInstall(opts.cwd ?? process.cwd(), async () => {
14185
+ const previous = readLockfile(opts.cwd).plugins[alias];
14186
+ if (previous && ((previous.pluginId ?? alias) !== entry.id || previous.registry !== this.baseUrl || previous.publisher !== pin.publisher))
14187
+ throw new Error("Plugin alias belongs to another publisher or registry");
14188
+ upsertLockEntry(opts.cwd ?? process.cwd(), alias, pin);
14189
+ });
14190
+ } catch (error) {
14191
+ if (installId) await this.postEvent(installId, "uninstall").catch(() => {
13701
14192
  });
13702
- installId = (await response.json()).installId;
14193
+ throw error;
14194
+ }
14195
+ if (prepared) return { plugin: { manifest: entry.manifest, dir: entry.dir, source: "store" }, entry, installId };
14196
+ try {
14197
+ installId = await this.registerInstall(id, version, scope, opts);
13703
14198
  await withDependencyInstall(opts.cwd ?? process.cwd(), async () => {
13704
14199
  const current = readLockfile(opts.cwd).plugins[alias];
13705
14200
  if (current?.sha256 === pin.sha256 && current.registry === pin.registry)
@@ -13725,13 +14220,13 @@ var RemoteRegistry = class {
13725
14220
  };
13726
14221
  function packPluginDir(pluginDir) {
13727
14222
  pluginBundleFiles(pluginDir);
13728
- const staging = (0, import_node_fs11.mkdtempSync)((0, import_node_path11.join)((0, import_node_os5.tmpdir)(), "octo-pack-"));
13729
- const out = (0, import_node_path11.join)(staging, "bundle.tar.gz");
14223
+ const staging = (0, import_node_fs13.mkdtempSync)((0, import_node_path13.join)((0, import_node_os6.tmpdir)(), "octo-pack-"));
14224
+ const out = (0, import_node_path13.join)(staging, "bundle.tar.gz");
13730
14225
  try {
13731
- (0, import_tar3.create)({ file: out, cwd: pluginDir, sync: true, portable: true, gzip: true }, pluginBundleFiles(pluginDir));
13732
- return (0, import_node_fs11.readFileSync)(out);
14226
+ (0, import_tar4.create)({ file: out, cwd: pluginDir, sync: true, portable: true, gzip: true }, pluginBundleFiles(pluginDir));
14227
+ return (0, import_node_fs13.readFileSync)(out);
13733
14228
  } finally {
13734
- (0, import_node_fs11.rmSync)(staging, { recursive: true, force: true });
14229
+ (0, import_node_fs13.rmSync)(staging, { recursive: true, force: true });
13735
14230
  }
13736
14231
  }
13737
14232
 
@@ -13739,7 +14234,7 @@ function packPluginDir(pluginDir) {
13739
14234
  async function installFromLock(opts = {}) {
13740
14235
  const cwd = resolveDependencyProject(opts.cwd ?? process.cwd()).target;
13741
14236
  if (opts.frozen && opts.force) throw new Error("Frozen restore cannot accept changed artifact bytes");
13742
- if (opts.frozen && !(0, import_node_fs12.existsSync)((0, import_node_path12.join)(cwd, "octonode.lock"))) throw new Error("Frozen restore requires octonode.lock");
14237
+ if (opts.frozen && !(0, import_node_fs14.existsSync)((0, import_node_path14.join)(cwd, "octonode.lock"))) throw new Error("Frozen restore requires octonode.lock");
13743
14238
  return withDependencyInstall(cwd, async () => {
13744
14239
  const lock = readLockfile(cwd);
13745
14240
  if (lock.generated && opts.force)
@@ -13756,9 +14251,8 @@ async function installFromLock(opts = {}) {
13756
14251
  throw new Error("Frozen restore cannot change the registry");
13757
14252
  if (pin.scope && pin.scope !== "public" && registry) {
13758
14253
  if (opts.offline) throw new Error("Private plugin access must be reauthorized online before restore");
13759
- const detail = await new RemoteRegistry({ baseUrl: registry, token: opts.token }).detail(remoteId, pin.scope);
13760
- const version = detail.versions.find((item) => item.version === pin.version);
13761
- if (!version || version.sha256 !== pin.sha256 || pin.publisher && version.publishedBy !== pin.publisher)
14254
+ const remote = new RemoteRegistry({ baseUrl: registry, token: opts.token });
14255
+ if (!await remote.matchesLockedRelease(id, pin))
13762
14256
  throw new Error("Locked private release is not authorized or changed");
13763
14257
  }
13764
14258
  let directory = storeEntryDir(id, pin.version, pin.sha256, opts.storeRoot);
@@ -13772,16 +14266,18 @@ async function installFromLock(opts = {}) {
13772
14266
  remoteId,
13773
14267
  pin.version,
13774
14268
  pin.scope,
13775
- id
14269
+ id,
14270
+ opts.force ? void 0 : pin.archiveSha256
13776
14271
  );
13777
14272
  try {
13778
14273
  const actual = hashPluginDir(downloaded);
13779
14274
  if (actual !== pin.sha256 && !opts.force) throw new Error("integrity mismatch for " + alias);
13780
14275
  const entry = addToStore(downloaded, { storeRoot: opts.storeRoot });
13781
14276
  directory = entry.dir;
13782
- if (actual !== pin.sha256) upsertLockEntry(cwd, alias, { ...pin, sha256: actual });
14277
+ if (actual !== pin.sha256)
14278
+ upsertLockEntry(cwd, alias, { ...pin, sha256: actual, archiveSha256: void 0 });
13783
14279
  } finally {
13784
- (0, import_node_fs12.rmSync)((0, import_node_path12.dirname)(downloaded), { recursive: true, force: true });
14280
+ (0, import_node_fs14.rmSync)((0, import_node_path14.dirname)(downloaded), { recursive: true, force: true });
13785
14281
  }
13786
14282
  result.restored.push(alias);
13787
14283
  }
@@ -13789,9 +14285,10 @@ async function installFromLock(opts = {}) {
13789
14285
  if (manifest2.id !== id || manifest2.version !== pin.version)
13790
14286
  throw new Error("Plugin identity mismatch: " + alias);
13791
14287
  if (manifest2.library) libraries.push({ alias, directory, sha256: pin.sha256 });
14288
+ if (!manifest2.library && preparedPluginPin(directory, pin)) continue;
13792
14289
  if (!manifest2.library && !pluginNpmDependencies(manifest2).length && !opts.artifactsOnly && !opts.noDeps) {
13793
- const packagePath = (0, import_node_path12.join)(directory, "package.json");
13794
- const legacy = (0, import_node_fs12.existsSync)(packagePath) ? JSON.parse((0, import_node_fs12.readFileSync)(packagePath, "utf8")) : {};
14290
+ const packagePath = (0, import_node_path14.join)(directory, "package.json");
14291
+ const legacy = (0, import_node_fs14.existsSync)(packagePath) ? JSON.parse((0, import_node_fs14.readFileSync)(packagePath, "utf8")) : {};
13795
14292
  if (legacy.dependencies || legacy.optionalDependencies) {
13796
14293
  if (opts.frozen || opts.offline)
13797
14294
  throw new Error(
@@ -13818,7 +14315,7 @@ async function installFromLock(opts = {}) {
13818
14315
  const generated = await generatePluginPackage(cwd, libraries, lock.generated.packer);
13819
14316
  if (generated.spec !== lock.generated.spec || generated.sha256 !== lock.generated.sha256 || JSON.stringify(generated.subpaths) !== JSON.stringify(lock.generated.subpaths))
13820
14317
  throw new Error("Generated package does not match octonode.lock");
13821
- const manifest2 = JSON.parse((0, import_node_fs12.readFileSync)((0, import_node_path12.join)(cwd, "package.json"), "utf8"));
14318
+ const manifest2 = JSON.parse((0, import_node_fs14.readFileSync)((0, import_node_path14.join)(cwd, "package.json"), "utf8"));
13822
14319
  if (manifest2.dependencies?.[generated.name]?.replace(/^file:\.\//, "file:") !== generated.spec.replace(/^file:\.\//, "file:"))
13823
14320
  throw new Error("package.json disagrees with octonode.lock");
13824
14321
  }
@@ -13838,11 +14335,11 @@ async function installFromLock(opts = {}) {
13838
14335
  }
13839
14336
 
13840
14337
  // packages/plugin/src/consumer/lifecycle.ts
13841
- var import_schema4 = __toESM(require_dist());
14338
+ var import_schema6 = __toESM(require_dist());
13842
14339
  async function runPluginLifecycle(command, target, flags) {
13843
- const cwd = resolveDependencyProject(typeof flags.cwd === "string" ? (0, import_node_path13.resolve)(flags.cwd) : process.cwd()).target;
14340
+ const cwd = resolveDependencyProject(typeof flags.cwd === "string" ? (0, import_node_path15.resolve)(flags.cwd) : process.cwd()).target;
13844
14341
  const scope = typeof flags.scope === "string" ? flags.scope : void 0;
13845
- if (scope && !import_schema4.MARKETPLACE_SCOPES.includes(scope)) throw new Error("Invalid marketplace scope");
14342
+ if (scope && !import_schema6.MARKETPLACE_SCOPES.includes(scope)) throw new Error("Invalid marketplace scope");
13846
14343
  const options = {
13847
14344
  cwd,
13848
14345
  alias: typeof flags.alias === "string" ? flags.alias : void 0,
@@ -13870,8 +14367,8 @@ async function runPluginLifecycle(command, target, flags) {
13870
14367
  await removePluginPin(target, options);
13871
14368
  return { removed: target, dryRun: options.dryRun };
13872
14369
  }
13873
- if (command === "install" && (0, import_node_fs13.existsSync)((0, import_node_path13.resolve)(cwd, target))) {
13874
- const entry = await installLocalArtifact((0, import_node_path13.resolve)(cwd, target), options);
14370
+ if (command === "install" && (0, import_node_fs15.existsSync)((0, import_node_path15.resolve)(cwd, target))) {
14371
+ const entry = await installLocalArtifact((0, import_node_path15.resolve)(cwd, target), options);
13875
14372
  return { id: options.alias ?? entry.id, version: entry.version, sha256: entry.sha256, dryRun: options.dryRun };
13876
14373
  }
13877
14374
  if (command !== "install" && command !== "update") throw new Error(`Unknown plugin lifecycle command: ${command}`);