@kbediako/codex-orchestrator 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +238 -0
  3. package/dist/bin/codex-orchestrator.js +507 -0
  4. package/dist/orchestrator/src/agents/builder.js +16 -0
  5. package/dist/orchestrator/src/agents/index.js +4 -0
  6. package/dist/orchestrator/src/agents/planner.js +17 -0
  7. package/dist/orchestrator/src/agents/reviewer.js +13 -0
  8. package/dist/orchestrator/src/agents/tester.js +13 -0
  9. package/dist/orchestrator/src/cli/adapters/CommandBuilder.js +20 -0
  10. package/dist/orchestrator/src/cli/adapters/CommandPlanner.js +164 -0
  11. package/dist/orchestrator/src/cli/adapters/CommandReviewer.js +32 -0
  12. package/dist/orchestrator/src/cli/adapters/CommandTester.js +33 -0
  13. package/dist/orchestrator/src/cli/adapters/index.js +4 -0
  14. package/dist/orchestrator/src/cli/config/userConfig.js +28 -0
  15. package/dist/orchestrator/src/cli/doctor.js +48 -0
  16. package/dist/orchestrator/src/cli/events/runEvents.js +84 -0
  17. package/dist/orchestrator/src/cli/exec/command.js +56 -0
  18. package/dist/orchestrator/src/cli/exec/context.js +108 -0
  19. package/dist/orchestrator/src/cli/exec/experience.js +77 -0
  20. package/dist/orchestrator/src/cli/exec/finalization.js +140 -0
  21. package/dist/orchestrator/src/cli/exec/learning.js +62 -0
  22. package/dist/orchestrator/src/cli/exec/stageRunner.js +71 -0
  23. package/dist/orchestrator/src/cli/exec/summary.js +109 -0
  24. package/dist/orchestrator/src/cli/exec/telemetry.js +18 -0
  25. package/dist/orchestrator/src/cli/exec/tfgrpo.js +200 -0
  26. package/dist/orchestrator/src/cli/exec/tfgrpoArtifacts.js +19 -0
  27. package/dist/orchestrator/src/cli/exec/types.js +1 -0
  28. package/dist/orchestrator/src/cli/init.js +64 -0
  29. package/dist/orchestrator/src/cli/mcp.js +124 -0
  30. package/dist/orchestrator/src/cli/metrics/metricsAggregator.js +404 -0
  31. package/dist/orchestrator/src/cli/metrics/metricsRecorder.js +138 -0
  32. package/dist/orchestrator/src/cli/orchestrator.js +554 -0
  33. package/dist/orchestrator/src/cli/pipelines/defaultDiagnostics.js +32 -0
  34. package/dist/orchestrator/src/cli/pipelines/designReference.js +72 -0
  35. package/dist/orchestrator/src/cli/pipelines/hiFiDesignToolkit.js +71 -0
  36. package/dist/orchestrator/src/cli/pipelines/index.js +34 -0
  37. package/dist/orchestrator/src/cli/run/environment.js +24 -0
  38. package/dist/orchestrator/src/cli/run/manifest.js +367 -0
  39. package/dist/orchestrator/src/cli/run/manifestPersister.js +88 -0
  40. package/dist/orchestrator/src/cli/run/runPaths.js +30 -0
  41. package/dist/orchestrator/src/cli/selfCheck.js +12 -0
  42. package/dist/orchestrator/src/cli/services/commandRunner.js +420 -0
  43. package/dist/orchestrator/src/cli/services/controlPlaneService.js +107 -0
  44. package/dist/orchestrator/src/cli/services/execRuntime.js +69 -0
  45. package/dist/orchestrator/src/cli/services/pipelineResolver.js +47 -0
  46. package/dist/orchestrator/src/cli/services/runPreparation.js +82 -0
  47. package/dist/orchestrator/src/cli/services/runSummaryWriter.js +35 -0
  48. package/dist/orchestrator/src/cli/services/schedulerService.js +42 -0
  49. package/dist/orchestrator/src/cli/tasks/taskMetadata.js +19 -0
  50. package/dist/orchestrator/src/cli/telemetry/schema.js +8 -0
  51. package/dist/orchestrator/src/cli/types.js +1 -0
  52. package/dist/orchestrator/src/cli/ui/HudApp.js +112 -0
  53. package/dist/orchestrator/src/cli/ui/controller.js +26 -0
  54. package/dist/orchestrator/src/cli/ui/store.js +240 -0
  55. package/dist/orchestrator/src/cli/utils/enforcementMode.js +12 -0
  56. package/dist/orchestrator/src/cli/utils/fs.js +8 -0
  57. package/dist/orchestrator/src/cli/utils/interactive.js +25 -0
  58. package/dist/orchestrator/src/cli/utils/jsonlWriter.js +10 -0
  59. package/dist/orchestrator/src/cli/utils/optionalDeps.js +30 -0
  60. package/dist/orchestrator/src/cli/utils/packageInfo.js +25 -0
  61. package/dist/orchestrator/src/cli/utils/planFormatter.js +49 -0
  62. package/dist/orchestrator/src/cli/utils/runId.js +7 -0
  63. package/dist/orchestrator/src/cli/utils/specGuardRunner.js +26 -0
  64. package/dist/orchestrator/src/cli/utils/strings.js +8 -0
  65. package/dist/orchestrator/src/cli/utils/time.js +6 -0
  66. package/dist/orchestrator/src/control-plane/drift-reporter.js +109 -0
  67. package/dist/orchestrator/src/control-plane/index.js +3 -0
  68. package/dist/orchestrator/src/control-plane/request-builder.js +217 -0
  69. package/dist/orchestrator/src/control-plane/types.js +1 -0
  70. package/dist/orchestrator/src/control-plane/validator.js +50 -0
  71. package/dist/orchestrator/src/credentials/CredentialBroker.js +1 -0
  72. package/dist/orchestrator/src/events/EventBus.js +25 -0
  73. package/dist/orchestrator/src/learning/crystalizer.js +108 -0
  74. package/dist/orchestrator/src/learning/harvester.js +146 -0
  75. package/dist/orchestrator/src/learning/manifest.js +56 -0
  76. package/dist/orchestrator/src/learning/runner.js +177 -0
  77. package/dist/orchestrator/src/learning/validator.js +164 -0
  78. package/dist/orchestrator/src/logger.js +20 -0
  79. package/dist/orchestrator/src/manager.js +388 -0
  80. package/dist/orchestrator/src/persistence/ArtifactStager.js +95 -0
  81. package/dist/orchestrator/src/persistence/ExperienceStore.js +210 -0
  82. package/dist/orchestrator/src/persistence/PersistenceCoordinator.js +65 -0
  83. package/dist/orchestrator/src/persistence/RunManifestWriter.js +23 -0
  84. package/dist/orchestrator/src/persistence/TaskStateStore.js +172 -0
  85. package/dist/orchestrator/src/persistence/identifierGuards.js +1 -0
  86. package/dist/orchestrator/src/persistence/lockFile.js +26 -0
  87. package/dist/orchestrator/src/persistence/sanitizeIdentifier.js +26 -0
  88. package/dist/orchestrator/src/persistence/sanitizeRunId.js +8 -0
  89. package/dist/orchestrator/src/persistence/sanitizeTaskId.js +8 -0
  90. package/dist/orchestrator/src/persistence/writeAtomicFile.js +4 -0
  91. package/dist/orchestrator/src/privacy/guard.js +111 -0
  92. package/dist/orchestrator/src/scheduler/index.js +1 -0
  93. package/dist/orchestrator/src/scheduler/plan.js +171 -0
  94. package/dist/orchestrator/src/scheduler/types.js +1 -0
  95. package/dist/orchestrator/src/sync/CloudRunsClient.js +1 -0
  96. package/dist/orchestrator/src/sync/CloudRunsHttpClient.js +82 -0
  97. package/dist/orchestrator/src/sync/CloudSyncWorker.js +206 -0
  98. package/dist/orchestrator/src/sync/createCloudSyncWorker.js +15 -0
  99. package/dist/orchestrator/src/types.js +1 -0
  100. package/dist/orchestrator/src/utils/atomicWrite.js +15 -0
  101. package/dist/orchestrator/src/utils/errorMessage.js +14 -0
  102. package/dist/orchestrator/src/utils/executionMode.js +69 -0
  103. package/dist/packages/control-plane-schemas/src/index.js +1 -0
  104. package/dist/packages/control-plane-schemas/src/run-request.js +548 -0
  105. package/dist/packages/orchestrator/src/exec/handle-service.js +203 -0
  106. package/dist/packages/orchestrator/src/exec/session-manager.js +147 -0
  107. package/dist/packages/orchestrator/src/exec/unified-exec.js +432 -0
  108. package/dist/packages/orchestrator/src/index.js +3 -0
  109. package/dist/packages/orchestrator/src/instructions/loader.js +101 -0
  110. package/dist/packages/orchestrator/src/instructions/promptPacks.js +151 -0
  111. package/dist/packages/orchestrator/src/notifications/index.js +74 -0
  112. package/dist/packages/orchestrator/src/telemetry/otel-exporter.js +142 -0
  113. package/dist/packages/orchestrator/src/tool-orchestrator.js +161 -0
  114. package/dist/packages/sdk-node/src/orchestrator.js +195 -0
  115. package/dist/packages/shared/config/designConfig.js +495 -0
  116. package/dist/packages/shared/config/env.js +37 -0
  117. package/dist/packages/shared/config/index.js +2 -0
  118. package/dist/packages/shared/design-artifacts/writer.js +221 -0
  119. package/dist/packages/shared/events/serializer.js +84 -0
  120. package/dist/packages/shared/events/types.js +1 -0
  121. package/dist/packages/shared/manifest/artifactUtils.js +36 -0
  122. package/dist/packages/shared/manifest/designArtifacts.js +665 -0
  123. package/dist/packages/shared/manifest/fileIO.js +29 -0
  124. package/dist/packages/shared/manifest/toolRuns.js +78 -0
  125. package/dist/packages/shared/manifest/toolkitArtifacts.js +223 -0
  126. package/dist/packages/shared/manifest/types.js +5 -0
  127. package/dist/packages/shared/manifest/validator.js +73 -0
  128. package/dist/packages/shared/manifest/writer.js +2 -0
  129. package/dist/packages/shared/streams/stdio.js +112 -0
  130. package/dist/scripts/design/pipeline/advanced-assets.js +466 -0
  131. package/dist/scripts/design/pipeline/componentize.js +74 -0
  132. package/dist/scripts/design/pipeline/context.js +34 -0
  133. package/dist/scripts/design/pipeline/extract.js +249 -0
  134. package/dist/scripts/design/pipeline/optionalDeps.js +107 -0
  135. package/dist/scripts/design/pipeline/prepare.js +46 -0
  136. package/dist/scripts/design/pipeline/reference.js +94 -0
  137. package/dist/scripts/design/pipeline/state.js +206 -0
  138. package/dist/scripts/design/pipeline/toolkit/common.js +94 -0
  139. package/dist/scripts/design/pipeline/toolkit/extract.js +258 -0
  140. package/dist/scripts/design/pipeline/toolkit/publish.js +202 -0
  141. package/dist/scripts/design/pipeline/toolkit/publishActions.js +12 -0
  142. package/dist/scripts/design/pipeline/toolkit/reference.js +846 -0
  143. package/dist/scripts/design/pipeline/toolkit/snapshot.js +882 -0
  144. package/dist/scripts/design/pipeline/toolkit/tokens.js +456 -0
  145. package/dist/scripts/design/pipeline/visual-regression.js +137 -0
  146. package/dist/scripts/design/pipeline/write-artifacts.js +61 -0
  147. package/package.json +97 -0
  148. package/schemas/manifest.json +1064 -0
  149. package/templates/README.md +12 -0
  150. package/templates/codex/mcp-client.json +8 -0
