witnora 0.20.16 → 0.20.17

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.
@@ -23,8 +23,9 @@ export async function saveConnection(name, input, options = {}) {
23
23
  return path;
24
24
  }
25
25
  export async function loadConnection(name, options = {}) {
26
+ const explicitConfigHome = options.configHome ?? process.env.WITNORA_CONFIG_HOME ?? process.env.AGENTCERT_CONFIG_HOME;
26
27
  const file = await readCredentialFile(credentialsPath(options))
27
- ?? (options.configHome ? undefined : await readCredentialFile(legacyCredentialsPath()));
28
+ ?? (explicitConfigHome !== undefined ? undefined : await readCredentialFile(legacyCredentialsPath()));
28
29
  if (!file)
29
30
  return undefined;
30
31
  const connectionName = name ? validateConnectionName(name) : file.defaultConnection;
package/dist/onboard.js CHANGED
@@ -59,6 +59,9 @@ export async function runOnboard(options) {
59
59
  if (!setupPlan || (token.approvedSetupPlanId && setupPlan.id !== token.approvedSetupPlanId) || !setupPlan.authorizedOperations.some((item) => item.kind === "authorize_install")) {
60
60
  throw new Error("Confirm the Setup Plan and authorize installation in the Witnora Workspace before running onboard.");
61
61
  }
62
+ const attemptId = `install-${Date.now()}-${randomSuffix()}`;
63
+ // Resume an authorized failed install before requesting fresh Runtime authority.
64
+ await reportInstall(requestFetch, server, token.projectId, token.apiKey, setupPlan.id, { status: "installing", attemptId });
62
65
  let localRuntime = await discoverRuntimeReferences({
63
66
  repository: repositoryPath, configHome: options.configHome, projectId: token.projectId, setupPlanId: setupPlan.id, server, env: options.env ?? process.env,
64
67
  });
@@ -97,7 +100,6 @@ export async function runOnboard(options) {
97
100
  runtimeLimitation = `Hosted Runtime bootstrap did not complete: ${detail.slice(0, 500)} The existing Gateway was preserved and setup remains RECORDED_ONLY.`;
98
101
  }
99
102
  }
100
- const attemptId = `install-${Date.now()}-${randomSuffix()}`;
101
103
  const generatedFiles = [];
102
104
  const gatewayLifecycle = options.gatewayLifecycle ?? {
103
105
  start: startManagedCustomerGateway,
@@ -146,7 +148,6 @@ export async function runOnboard(options) {
146
148
  }
147
149
  throw lastError;
148
150
  };
149
- await reportInstall(requestFetch, server, token.projectId, token.apiKey, setupPlan.id, { status: "installing", attemptId });
150
151
  try {
151
152
  generatedFiles.push(...await generateRepositoryConfig(repositoryPath, repository.template, repository.name));
152
153
  const selfTestDir = join(repositoryPath, ".witnora", "onboarding", "self-test", attemptId);
@@ -204,8 +205,12 @@ export async function runOnboard(options) {
204
205
  generatedFiles.push(...gateway.generatedFiles);
205
206
  }
206
207
  else {
207
- const binding = await inspectGatewayBinding(gatewayState.directory, token.projectId, server);
208
- if (binding.matches) {
208
+ const binding = await inspectGatewayBinding(gatewayState.directory, token.projectId, server, setupPlan.id);
209
+ if (binding.projectId === token.projectId && binding.server === server) {
210
+ const planRepairRequired = !binding.matches && Boolean(binding.runtimeSetupPlanId);
211
+ if (planRepairRequired && !localRuntime.references) {
212
+ throw new RuntimeSetupNotReadyError(`The existing Gateway belongs to a different Setup Plan and could not be restored. ${runtimeLimitation ?? "Runtime references are unavailable."} Run onboard again to retry; the existing Gateway is preserved.`);
213
+ }
209
214
  await saveConnection(binding.connectionName, { server, projectId: token.projectId, apiKey: token.apiKey, approvedSetupPlanId: setupPlan.id }, { configHome: options.configHome });
210
215
  if (localRuntime.references) {
211
216
  try {
@@ -223,6 +228,8 @@ export async function runOnboard(options) {
223
228
  catch (error) {
224
229
  if (!(error instanceof RuntimeSetupNotReadyError))
225
230
  throw error;
231
+ if (planRepairRequired)
232
+ throw error;
226
233
  runtimeLimitation = `Local sandbox Runtime references were found but did not establish readiness: ${error.message}`;
227
234
  output(`\nExisting customer-owned Gateway remains RECORDED_ONLY because its Runtime references did not pass readiness checks: ${error.message}\n`);
228
235
  }
@@ -598,7 +605,7 @@ function configuredGatewayPorts(environment) {
598
605
  const port = Number(value);
599
606
  return Number.isInteger(port) && port > 0 && port <= 65_535 ? new Set([port]) : new Set();
600
607
  }
601
- async function inspectGatewayBinding(directory, projectId, server) {
608
+ async function inspectGatewayBinding(directory, projectId, server, setupPlanId) {
602
609
  let value;
603
610
  try {
604
611
  value = JSON.parse(await readFile(join(directory, "gateway.json"), "utf8"));
@@ -612,10 +619,12 @@ async function inspectGatewayBinding(directory, projectId, server) {
612
619
  const collectorId = typeof value.collectorId === "string" ? value.collectorId.trim() : "";
613
620
  const host = typeof value.host === "string" && value.host.trim() ? value.host.trim() : "127.0.0.1";
614
621
  const port = Number(value.port);
622
+ const worker = value.runtimeWorker;
623
+ const runtimeSetupPlanId = typeof worker?.runtimeSetupPlanId === "string" ? worker.runtimeSetupPlanId : undefined;
615
624
  if (!existingProjectId || !existingServer || !connectionName || !collectorId || !Number.isInteger(port) || port < 1 || port > 65_535) {
616
625
  throw new Error("Existing Gateway configuration is missing a valid project, server, connection, collector, host, or port. Preserve it and repair the setup in Advanced mode.");
617
626
  }
618
- return { matches: existingProjectId === projectId && existingServer === server, projectId: existingProjectId, server: existingServer, connectionName, collectorId, host, port };
627
+ return { matches: existingProjectId === projectId && existingServer === server && runtimeSetupPlanId === setupPlanId, runtimeSetupPlanId, projectId: existingProjectId, server: existingServer, connectionName, collectorId, host, port };
619
628
  }
620
629
  async function assertGatewayStopped(requestFetch, host, port, oldCollectorId, oldProjectId, newProjectId) {
621
630
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "witnora",
3
- "version": "0.20.16",
3
+ "version": "0.20.17",
4
4
  "description": "Independent assurance for covered agent action paths across models and frameworks.",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE",