witnora 0.13.4 → 0.13.6

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.
@@ -1,4 +1,4 @@
1
- import { CustomerSourceKeyRing, type CustomerSourceSigner, type RemoteCollectorAck, type RemoteTrustedSourceRecord } from "./remote-collector.js";
1
+ import { CustomerSourceKeyRing, type CustomerSourceSigner, type CollectorRuntimeHeartbeat, type RuntimeReadinessBinding, type RemoteCollectorAck, type RemoteTrustedSourceRecord } from "./remote-collector.js";
2
2
  export interface RemoteCollectorTransport {
3
3
  registerSourceKey(input: {
4
4
  collectorId: string;
@@ -12,6 +12,7 @@ export interface RemoteCollectorTransport {
12
12
  signer: CustomerSourceSigner;
13
13
  pendingRecordCount: number;
14
14
  lastAckSequence?: number;
15
+ runtime?: CollectorRuntimeHeartbeat;
15
16
  }): Promise<Record<string, unknown>>;
16
17
  reconcile(runId: string, receipt: Record<string, unknown>): Promise<Record<string, unknown>>;
17
18
  proposeAction(proposal: Record<string, unknown>, idempotencyKey: string): Promise<Record<string, unknown>>;
@@ -37,7 +38,14 @@ export interface CustomerOwnedCollectorGatewayOptions {
37
38
  }): Promise<unknown>;
38
39
  status(): Promise<Record<string, unknown>>;
39
40
  close?(): void | Promise<void>;
41
+ runtimeBinding?: {
42
+ classification: "LOCAL_SANDBOX_ONLY";
43
+ binding: RuntimeReadinessBinding;
44
+ fixtureReady: boolean;
45
+ workerReady?: boolean;
46
+ };
40
47
  };
48
+ runtimeBinding?: RuntimeReadinessBinding;
41
49
  }