@@ -0,0 +1,82 @@
1
+ export class CloudRunsHttpError extends Error {
2
+ status;
3
+ statusText;
4
+ body;
5
+ constructor(message, status, statusText, body) {
6
+ super(message);
7
+ this.status = status;
8
+ this.statusText = statusText;
9
+ this.body = body;
10
+ this.name = 'CloudRunsHttpError';
11
+ }
12
+ }
13
+ export class CloudRunsHttpClient {
14
+ broker;
15
+ baseUrl;
16
+ workspaceId;
17
+ bucket;
18
+ vaultPath;
19
+ scope;
20
+ fetchImpl;
21
+ constructor(options) {
22
+ this.broker = options.broker;
23
+ this.baseUrl = options.baseUrl ?? process.env.CODEX_CLOUD_BASE_URL ?? 'https://api.codex.cloud';
24
+ this.workspaceId = options.workspaceId ?? process.env.CODEX_CLOUD_WORKSPACE_ID ?? '';
25
+ this.bucket = options.bucket ?? process.env.CLOUD_SYNC_BUCKET ?? undefined;
26
+ this.vaultPath = options.vaultPath ?? process.env.CLOUD_SYNC_VAULT_PATH ?? undefined;
27
+ this.scope = options.scope ?? 'runs:write';
28
+ this.fetchImpl = options.fetchImpl ?? globalThis.fetch;
29
+ if (!this.workspaceId) {
30
+ throw new Error('CloudRunsHttpClient requires a workspace id (set CODEX_CLOUD_WORKSPACE_ID)');
31
+ }
32
+ if (!this.fetchImpl) {
33
+ throw new Error('CloudRunsHttpClient requires a fetch implementation');
34
+ }
35
+ }
36
+ async uploadManifest(payload) {
37
+ const token = await this.fetchToken();
38
+ const response = await this.fetchImpl(`${this.baseUrl}/workspaces/${this.workspaceId}/runs/import`, {
39
+ method: 'POST',
40
+ headers: {
41
+ 'content-type': 'application/json',
42
+ authorization: `Bearer ${token}`,
43
+ 'x-idempotency-key': payload.idempotencyKey
44
+ },
45
+ body: JSON.stringify({
46
+ summary: payload.summary,
47
+ manifest: payload.manifest,
48
+ bucket: this.bucket,
49
+ idempotencyKey: payload.idempotencyKey
50
+ })
51
+ });
52
+ if (!response.ok) {
53
+ const text = await response.text().catch(() => '');
54
+ throw new CloudRunsHttpError(`CloudRuns upload failed with status ${response.status}`, response.status, response.statusText, text);
55
+ }
56
+ let remoteId;
57
+ try {
58
+ const data = (await response.json());
59
+ remoteId = data.id ?? data.runId;
60
+ }
61
+ catch (error) {
62
+ // Ignore JSON parse errors; remote id stays undefined.
63
+ remoteId = undefined;
64
+ }
65
+ return {
66
+ status: 'success',
67
+ runId: payload.summary.runId,
68
+ remoteId
69
+ };
70
+ }
71
+ async fetchToken() {
72
+ const { token } = await this.broker.getToken({
73
+ service: 'codex-cloud',
74
+ scope: this.scope,
75
+ vaultPath: this.vaultPath
76
+ });
77
+ if (!token) {
78
+ throw new Error('Credential broker returned an empty token for codex-cloud');
79
+ }
80
+ return token;
81
+ }
82
+ }
@@ -0,0 +1,206 @@
1
+ import { appendFile, mkdir, readFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { createHash } from 'node:crypto';
4
+ import { CloudRunsHttpError } from './CloudRunsHttpClient.js';
5
+ import { sanitizeTaskId } from '../persistence/sanitizeTaskId.js';
6
+ import { sanitizeRunId } from '../persistence/sanitizeRunId.js';
7
+ export class CloudSyncWorker {
8
+ bus;
9
+ client;
10
+ options;
11
+ runsDir;
12
+ outDir;
13
+ enabled;
14
+ maxRetries;
15
+ backoffMs;
16
+ unsubscribe;
17
+ manifestReadRetries;
18
+ manifestInitialDelayMs;
19
+ constructor(bus, client, options = {}) {
20
+ this.bus = bus;
21
+ this.client = client;
22
+ this.options = options;
23
+ this.runsDir = options.runsDir ?? join(process.cwd(), '.runs');
24
+ this.outDir = options.outDir ?? join(process.cwd(), 'out');
25
+ this.enabled = options.enabled ?? true;
26
+ this.maxRetries = options.maxRetries ?? 3;
27
+ this.backoffMs = options.backoffMs ?? 250;
28
+ this.manifestReadRetries = options.manifestReadRetries ?? 5;
29
+ this.manifestInitialDelayMs = options.manifestInitialDelayMs ?? 50;
30
+ }
31
+ start() {
32
+ if (!this.enabled || this.unsubscribe) {
33
+ return;
34
+ }
35
+ this.unsubscribe = this.bus.on('run:completed', (event) => {
36
+ void this.handleRunCompleted(event.payload);
37
+ });
38
+ }
39
+ stop() {
40
+ if (this.unsubscribe) {
41
+ this.unsubscribe();
42
+ this.unsubscribe = undefined;
43
+ }
44
+ }
45
+ async handleRunCompleted(summary) {
46
+ if (!this.enabled) {
47
+ return;
48
+ }
49
+ let manifest;
50
+ try {
51
+ manifest = await this.readManifestWithRetry(summary);
52
+ }
53
+ catch (error) {
54
+ this.options.onError?.(error, summary, 0);
55
+ await this.appendAuditLog({
56
+ level: 'error',
57
+ message: 'Failed to read manifest before sync',
58
+ summary,
59
+ details: serializeError(error)
60
+ });
61
+ return;
62
+ }
63
+ const idempotencyKey = createHash('sha256')
64
+ .update(`${summary.taskId}:${summary.runId}`)
65
+ .digest('hex');
66
+ let attempt = 0;
67
+ let delay = this.backoffMs;
68
+ while (attempt < this.maxRetries) {
69
+ attempt += 1;
70
+ try {
71
+ const result = await this.client.uploadManifest({
72
+ summary,
73
+ manifest,
74
+ idempotencyKey
75
+ });
76
+ this.options.onSuccess?.(result, summary);
77
+ await this.appendAuditLog({
78
+ level: 'info',
79
+ message: 'Cloud sync completed',
80
+ summary,
81
+ details: { remoteId: result.remoteId, attempt }
82
+ });
83
+ return;
84
+ }
85
+ catch (error) {
86
+ this.options.onError?.(error, summary, attempt);
87
+ await this.appendAuditLog({
88
+ level: 'error',
89
+ message: 'Cloud sync attempt failed',
90
+ summary,
91
+ details: { attempt, error: serializeError(error) }
92
+ });
93
+ const shouldRetry = this.shouldRetry(error);
94
+ if (attempt >= this.maxRetries || !shouldRetry) {
95
+ return;
96
+ }
97
+ await new Promise((resolve) => setTimeout(resolve, delay));
98
+ delay *= 2;
99
+ }
100
+ }
101
+ }
102
+ buildManifestPath(summary) {
103
+ const safeTaskId = sanitizeTaskId(summary.taskId);
104
+ const safeRunId = sanitizeRunId(summary.runId);
105
+ const runDir = join(this.runsDir, safeTaskId, safeRunId);
106
+ return join(runDir, 'manifest.json');
107
+ }
108
+ async appendAuditLog(entry) {
109
+ const safeTaskId = sanitizeTaskId(entry.summary.taskId);
110
+ const logDir = join(this.outDir, safeTaskId, 'cloud-sync');
111
+ await mkdir(logDir, { recursive: true });
112
+ const logPath = join(logDir, 'audit.log');
113
+ const line = JSON.stringify({
114
+ timestamp: new Date().toISOString(),
115
+ taskId: entry.summary.taskId,
116
+ runId: entry.summary.runId,
117
+ level: entry.level,
118
+ message: entry.message,
119
+ details: entry.details
120
+ });
121
+ await appendFile(logPath, `${line}\n`, 'utf-8');
122
+ }
123
+ shouldRetry(error) {
124
+ if (this.options.retryDecider) {
125
+ return this.options.retryDecider(error);
126
+ }
127
+ if (error instanceof CloudRunsHttpError) {
128
+ if (error.status === 429) {
129
+ return true;
130
+ }
131
+ return error.status >= 500;
132
+ }
133
+ return true;
134
+ }
135
+ async readManifestWithRetry(summary) {
136
+ const manifestPath = this.buildManifestPath(summary);
137
+ let attempt = 0;
138
+ let delay = this.manifestInitialDelayMs;
139
+ let lastError;
140
+ let lastContents = null;
141
+ while (attempt < this.manifestReadRetries) {
142
+ attempt += 1;
143
+ try {
144
+ const contents = await readFile(manifestPath, 'utf-8');
145
+ lastContents = contents;
146
+ return JSON.parse(contents);
147
+ }
148
+ catch (error) {
149
+ lastError = error;
150
+ if (shouldRetryManifestRead(error) && attempt < this.manifestReadRetries) {
151
+ await new Promise((resolve) => setTimeout(resolve, delay));
152
+ delay *= 2;
153
+ continue;
154
+ }
155
+ break;
156
+ }
157
+ }
158
+ if (lastContents && lastError instanceof SyntaxError) {
159
+ const repaired = attemptJsonRecovery(lastContents);
160
+ if (repaired) {
161
+ try {
162
+ const parsed = JSON.parse(repaired);
163
+ await this.appendAuditLog({
164
+ level: 'info',
165
+ message: 'Recovered manifest from partial JSON',
166
+ summary,
167
+ details: { strategy: 'trim-trailing', attempts: attempt }
168
+ });
169
+ return parsed;
170
+ }
171
+ catch (parseError) {
172
+ lastError = parseError;
173
+ }
174
+ }
175
+ }
176
+ throw lastError ?? new Error(`Manifest not available after ${this.manifestReadRetries} attempts`);
177
+ }
178
+ }
179
+ function shouldRetryManifestRead(error) {
180
+ if (error instanceof SyntaxError) {
181
+ return true;
182
+ }
183
+ const code = error?.code;
184
+ return code === 'ENOENT' || code === 'EBUSY' || code === 'EMFILE';
185
+ }
186
+ function attemptJsonRecovery(contents) {
187
+ const lastBrace = contents.lastIndexOf('}');
188
+ if (lastBrace === -1) {
189
+ return null;
190
+ }
191
+ const candidate = contents.slice(0, lastBrace + 1);
192
+ return candidate.trim().length > 0 ? candidate : null;
193
+ }
194
+ function serializeError(error) {
195
+ if (error instanceof Error) {
196
+ return {
197
+ name: error.name,
198
+ message: error.message,
199
+ stack: error.stack
200
+ };
201
+ }
202
+ if (typeof error === 'object' && error !== null) {
203
+ return error;
204
+ }
205
+ return { message: String(error) };
206
+ }
@@ -0,0 +1,15 @@
1
+ import { CloudRunsHttpClient } from './CloudRunsHttpClient.js';
2
+ import { CloudSyncWorker } from './CloudSyncWorker.js';
3
+ /**
4
+ * Convenience factory that wires the CloudRuns HTTP client to the CloudSync worker using
5
+ * the credential broker defined in the architecture spec. Callers can override client or
6
+ * worker options as needed.
7
+ */
8
+ export function createCloudSyncWorker(params) {
9
+ const client = new CloudRunsHttpClient({
10
+ broker: params.broker,
11
+ ...(params.client ?? {})
12
+ });
13
+ const worker = new CloudSyncWorker(params.bus, client, params.worker);
14
+ return { worker, client };
15
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,15 @@
1
+ import { mkdir, rename, writeFile } from 'node:fs/promises';
2
+ import { dirname } from 'node:path';
3
+ let atomicWriteCounter = 0;
4
+ export function buildAtomicTempPath(destination, now = Date.now, pid = process.pid) {
5
+ atomicWriteCounter = (atomicWriteCounter + 1) % Number.MAX_SAFE_INTEGER;
6
+ return `${destination}.tmp-${pid}-${now()}-${atomicWriteCounter}`;
7
+ }
8
+ export async function writeAtomicFile(destination, contents, options = {}) {
9
+ const tmpPath = buildAtomicTempPath(destination, options.now ?? Date.now, options.pid ?? process.pid);
10
+ if (options.ensureDir) {
11
+ await mkdir(dirname(destination), { recursive: true });
12
+ }
13
+ await writeFile(tmpPath, contents, options.encoding ?? 'utf8');
14
+ await rename(tmpPath, destination);
15
+ }
@@ -0,0 +1,14 @@
1
+ export function normalizeErrorMessage(error) {
2
+ if (error instanceof Error && error.message) {
3
+ return error.message;
4
+ }
5
+ if (typeof error === 'string') {
6
+ return error;
7
+ }
8
+ try {
9
+ return JSON.stringify(error);
10
+ }
11
+ catch {
12
+ return String(error);
13
+ }
14
+ }
@@ -0,0 +1,69 @@
1
+ export function createExecutionModeParser(options) {
2
+ const trim = options.trim ?? false;
3
+ const lowercase = options.lowercase ?? true;
4
+ const truthy = new Set(options.truthyValues);
5
+ const falsy = new Set(options.falsyValues);
6
+ return (value) => {
7
+ const normalizedInput = trim ? value.trim() : value;
8
+ if (!normalizedInput) {
9
+ return null;
10
+ }
11
+ const normalized = lowercase ? normalizedInput.toLowerCase() : normalizedInput;
12
+ if (truthy.has(normalized)) {
13
+ return true;
14
+ }
15
+ if (falsy.has(normalized)) {
16
+ return false;
17
+ }
18
+ return null;
19
+ };
20
+ }
21
+ export const CLI_EXECUTION_MODE_PARSER = createExecutionModeParser({
22
+ trim: false,
23
+ lowercase: true,
24
+ truthyValues: ['cloud'],
25
+ falsyValues: ['mcp']
26
+ });
27
+ export const MANAGER_EXECUTION_MODE_PARSER = createExecutionModeParser({
28
+ trim: true,
29
+ lowercase: true,
30
+ truthyValues: ['cloud', 'true', '1', 'yes'],
31
+ falsyValues: ['mcp', 'false', '0', 'no']
32
+ });
33
+ export const PLANNER_EXECUTION_MODE_PARSER = createExecutionModeParser({
34
+ trim: false,
35
+ lowercase: true,
36
+ truthyValues: ['cloud'],
37
+ falsyValues: ['mcp']
38
+ });
39
+ export function resolveRequiresCloudFlag(options) {
40
+ for (const flag of options.boolFlags) {
41
+ if (flag === true) {
42
+ return true;
43
+ }
44
+ if (flag === false) {
45
+ return false;
46
+ }
47
+ }
48
+ for (const candidate of options.metadataModes) {
49
+ if (typeof candidate !== 'string') {
50
+ continue;
51
+ }
52
+ const parsed = options.parseMode(candidate);
53
+ if (parsed !== null) {
54
+ return parsed;
55
+ }
56
+ }
57
+ return null;
58
+ }
59
+ export function resolveRequiresCloudPolicy(options) {
60
+ const metadataModes = options.metadataOrder.map((key) => {
61
+ const value = options.metadata[key];
62
+ return typeof value === 'string' ? value : null;
63
+ });
64
+ return resolveRequiresCloudFlag({
65
+ boolFlags: options.boolFlags,
66
+ metadataModes,
67
+ parseMode: options.parseMode
68
+ });
69
+ }
@@ -0,0 +1 @@
1
+ export { CONTROL_PLANE_RUN_REQUEST_SCHEMA, CONTROL_PLANE_RUN_REQUEST_VERSION, validateRunRequestV2 } from './run-request.js';