witnora 0.20.7 → 0.20.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -160,6 +160,7 @@ else if (command === "onboard") {
160
160
  repository: readFlag("--repo") ?? process.cwd(),
161
161
  template: readFlag("--template") ? parseAgentTemplate(readFlag("--template")) : undefined,
162
162
  actionTransport: readActionTransport(readFlag("--action-transport")),
163
+ waitForActionPathMs: readActionTransport(readFlag("--action-transport")) && !readBoolFlag("--no-wait-for-action-path") ? 10 * 60 * 1_000 : 0,
163
164
  openBrowser: readBoolFlag("--no-browser") ? async () => { } : undefined,
164
165
  });
165
166
  }
package/dist/onboard.js CHANGED
@@ -125,6 +125,7 @@ export async function runOnboard(options) {
125
125
  let assuranceHarnessChanged = false;
126
126
  let httpActionSetup;
127
127
  let continuousService;
128
+ let localOutputTaskConfirmed = false;
128
129
  const prepareRuntime = async (operation) => {
129
130
  const delays = [250, 500, 1_000, 2_000, 4_000, 8_000];
130
131
  let lastError;
@@ -304,7 +305,7 @@ export async function runOnboard(options) {
304
305
  const runtimeReadiness = doctor.overall === "READY_FOR_RUNTIME" && runtimeBinding
305
306
  ? { state: "LOCAL_SANDBOX_READY", checkedAt: new Date().toISOString(), limitations: [] }
306
307
  : { state: "RECORDED_ONLY", checkedAt: new Date().toISOString(), limitations: [runtimeLimitation ?? "The local sandbox Runtime worker has not established exact adapter, probe, source-key, identity, mandate, and readiness bindings."] };
307
- const actionTransportTest = options.actionTransport
308
+ let actionTransportTest = options.actionTransport
308
309
  ? await runActionTransportTest({
309
310
  transport: options.actionTransport,
310
311
  repository: repositoryPath,
@@ -319,12 +320,66 @@ export async function runOnboard(options) {
319
320
  : undefined;
320
321
  const localWorkflowCommand = await detectLocalWorkflowCommand(repositoryPath);
321
322
  const cliVersion = await currentCliVersion();
323
+ const agentRunCommand = localWorkflowCommand
324
+ ? `npx --yes witnora@${cliVersion} gateway exec -- ${localWorkflowCommand.join(" ")}`
325
+ : undefined;
322
326
  await reportInstall(requestFetch, server, token.projectId, token.apiKey, setupPlan.id, {
323
327
  status: "verified", attemptId, generatedFiles: relativeGeneratedFiles(repositoryPath, generatedFiles), runtimeReadiness,
324
328
  connectedAgent: agentIdentity,
329
+ agentRunCommand,
325
330
  ...(runtimeBinding ? { runtimeBinding } : {}),
326
331
  });
327
- output(`\nWitnora Setup Autopilot completed for ${repository.name}.\n`);
332
+ if (actionTransportTest?.state === "WAITING_FOR_ACTION_PATH" && (options.waitForActionPathMs ?? 0) > 0) {
333
+ output("\nBase setup is complete. Onboarding is waiting for the Business Task and Action path; it has not claimed completion.\n");
334
+ output(agentRunCommand
335
+ ? `Open a second terminal in this repository and run the Agent safely once:\n${agentRunCommand}\n`
336
+ : "Run the Agent normally in its sandbox. If it has no work now, you may enter the workspace and finish Action verification after its first real run.\n");
337
+ output(`Keep this command open for up to ${Math.max(1, Math.ceil((options.waitForActionPathMs ?? 0) / 60_000))} minutes. It will finish automatically after you confirm the Business Task in the browser; no second onboard command is required. Press Ctrl+C to pause safely.\n`);
338
+ const resolution = await waitForOnboardingResolution({
339
+ repository: repositoryPath, server, projectId: token.projectId, apiKey: token.apiKey,
340
+ env: options.env, fetch: requestFetch, sleep: options.sleep, timeoutMs: options.waitForActionPathMs ?? 0,
341
+ });
342
+ if (resolution?.kind === "LOCAL_OUTPUT") {
343
+ localOutputTaskConfirmed = true;
344
+ actionTransportTest = undefined;
345
+ if (assuranceHarnessReadiness.state === "WAITING_FOR_CUSTOMER_HARNESS") {
346
+ assuranceHarnessReadiness = { state: "NOT_REQUIRED_FOR_LOCAL_OUTPUT" };
347
+ }
348
+ }
349
+ else if (resolution?.kind === "REAL_PATH") {
350
+ const lateActivation = resolution.activation;
351
+ realPathActivation = lateActivation;
352
+ generatedFiles.push(...lateActivation.generatedFiles);
353
+ const harness = await activateManagedWorkflowHarness({ repository: repositoryPath, realPathActivations: lateActivation.activations, previousGeneratedModuleSha256: lateActivation.previousGeneratedModuleSha256 });
354
+ if (harness.created)
355
+ generatedFiles.push(harness.path);
356
+ assuranceHarnessReadiness = { state: "ACTIVE" };
357
+ httpActionSetup = await configureCustomerHttpAction({ repository: repositoryPath, activations: lateActivation.activations });
358
+ generatedFiles.push(...httpActionSetup.generatedFiles);
359
+ if (harness.changed || httpActionSetup.changed) {
360
+ await stopGatewayOwners();
361
+ if (!options.gatewayLifecycle) {
362
+ await installCurrentGatewayService({ repository: repositoryPath, cliEntry: fileURLToPath(new URL("./cli.js", import.meta.url)), configHome: options.configHome });
363
+ managedGateway = await waitForInstalledGatewayService({ repository: repositoryPath, fetch: requestFetch, sleep: options.sleep, timeoutMs: options.timeoutMs });
364
+ }
365
+ else {
366
+ managedGateway = await gatewayLifecycle.start({ repository: repositoryPath, configHome: options.configHome, fetch: requestFetch, output });
367
+ }
368
+ }
369
+ actionTransportTest = await runActionTransportTest({
370
+ transport: options.actionTransport, repository: repositoryPath, server, projectId: token.projectId, apiKey: token.apiKey,
371
+ repositoryIdentity: repository, httpActionReady: httpActionSetup.state === "READY" && Boolean(httpActionSetup.action),
372
+ fetch: requestFetch, generatedFiles,
373
+ });
374
+ await reportInstall(requestFetch, server, token.projectId, token.apiKey, setupPlan.id, {
375
+ status: "verified", attemptId, generatedFiles: relativeGeneratedFiles(repositoryPath, generatedFiles), runtimeReadiness,
376
+ connectedAgent: agentIdentity, agentRunCommand, ...(runtimeBinding ? { runtimeBinding } : {}),
377
+ });
378
+ }
379
+ }
380
+ output(actionTransportTest?.state === "WAITING_FOR_ACTION_PATH"
381
+ ? `\nWitnora base setup completed for ${repository.name}; Action onboarding is paused and still pending.\n`
382
+ : `\nWitnora Setup Autopilot completed for ${repository.name}.\n`);
328
383
  output(`Project: ${token.projectId}\nTemplate: ${repository.template} (${repository.kind})\n`);
329
384
  output(`Credentials: ${credentialsPath}\nSelf-test receipt: ${receiptPath}\n`);
330
385
  output(`Private discovery: ${discovery.capabilityCount} capability group(s); ${discovery.unknownCapabilityCount} pending confirmation.\n`);
@@ -337,7 +392,9 @@ export async function runOnboard(options) {
337
392
  : `Runtime: RECORDED_ONLY. ${runtimeReadiness.limitations[0]}\n`);
338
393
  output(assuranceHarnessReadiness.state === "ACTIVE"
339
394
  ? `Assurance Harness: ACTIVE. Nora can dispatch authority-ready Replay and no-write Shadow evaluations without manual Workflow IDs, evaluator origins, credentials, or contract digests.${realPathActivation.activations.length ? ` ${realPathActivation.activations.length} exact sandbox real-path binding(s) passed read-only preflight.` : ""}\n`
340
- : `Assurance Harness: WAITING_FOR_CUSTOMER_HARNESS. ${assuranceHarnessReadiness.limitation}\n`);
395
+ : assuranceHarnessReadiness.state === "NOT_REQUIRED_FOR_LOCAL_OUTPUT"
396
+ ? "Assurance Harness: NOT_REQUIRED_FOR_LOCAL_OUTPUT. The approved read-only local-output task is confirmed; no external Action transport is required.\n"
397
+ : `Assurance Harness: WAITING_FOR_CUSTOMER_HARNESS. ${assuranceHarnessReadiness.limitation}\n`);
341
398
  if (httpActionSetup?.state === "READY" && httpActionSetup.action) {
342
399
  output(`HTTP Action: READY. POST ${managedGateway.baseUrl}${httpActionSetup.action.path}; copy the action-scoped token and request example from .witnora/gateway/HTTP_ACTION.md.\n`);
343
400
  }
@@ -347,11 +404,13 @@ export async function runOnboard(options) {
347
404
  else if (actionTransportTest) {
348
405
  output(`Action transport: ${actionTransportTest.transport.toUpperCase()} is waiting for one exact sandbox Task/action path. ${actionTransportTest.limitation}\n`);
349
406
  }
350
- output(actionTransportTest?.state === "WAITING_FOR_ACTION_PATH"
351
- ? `Base Gateway connected, but ${actionTransportTest.transport.toUpperCase()} Action is not verified yet. Run the Agent's normal sandbox workflow from this repository; there is no Run button in Overview. Once Overview receives the activity, confirm one sandbox Business Task and choose its exact discovered Agent action, then rerun this same command.\n`
352
- : "Connected. Nora is monitoring this Agent. Run it normally whenever it is ready; the first source-signed activity will appear automatically without blocking setup.\n");
407
+ output(localOutputTaskConfirmed
408
+ ? "Connected. Nora is monitoring this Agent. The approved read-only local-output task is confirmed; no external Action transport is required.\n"
409
+ : actionTransportTest?.state === "WAITING_FOR_ACTION_PATH"
410
+ ? `Base Gateway connected, but ${actionTransportTest.transport.toUpperCase()} Action is not verified yet. Run the Agent once and confirm its Business Task in the browser. Recovery only: rerun this command if the original waiting process was closed.\n`
411
+ : "Connected. Nora is monitoring this Agent. Run it normally whenever it is ready; the first source-signed activity will appear automatically without blocking setup.\n");
353
412
  output(localWorkflowCommand
354
- ? `Local sandbox command: npx --yes witnora@${cliVersion} gateway exec -- ${localWorkflowCommand.join(" ")}\n`
413
+ ? `Local sandbox command: ${agentRunCommand}\n`
355
414
  : `For a local sandbox workflow, use npx --yes witnora@${cliVersion} gateway exec -- <your normal sandbox command> so the Gateway token stays out of shell history.\n`);
356
415
  return { projectId: token.projectId, connectionName: token.connectionName, credentialsPath, template: repository.template,
357
416
  repositoryKind: repository.kind, generatedFiles, receiptPath, discovery, setupPlanId: setupPlan.id,
@@ -412,6 +471,24 @@ async function loadMatchingOnboardConnection(options) {
412
471
  return undefined;
413
472
  }
414
473
  }
474
+ async function waitForOnboardingResolution(options) {
475
+ const sleep = options.sleep ?? ((milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)));
476
+ let waited = 0;
477
+ let delay = 2_000;
478
+ while (waited < options.timeoutMs) {
479
+ const activation = await activateRealPathIntegrations(options);
480
+ if (activation.activations.length)
481
+ return { kind: "REAL_PATH", activation };
482
+ const onboarding = await jsonRequest(options.fetch, `${options.server}/v1/projects/${encodeURIComponent(options.projectId)}/onboarding`, { method: "GET", headers: { authorization: `Bearer ${options.apiKey}` } });
483
+ if (onboarding.localOutputTaskConfirmed)
484
+ return { kind: "LOCAL_OUTPUT" };
485
+ const interval = Math.min(delay, options.timeoutMs - waited);
486
+ await sleep(interval);
487
+ waited += interval;
488
+ delay = Math.min(15_000, Math.round(delay * 1.5));
489
+ }
490
+ return undefined;
491
+ }
415
492
  async function runActionTransportTest(options) {
416
493
  if (!options.httpActionReady)
417
494
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "witnora",
3
- "version": "0.20.7",
3
+ "version": "0.20.9",
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",