42
50
  export interface CustomerOwnedCollectorGateway {
43
51
  baseUrl: string;
@@ -1 +1 @@
1
- {"version":3,"file":"collector-gateway.d.ts","sourceRoot":"","sources":["../../../../agentcert-sdk/src/collector-gateway.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"collector-gateway.d.ts","sourceRoot":"","sources":["../../../../agentcert-sdk/src/collector-gateway.ts"],"names":[],"mappings":"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"}
@@ -10,6 +10,10 @@ export async function startCustomerOwnedCollectorGateway(options) {
10
10
  const storageDirectory = resolve(options.storageDirectory);
11
11
  await mkdir(storageDirectory, { recursive: true });
12
12
  const signer = options.keyRing.activeSigner();
13
+ const runtimeBinding = options.actionWorker?.runtimeBinding?.binding ?? options.runtimeBinding;
14
+ if (runtimeBinding && (runtimeBinding.collectorId !== options.keyRing.collectorId || runtimeBinding.sourceKeyId !== signer.keyId)) {
15
+ throw new Error("runtimeBinding must match the Gateway collector and active source key.");
16
+ }
13
17
  let sourceKeyRegistered = false;
14
18
  const journals = new Map();
15
19
  const activeCollector = {
@@ -98,7 +102,8 @@ export async function startCustomerOwnedCollectorGateway(options) {
98
102
  if (request.method === "POST" && url.pathname === "/v1/actions") {
99
103
  const body = await readJson(request, options.maxBodyBytes ?? 1_048_576);
100
104
  const proposal = object(body.proposal);
101
- const action = await options.client.proposeAction(proposal, identifier(body.idempotencyKey, "idempotencyKey"));
105
+ const hostedProposal = runtimeBinding ? { ...proposal, localRuntimeBinding: runtimeBinding } : proposal;
106
+ const action = await options.client.proposeAction(hostedProposal, identifier(body.idempotencyKey, "idempotencyKey"));
102
107
  if (options.actionWorker)
103
108
  await options.actionWorker.track({ actionId: identifier(action.id, "actionId"), proposal });
104
109
  return json(response, 202, action);
@@ -165,15 +170,17 @@ export async function startCustomerOwnedCollectorGateway(options) {
165
170
  if (!address || typeof address === "string")
166
171
  throw new Error("Collector gateway did not bind a TCP port.");
167
172
  const flushTimer = setInterval(() => void flush(), options.flushIntervalMs ?? 5_000);
168
- const heartbeatTimer = setInterval(async () => {
173
+ const sendHeartbeat = async () => {
169
174
  const current = await status();
170
175
  try {
171
176
  await ensureSourceKeyRegistered();
177
+ const workerStatus = options.actionWorker ? await options.actionWorker.status() : undefined;
172
178
  await options.client.heartbeat({
173
179
  collectorId: activeCollector.id,
174
180
  signer,
175
181
  pendingRecordCount: current.pendingRecordCount,
176
182
  lastAckSequence: current.lastAckSequence,
183
+ runtime: runtimeBinding && workerStatus ? runtimeHeartbeat(runtimeBinding, workerStatus, options.actionWorker?.runtimeBinding?.fixtureReady) : undefined,
177
184
  });
178
185
  lastRemoteSuccessAt = new Date().toISOString();
179
186
  lastRemoteError = undefined;
@@ -181,12 +188,14 @@ export async function startCustomerOwnedCollectorGateway(options) {
181
188
  catch (error) {
182
189
  lastRemoteError = message(error);
183
190
  }
184
- }, options.heartbeatIntervalMs ?? 30_000);
191
+ };
192
+ const heartbeatTimer = setInterval(() => void sendHeartbeat(), options.heartbeatIntervalMs ?? 30_000);
185
193
  flushTimer.unref();
186
194
  heartbeatTimer.unref();
187
195
  for (const runId of await discoverRunIds(storageDirectory))
188
196
  await journalFor(runId);
189
197
  await flush();
198
+ await sendHeartbeat();
190
199
  return {
191
200
  baseUrl: `http://${options.host ?? "127.0.0.1"}:${address.port}`,
192
201
  close: async () => {
@@ -200,6 +209,22 @@ export async function startCustomerOwnedCollectorGateway(options) {
200
209
  status,
201
210
  };
202
211
  }
212
+ function runtimeHeartbeat(binding, status, configuredFixtureReady) {
213
+ const boundary = status.runtimeBoundary && typeof status.runtimeBoundary === "object" && !Array.isArray(status.runtimeBoundary)
214
+ ? status.runtimeBoundary
215
+ : undefined;
216
+ const fixture = boundary?.fixture && typeof boundary.fixture === "object" && !Array.isArray(boundary.fixture)
217
+ ? boundary.fixture
218
+ : undefined;
219
+ const lastError = typeof status.lastError === "string" && status.lastError.trim() ? status.lastError.slice(0, 1_000) : undefined;
220
+ return {
221
+ classification: "LOCAL_SANDBOX_ONLY",
222
+ binding,
223
+ workerReady: status.ready === true,
224
+ fixtureReady: fixture?.ready === true || status.fixtureReady === true || configuredFixtureReady === true,
225
+ ...(lastError ? { lastError } : {}),
226
+ };
227
+ }
203
228
  class GatewayRunJournal {
204
229
  runId;
205
230
  collector;
@@ -38,6 +38,25 @@ export interface RemoteCollectorAck {
38
38
  alerts: Array<Record<string, unknown>>;
39
39
  run: Record<string, unknown>;
40
40
  }
41
+ export interface RuntimeReadinessBinding {
42
+ collectorId: string;
43
+ sourceKeyId: string;
44
+ configDigestSha256: string;
45
+ runtimeIdentity: {
46
+ id: string;
47
+ };
48
+ mandateDigestSha256: string;
49
+ adapterDigestSha256: string;
50
+ probeDigestSha256: string;
51
+ fixtureContractDigestSha256: string;
52
+ }
53
+ export interface CollectorRuntimeHeartbeat {
54
+ classification: "LOCAL_SANDBOX_ONLY";
55
+ binding: RuntimeReadinessBinding;
56
+ workerReady: boolean;
57
+ fixtureReady: boolean;
58
+ lastError?: string;
59
+ }
41
60
  export interface RemoteCollectorClientOptions {
42
61
  baseUrl: string;
43
62
  projectId: string;
@@ -85,6 +104,7 @@ export declare class RemoteCollectorClient {
85
104
  pendingRecordCount: number;
86
105
  lastAckSequence?: number;
87
106
  occurredAt?: string;
107
+ runtime?: CollectorRuntimeHeartbeat;
88
108
  }): Promise<Record<string, unknown>>;
89
109
  reconcile(runId: string, receipt: Record<string, unknown>): Promise<Record<string, unknown>>;
90
110
  proposeAction(proposal: Record<string, unknown>, idempotencyKey: string): Promise<Record<string, unknown>>;
@@ -1 +1 @@
1
- {"version":3,"file":"remote-collector.d.ts","sourceRoot":"","sources":["../../../../agentcert-sdk/src/remote-collector.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"remote-collector.d.ts","sourceRoot":"","sources":["../../../../agentcert-sdk/src/remote-collector.ts"],"names":[],"mappings":"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"}
@@ -104,6 +104,7 @@ export class RemoteCollectorClient {
104
104
  occurredAt: input.occurredAt ?? new Date().toISOString(),
105
105
  pendingRecordCount: input.pendingRecordCount,
106
106
  lastAckSequence: input.lastAckSequence,
107
+ runtime: input.runtime,
107
108
  };
108
109
  const payloadSha256 = sha256(canonicalJson(payload));
109
110
  return this.json("collector-heartbeats", {
package/dist/onboard.js CHANGED
@@ -7,7 +7,9 @@ import { verifyControlPlaneConnection } from "./control-plane.js";
7
7
  import { inferPrivateCapabilities, runPrivateCapabilityDiscovery } from "./private-discovery.js";
8
8
  import { parseAgentTemplate, starterAdapter, starterProfile, starterTripwireConfig } from "./onboarding-templates.js";
9
9
  import { writeTryEvidence } from "./try.js";
10
- import { doctorCustomerGateway, initializeCustomerGateway, inspectCustomerGatewayFiles, startManagedCustomerGateway, stopManagedCustomerGateway, } from "./gateway.js";
10
+ import { doctorCustomerGateway, initializeCustomerGateway, inspectLocalRuntimeBinding, inspectCustomerGatewayFiles, startManagedCustomerGateway, stopManagedCustomerGateway, upgradeCustomerGatewayRuntime, RuntimeSetupNotReadyError, } from "./gateway.js";
11
+ import { discoverRuntimeReferences, planRuntimeSandboxModules } from "./runtime-sandbox-kit.js";
12
+ import { automaticRuntimeReferencesUsable, bootstrapLocalRuntime, verifyAutomaticRuntimeProbe } from "./runtime-bootstrap.js";
11
13
  export async function runOnboard(options) {
12
14
  const requestFetch = options.fetch ?? fetch;
13
15
  const output = options.output ?? ((message) => process.stdout.write(message));
@@ -36,6 +38,44 @@ export async function runOnboard(options) {
36
38
  if (!setupPlan || !setupPlan.authorizedOperations.some((item) => item.kind === "authorize_install")) {
37
39
  throw new Error("Confirm the Setup Plan and authorize installation in the Witnora Workspace before running onboard.");
38
40
  }
41
+ let localRuntime = await discoverRuntimeReferences({
42
+ repository: repositoryPath, configHome: options.configHome, projectId: token.projectId, server, env: options.env ?? process.env,
43
+ });
44
+ let runtimeLimitation = localRuntime.limitation;
45
+ let runtimeBootstrapRequired = !localRuntime.references;
46
+ if (localRuntime.references?.probeApiKeyId) {
47
+ try {
48
+ if (!await automaticRuntimeReferencesUsable(localRuntime.references))
49
+ throw new Error("local bootstrap material invalid");
50
+ await verifyAutomaticRuntimeProbe({ references: localRuntime.references, projectId: token.projectId, server, fetch: requestFetch });
51
+ }
52
+ catch {
53
+ runtimeBootstrapRequired = true;
54
+ }
55
+ }
56
+ if (runtimeBootstrapRequired) {
57
+ try {
58
+ const references = localRuntime.references;
59
+ const modules = references?.sandboxOrigin && references.adapterDigestSha256 && references.probeDigestSha256 && references.fixtureContractDigestSha256
60
+ ? { sandboxOrigin: references.sandboxOrigin, adapterDigestSha256: references.adapterDigestSha256, probeDigestSha256: references.probeDigestSha256, fixtureContractDigestSha256: references.fixtureContractDigestSha256 }
61
+ : await planRuntimeSandboxModules();
62
+ const bootstrap = await bootstrapLocalRuntime({
63
+ projectId: token.projectId,
64
+ planId: setupPlan.id,
65
+ server,
66
+ apiKey: token.apiKey,
67
+ configHome: options.configHome,
68
+ fetch: requestFetch,
69
+ modules,
70
+ });
71
+ localRuntime = { references: bootstrap.references };
72
+ runtimeLimitation = undefined;
73
+ }
74
+ catch (error) {
75
+ const detail = error instanceof Error ? error.message : "Unknown Runtime bootstrap error.";
76
+ runtimeLimitation = `Hosted Runtime bootstrap did not complete: ${detail.slice(0, 500)} The existing Gateway was preserved and setup remains RECORDED_ONLY.`;
77
+ }
78
+ }
39
79
  const attemptId = `install-${Date.now()}-${randomSuffix()}`;
40
80
  const generatedFiles = [];
41
81
  const gatewayLifecycle = options.gatewayLifecycle ?? {
@@ -44,6 +84,7 @@ export async function runOnboard(options) {
44
84
  };
45
85
  let gatewayMigration;
46
86
  let managedGateway;
87
+ let runtimeUpgrade;
47
88
  await reportInstall(requestFetch, server, token.projectId, token.apiKey, setupPlan.id, { status: "installing", attemptId });
48
89
  try {
49
90
  generatedFiles.push(...await generateRepositoryConfig(repositoryPath, repository.template, repository.name));
@@ -84,17 +125,49 @@ export async function runOnboard(options) {
84
125
  throw new Error(`Existing Gateway setup is incomplete. Preserve the existing files and repair or remove the partial setup in Advanced mode. Missing: ${gatewayState.missing.map((path) => basename(path)).join(", ")}.`);
85
126
  }
86
127
  if (gatewayState.status === "absent") {
87
- const gateway = await initializeCustomerGateway({
88
- projectId: token.projectId, server, repository: repositoryPath, authorization: token,
89
- fetch: requestFetch, configHome: options.configHome, output,
90
- });
128
+ let gateway;
129
+ try {
130
+ gateway = await initializeCustomerGateway({
131
+ projectId: token.projectId, server, repository: repositoryPath, authorization: token,
132
+ runtimeReferences: localRuntime.references,
133
+ fetch: requestFetch, configHome: options.configHome, output,
134
+ });
135
+ }
136
+ catch (error) {
137
+ if (!(error instanceof RuntimeSetupNotReadyError) || !localRuntime.references)
138
+ throw error;
139
+ runtimeLimitation = `Local sandbox Runtime references were found but did not establish readiness: ${error.message}`;
140
+ gateway = await initializeCustomerGateway({ projectId: token.projectId, server, repository: repositoryPath, authorization: token, fetch: requestFetch, configHome: options.configHome, output });
141
+ }
91
142
  generatedFiles.push(...gateway.generatedFiles);
92
143
  }
93
144
  else {
94
145
  const binding = await inspectGatewayBinding(gatewayState.directory, token.projectId, server);
95
146
  if (binding.matches) {
96
147
  await saveConnection(binding.connectionName, { server, projectId: token.projectId, apiKey: token.apiKey }, { configHome: options.configHome });
97
- output("\nExisting customer-owned Gateway matches this project; verifying and reusing it.\n");
148
+ if (localRuntime.references) {
149
+ try {
150
+ runtimeUpgrade = await upgradeCustomerGatewayRuntime({ repository: repositoryPath, authorization: token, runtimeReferences: localRuntime.references, configHome: options.configHome, fetch: requestFetch });
151
+ if (runtimeUpgrade.changed) {
152
+ const stopped = await gatewayLifecycle.stop({ repository: repositoryPath, configHome: options.configHome, fetch: requestFetch });
153
+ if (stopped.state !== "STOPPED" || stopped.healthy)
154
+ throw new Error("The prior managed Gateway process did not stop before Runtime generation replacement.");
155
+ }
156
+ runtimeLimitation = undefined;
157
+ output(runtimeUpgrade.changed
158
+ ? "\nExisting customer-owned Gateway matches this project; safely replaced its generated Runtime generation, stopped the prior process, and preserved a local backup.\n"
159
+ : "\nExisting customer-owned Gateway already has the exact current Runtime generation; verifying and reusing it.\n");
160
+ }
161
+ catch (error) {
162
+ if (!(error instanceof RuntimeSetupNotReadyError))
163
+ throw error;
164
+ runtimeLimitation = `Local sandbox Runtime references were found but did not establish readiness: ${error.message}`;
165
+ output("\nExisting customer-owned Gateway remains RECORDED_ONLY because its Runtime references did not pass readiness checks.\n");
166
+ }
167
+ }
168
+ else {
169
+ output("\nExisting customer-owned Gateway matches this project; verifying and reusing it.\n");
170
+ }
98
171
  }
99
172
  else {
100
173
  await assertGatewayStopped(requestFetch, binding.host, binding.port, binding.projectId, token.projectId);
@@ -102,12 +175,14 @@ export async function runOnboard(options) {
102
175
  output(`\nExisting Gateway belongs to project ${binding.projectId}; archived it at ${gatewayMigration.archiveDirectory}.\n`);
103
176
  const gateway = await initializeCustomerGateway({
104
177
  projectId: token.projectId, server, repository: repositoryPath, authorization: token,
178
+ runtimeReferences: localRuntime.references,
105
179
  fetch: requestFetch, configHome: options.configHome, output,
106
180
  });
107
181
  generatedFiles.push(...gateway.generatedFiles);
108
182
  }
109
183
  }
110
- generatedFiles.push(...await generateAutopilotFiles(repositoryPath, repository.name));
184
+ const runtimeConfigured = await gatewayHasRuntimeWorker(repositoryPath);
185
+ generatedFiles.push(...await generateAutopilotFiles(repositoryPath, repository.name, runtimeConfigured));
111
186
  managedGateway = await gatewayLifecycle.start({
112
187
  repository: repositoryPath,
113
188
  configHome: options.configHome,
@@ -117,10 +192,14 @@ export async function runOnboard(options) {
117
192
  if (!managedGateway.healthy)
118
193
  throw new Error(managedGateway.detail);
119
194
  const doctor = await doctorCustomerGateway({ repository: repositoryPath, configHome: options.configHome, fetch: requestFetch });
120
- if (doctor.overall !== "READY_TO_RECORD")
195
+ if (doctor.overall !== "READY_TO_RECORD" && doctor.overall !== "READY_FOR_RUNTIME")
121
196
  throw new Error(doctor.checks.filter((check) => check.status === "FAIL").map((check) => check.message).join(" "));
197
+ const runtimeBinding = doctor.overall === "READY_FOR_RUNTIME" ? await inspectLocalRuntimeBinding({ repository: repositoryPath }).catch(() => undefined) : undefined;
198
+ const runtimeReadiness = doctor.overall === "READY_FOR_RUNTIME" && runtimeBinding
199
+ ? { state: "LOCAL_SANDBOX_READY", checkedAt: new Date().toISOString(), limitations: [] }
200
+ : { 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."] };
122
201
  await reportInstall(requestFetch, server, token.projectId, token.apiKey, setupPlan.id, {
123
- status: "verified", attemptId, generatedFiles: relativeGeneratedFiles(repositoryPath, generatedFiles),
202
+ status: "verified", attemptId, generatedFiles: relativeGeneratedFiles(repositoryPath, generatedFiles), runtimeReadiness, ...(runtimeBinding ? { runtimeBinding } : {}),
124
203
  });
125
204
  output(`\nWitnora Setup Autopilot completed for ${repository.name}.\n`);
126
205
  output(`Project: ${token.projectId}\nTemplate: ${repository.template} (${repository.kind})\n`);
@@ -128,11 +207,14 @@ export async function runOnboard(options) {
128
207
  output(`Private discovery: ${discovery.capabilityCount} capability group(s); ${discovery.unknownCapabilityCount} pending confirmation.\n`);
129
208
  output("Installed: customer-owned Gateway, default-deny policy, independent-probe contract, review contract, and PR/release/nightly CI.\n");
130
209
  output(`Gateway: ${managedGateway.state} at ${managedGateway.baseUrl}${managedGateway.pid ? ` (process ${managedGateway.pid})` : ""}.\n`);
210
+ output(runtimeReadiness.state === "LOCAL_SANDBOX_READY"
211
+ ? "Runtime: LOCAL_SANDBOX_READY. This proves only the generated localhost sandbox loop is ready; it does not establish coverage, CURRENT, or a verified customer outcome.\n"
212
+ : `Runtime: RECORDED_ONLY. ${runtimeReadiness.limitations[0]}\n`);
131
213
  output("The self-test remains isolated. The Gateway is ready in the background; run the agent normally. The first source-signed, server-reconciled Gateway run completes onboarding.\n");
132
214
  return { projectId: token.projectId, connectionName: token.connectionName, credentialsPath, template: repository.template,
133
215
  repositoryKind: repository.kind, generatedFiles, receiptPath, discovery, setupPlanId: setupPlan.id,
134
216
  gatewayDirectory: join(repositoryPath, ".witnora", "gateway"), gatewayArchiveDirectory: gatewayMigration?.archiveDirectory,
135
- gateway: managedGateway };
217
+ gateway: managedGateway, runtimeReadiness };
136
218
  }
137
219
  catch (error) {
138
220
  const diagnosis = error instanceof Error ? error.message : String(error);
@@ -140,6 +222,7 @@ export async function runOnboard(options) {
140
222
  await gatewayLifecycle.stop({ repository: repositoryPath, configHome: options.configHome, fetch: requestFetch }).catch(() => undefined);
141
223
  }
142
224
  await rollbackGeneratedFiles(generatedFiles);
225
+ await runtimeUpgrade?.rollback().catch(() => undefined);
143
226
  if (gatewayMigration)
144
227
  await restoreGateway(gatewayMigration);
145
228
  await reportInstall(requestFetch, server, token.projectId, token.apiKey, setupPlan.id, {
@@ -199,10 +282,10 @@ async function restoreGateway(migration) {
199
282
  function safePathSegment(value) {
200
283
  return (value.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-|-$/g, "") || "unknown-project").slice(0, 80);
201
284
  }
202
- async function generateAutopilotFiles(repositoryPath, subject) {
285
+ async function generateAutopilotFiles(repositoryPath, subject, runtimeConfigured) {
203
286
  const files = new Map([
204
287
  [".witnora/setup/policy.json", `${JSON.stringify({ schemaVersion: "witnora.setup_policy.v0.1", subject, unknownCapabilities: "pending_confirmation", defaultDecision: "deny", environment: "sandbox" }, null, 2)}\n`],
205
- [".witnora/setup/outcome-probe.json", `${JSON.stringify({ schemaVersion: "witnora.outcome_probe_contract.v0.1", mode: "independent_read_only", credentialEnv: "WITNORA_OUTCOME_PROBE_CREDENTIAL", status: "awaiting_customer_secret", uploadsCredential: false }, null, 2)}\n`],
288
+ [".witnora/setup/outcome-probe.json", `${JSON.stringify({ schemaVersion: "witnora.outcome_probe_contract.v0.1", mode: "independent_read_only", status: runtimeConfigured ? "configured" : "awaiting_runtime_bootstrap", uploadsCredential: false }, null, 2)}\n`],
206
289
  [".witnora/setup/review.json", `${JSON.stringify({ schemaVersion: "witnora.review_contract.v0.1", independentReviewRequired: true, syntheticEvidenceEligible: false }, null, 2)}\n`],
207
290
  [".github/workflows/witnora-assurance.yml", continuousAssuranceWorkflow()],
208
291
  ]);
@@ -217,6 +300,10 @@ async function generateAutopilotFiles(repositoryPath, subject) {
217
300
  }
218
301
  return written;
219
302
  }
303
+ async function gatewayHasRuntimeWorker(repositoryPath) {
304
+ const config = await optionalJson(join(repositoryPath, ".witnora", "gateway", "gateway.json"));
305
+ return Boolean(config?.runtimeWorker && typeof config.runtimeWorker === "object" && !Array.isArray(config.runtimeWorker));
306
+ }
220
307
  function continuousAssuranceWorkflow() {
221
308
  return `name: Witnora assurance\non:\n pull_request:\n push:\n tags: [\"v*\"]\n schedule:\n - cron: \"17 3 * * *\"\n workflow_dispatch:\npermissions:\n contents: read\njobs:\n assurance:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-node@v4\n with:\n node-version: 22\n - run: npx witnora@latest release-gate --config witnora.config.json --strict\n`;
222
309
  }