openlinear 0.1.3

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.
@@ -0,0 +1,74 @@
1
+ import { z } from 'zod';
2
+
3
+ declare const ErrorCategory: z.ZodEnum<["AUTH", "RATE_LIMIT", "MERGE_CONFLICT", "TIMEOUT", "UNKNOWN"]>;
4
+ declare const ExecutionStatus: z.ZodEnum<["pending", "running", "completed", "failed", "cancelled"]>;
5
+ declare const ExecutionMetadataSyncSchema: z.ZodObject<{
6
+ taskId: z.ZodString;
7
+ runId: z.ZodString;
8
+ status: z.ZodEnum<["pending", "running", "completed", "failed", "cancelled"]>;
9
+ startedAt: z.ZodOptional<z.ZodString>;
10
+ completedAt: z.ZodOptional<z.ZodString>;
11
+ durationMs: z.ZodOptional<z.ZodNumber>;
12
+ progress: z.ZodOptional<z.ZodNumber>;
13
+ branch: z.ZodOptional<z.ZodString>;
14
+ commitSha: z.ZodOptional<z.ZodString>;
15
+ prUrl: z.ZodOptional<z.ZodString>;
16
+ prNumber: z.ZodOptional<z.ZodNumber>;
17
+ outcome: z.ZodOptional<z.ZodString>;
18
+ errorCategory: z.ZodOptional<z.ZodEnum<["AUTH", "RATE_LIMIT", "MERGE_CONFLICT", "TIMEOUT", "UNKNOWN"]>>;
19
+ filesChanged: z.ZodOptional<z.ZodNumber>;
20
+ toolsExecuted: z.ZodOptional<z.ZodNumber>;
21
+ }, "strict", z.ZodTypeAny, {
22
+ status: "pending" | "running" | "completed" | "failed" | "cancelled";
23
+ taskId: string;
24
+ runId: string;
25
+ startedAt?: string | undefined;
26
+ completedAt?: string | undefined;
27
+ durationMs?: number | undefined;
28
+ progress?: number | undefined;
29
+ branch?: string | undefined;
30
+ commitSha?: string | undefined;
31
+ prUrl?: string | undefined;
32
+ prNumber?: number | undefined;
33
+ outcome?: string | undefined;
34
+ errorCategory?: "AUTH" | "RATE_LIMIT" | "MERGE_CONFLICT" | "TIMEOUT" | "UNKNOWN" | undefined;
35
+ filesChanged?: number | undefined;
36
+ toolsExecuted?: number | undefined;
37
+ }, {
38
+ status: "pending" | "running" | "completed" | "failed" | "cancelled";
39
+ taskId: string;
40
+ runId: string;
41
+ startedAt?: string | undefined;
42
+ completedAt?: string | undefined;
43
+ durationMs?: number | undefined;
44
+ progress?: number | undefined;
45
+ branch?: string | undefined;
46
+ commitSha?: string | undefined;
47
+ prUrl?: string | undefined;
48
+ prNumber?: number | undefined;
49
+ outcome?: string | undefined;
50
+ errorCategory?: "AUTH" | "RATE_LIMIT" | "MERGE_CONFLICT" | "TIMEOUT" | "UNKNOWN" | undefined;
51
+ filesChanged?: number | undefined;
52
+ toolsExecuted?: number | undefined;
53
+ }>;
54
+ type ExecutionMetadataSync = z.infer<typeof ExecutionMetadataSyncSchema>;
55
+ declare function validateExecutionMetadataSync(payload: unknown): ExecutionMetadataSync;
56
+ declare function safeValidateExecutionMetadataSync(payload: unknown): {
57
+ success: true;
58
+ data: ExecutionMetadataSync;
59
+ } | {
60
+ success: false;
61
+ error: z.ZodError;
62
+ };
63
+ declare function checkExecutionMetadataSync(payload: unknown): {
64
+ valid: boolean;
65
+ issues?: string[];
66
+ };
67
+ declare const FORBIDDEN_SYNC_FIELDS: readonly ["prompt", "logs", "toolLogs", "executionLogs", "repoPath", "accessToken", "apiKey", "passwordHash", "jwt", "client", "timeoutId", "rawOutput", "diff", "fileContents", "env", "environment", "processEnv"];
68
+ declare function isForbiddenField(field: string): boolean;
69
+ declare function sanitizePayload(payload: Record<string, any>): {
70
+ sanitized: Record<string, any>;
71
+ removed: string[];
72
+ };
73
+
74
+ export { ErrorCategory, type ExecutionMetadataSync, ExecutionMetadataSyncSchema, ExecutionStatus, FORBIDDEN_SYNC_FIELDS, checkExecutionMetadataSync, isForbiddenField, safeValidateExecutionMetadataSync, sanitizePayload, validateExecutionMetadataSync };
@@ -0,0 +1,74 @@
1
+ import { z } from 'zod';
2
+
3
+ declare const ErrorCategory: z.ZodEnum<["AUTH", "RATE_LIMIT", "MERGE_CONFLICT", "TIMEOUT", "UNKNOWN"]>;
4
+ declare const ExecutionStatus: z.ZodEnum<["pending", "running", "completed", "failed", "cancelled"]>;
5
+ declare const ExecutionMetadataSyncSchema: z.ZodObject<{
6
+ taskId: z.ZodString;
7
+ runId: z.ZodString;
8
+ status: z.ZodEnum<["pending", "running", "completed", "failed", "cancelled"]>;
9
+ startedAt: z.ZodOptional<z.ZodString>;
10
+ completedAt: z.ZodOptional<z.ZodString>;
11
+ durationMs: z.ZodOptional<z.ZodNumber>;
12
+ progress: z.ZodOptional<z.ZodNumber>;
13
+ branch: z.ZodOptional<z.ZodString>;
14
+ commitSha: z.ZodOptional<z.ZodString>;
15
+ prUrl: z.ZodOptional<z.ZodString>;
16
+ prNumber: z.ZodOptional<z.ZodNumber>;
17
+ outcome: z.ZodOptional<z.ZodString>;
18
+ errorCategory: z.ZodOptional<z.ZodEnum<["AUTH", "RATE_LIMIT", "MERGE_CONFLICT", "TIMEOUT", "UNKNOWN"]>>;
19
+ filesChanged: z.ZodOptional<z.ZodNumber>;
20
+ toolsExecuted: z.ZodOptional<z.ZodNumber>;
21
+ }, "strict", z.ZodTypeAny, {
22
+ status: "pending" | "running" | "completed" | "failed" | "cancelled";
23
+ taskId: string;
24
+ runId: string;
25
+ startedAt?: string | undefined;
26
+ completedAt?: string | undefined;
27
+ durationMs?: number | undefined;
28
+ progress?: number | undefined;
29
+ branch?: string | undefined;
30
+ commitSha?: string | undefined;
31
+ prUrl?: string | undefined;
32
+ prNumber?: number | undefined;
33
+ outcome?: string | undefined;
34
+ errorCategory?: "AUTH" | "RATE_LIMIT" | "MERGE_CONFLICT" | "TIMEOUT" | "UNKNOWN" | undefined;
35
+ filesChanged?: number | undefined;
36
+ toolsExecuted?: number | undefined;
37
+ }, {
38
+ status: "pending" | "running" | "completed" | "failed" | "cancelled";
39
+ taskId: string;
40
+ runId: string;
41
+ startedAt?: string | undefined;
42
+ completedAt?: string | undefined;
43
+ durationMs?: number | undefined;
44
+ progress?: number | undefined;
45
+ branch?: string | undefined;
46
+ commitSha?: string | undefined;
47
+ prUrl?: string | undefined;
48
+ prNumber?: number | undefined;
49
+ outcome?: string | undefined;
50
+ errorCategory?: "AUTH" | "RATE_LIMIT" | "MERGE_CONFLICT" | "TIMEOUT" | "UNKNOWN" | undefined;
51
+ filesChanged?: number | undefined;
52
+ toolsExecuted?: number | undefined;
53
+ }>;
54
+ type ExecutionMetadataSync = z.infer<typeof ExecutionMetadataSyncSchema>;
55
+ declare function validateExecutionMetadataSync(payload: unknown): ExecutionMetadataSync;
56
+ declare function safeValidateExecutionMetadataSync(payload: unknown): {
57
+ success: true;
58
+ data: ExecutionMetadataSync;
59
+ } | {
60
+ success: false;
61
+ error: z.ZodError;
62
+ };
63
+ declare function checkExecutionMetadataSync(payload: unknown): {
64
+ valid: boolean;
65
+ issues?: string[];
66
+ };
67
+ declare const FORBIDDEN_SYNC_FIELDS: readonly ["prompt", "logs", "toolLogs", "executionLogs", "repoPath", "accessToken", "apiKey", "passwordHash", "jwt", "client", "timeoutId", "rawOutput", "diff", "fileContents", "env", "environment", "processEnv"];
68
+ declare function isForbiddenField(field: string): boolean;
69
+ declare function sanitizePayload(payload: Record<string, any>): {
70
+ sanitized: Record<string, any>;
71
+ removed: string[];
72
+ };
73
+
74
+ export { ErrorCategory, type ExecutionMetadataSync, ExecutionMetadataSyncSchema, ExecutionStatus, FORBIDDEN_SYNC_FIELDS, checkExecutionMetadataSync, isForbiddenField, safeValidateExecutionMetadataSync, sanitizePayload, validateExecutionMetadataSync };
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/validation/index.ts
21
+ var validation_exports = {};
22
+ __export(validation_exports, {
23
+ ErrorCategory: () => ErrorCategory,
24
+ ExecutionMetadataSyncSchema: () => ExecutionMetadataSyncSchema,
25
+ ExecutionStatus: () => ExecutionStatus,
26
+ FORBIDDEN_SYNC_FIELDS: () => FORBIDDEN_SYNC_FIELDS,
27
+ checkExecutionMetadataSync: () => checkExecutionMetadataSync,
28
+ isForbiddenField: () => isForbiddenField,
29
+ safeValidateExecutionMetadataSync: () => safeValidateExecutionMetadataSync,
30
+ sanitizePayload: () => sanitizePayload,
31
+ validateExecutionMetadataSync: () => validateExecutionMetadataSync
32
+ });
33
+ module.exports = __toCommonJS(validation_exports);
34
+
35
+ // src/validation/security.ts
36
+ var import_zod = require("zod");
37
+ var ErrorCategory = import_zod.z.enum([
38
+ "AUTH",
39
+ "RATE_LIMIT",
40
+ "MERGE_CONFLICT",
41
+ "TIMEOUT",
42
+ "UNKNOWN"
43
+ ]);
44
+ var ExecutionStatus = import_zod.z.enum([
45
+ "pending",
46
+ "running",
47
+ "completed",
48
+ "failed",
49
+ "cancelled"
50
+ ]);
51
+ var ExecutionMetadataSyncSchema = import_zod.z.object({
52
+ taskId: import_zod.z.string(),
53
+ runId: import_zod.z.string(),
54
+ status: ExecutionStatus,
55
+ startedAt: import_zod.z.string().datetime().optional(),
56
+ completedAt: import_zod.z.string().datetime().optional(),
57
+ durationMs: import_zod.z.number().int().min(0).optional(),
58
+ progress: import_zod.z.number().int().min(0).max(100).optional(),
59
+ branch: import_zod.z.string().optional(),
60
+ commitSha: import_zod.z.string().optional(),
61
+ prUrl: import_zod.z.string().url().optional(),
62
+ prNumber: import_zod.z.number().int().positive().optional(),
63
+ outcome: import_zod.z.string().max(500).optional(),
64
+ errorCategory: ErrorCategory.optional(),
65
+ filesChanged: import_zod.z.number().int().min(0).optional(),
66
+ toolsExecuted: import_zod.z.number().int().min(0).optional()
67
+ }).strict();
68
+ function validateExecutionMetadataSync(payload) {
69
+ return ExecutionMetadataSyncSchema.parse(payload);
70
+ }
71
+ function safeValidateExecutionMetadataSync(payload) {
72
+ const result = ExecutionMetadataSyncSchema.safeParse(payload);
73
+ if (result.success) {
74
+ return { success: true, data: result.data };
75
+ } else {
76
+ return { success: false, error: result.error };
77
+ }
78
+ }
79
+ function checkExecutionMetadataSync(payload) {
80
+ const result = ExecutionMetadataSyncSchema.safeParse(payload);
81
+ if (result.success) {
82
+ return { valid: true };
83
+ } else {
84
+ return {
85
+ valid: false,
86
+ issues: result.error.errors.map(
87
+ (e) => `${e.path.join(".")}: ${e.message}`
88
+ )
89
+ };
90
+ }
91
+ }
92
+ var FORBIDDEN_SYNC_FIELDS = [
93
+ "prompt",
94
+ "logs",
95
+ "toolLogs",
96
+ "executionLogs",
97
+ "repoPath",
98
+ "accessToken",
99
+ "apiKey",
100
+ "passwordHash",
101
+ "jwt",
102
+ "client",
103
+ "timeoutId",
104
+ "rawOutput",
105
+ "diff",
106
+ "fileContents",
107
+ "env",
108
+ "environment",
109
+ "processEnv"
110
+ ];
111
+ function isForbiddenField(field) {
112
+ return FORBIDDEN_SYNC_FIELDS.includes(field);
113
+ }
114
+ function sanitizePayload(payload) {
115
+ const sanitized = {};
116
+ const removed = [];
117
+ for (const [key, value] of Object.entries(payload)) {
118
+ if (isForbiddenField(key)) {
119
+ removed.push(key);
120
+ } else {
121
+ sanitized[key] = value;
122
+ }
123
+ }
124
+ return { sanitized, removed };
125
+ }
126
+ // Annotate the CommonJS export names for ESM import in node:
127
+ 0 && (module.exports = {
128
+ ErrorCategory,
129
+ ExecutionMetadataSyncSchema,
130
+ ExecutionStatus,
131
+ FORBIDDEN_SYNC_FIELDS,
132
+ checkExecutionMetadataSync,
133
+ isForbiddenField,
134
+ safeValidateExecutionMetadataSync,
135
+ sanitizePayload,
136
+ validateExecutionMetadataSync
137
+ });
@@ -0,0 +1,22 @@
1
+ import {
2
+ ErrorCategory,
3
+ ExecutionMetadataSyncSchema,
4
+ ExecutionStatus,
5
+ FORBIDDEN_SYNC_FIELDS,
6
+ checkExecutionMetadataSync,
7
+ isForbiddenField,
8
+ safeValidateExecutionMetadataSync,
9
+ sanitizePayload,
10
+ validateExecutionMetadataSync
11
+ } from "../chunk-P3FFNK6N.mjs";
12
+ export {
13
+ ErrorCategory,
14
+ ExecutionMetadataSyncSchema,
15
+ ExecutionStatus,
16
+ FORBIDDEN_SYNC_FIELDS,
17
+ checkExecutionMetadataSync,
18
+ isForbiddenField,
19
+ safeValidateExecutionMetadataSync,
20
+ sanitizePayload,
21
+ validateExecutionMetadataSync
22
+ };
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "openlinear",
3
+ "version": "0.1.3",
4
+ "description": "OpenLinear launcher, installer, and validation utilities",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/kaizen403/openlinear"
9
+ },
10
+ "main": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "import": "./dist/index.js",
15
+ "require": "./dist/index.cjs",
16
+ "types": "./dist/index.d.ts"
17
+ },
18
+ "./types": {
19
+ "import": "./dist/types/index.js",
20
+ "require": "./dist/types/index.cjs",
21
+ "types": "./dist/types/index.d.ts"
22
+ },
23
+ "./validation": {
24
+ "import": "./dist/validation/index.js",
25
+ "require": "./dist/validation/index.cjs",
26
+ "types": "./dist/validation/index.d.ts"
27
+ },
28
+ "./config": {
29
+ "import": "./dist/config/index.js",
30
+ "require": "./dist/config/index.cjs",
31
+ "types": "./dist/config/index.d.ts"
32
+ }
33
+ },
34
+ "bin": {
35
+ "openlinear": "bin/openlinear.js"
36
+ },
37
+ "files": [
38
+ "bin",
39
+ "scripts",
40
+ "dist",
41
+ "src"
42
+ ],
43
+ "scripts": {
44
+ "build": "tsup src/index.ts src/types/index.ts src/validation/index.ts src/config/index.ts --format cjs,esm --dts",
45
+ "postinstall": "node scripts/postinstall.js",
46
+ "prepublishOnly": "npm run build"
47
+ },
48
+ "engines": {
49
+ "node": ">=18"
50
+ },
51
+ "publishConfig": {
52
+ "access": "public"
53
+ },
54
+ "dependencies": {
55
+ "zod": "^3.25.6"
56
+ },
57
+ "devDependencies": {
58
+ "tsup": "^8.0.0",
59
+ "typescript": "^5.4.0"
60
+ }
61
+ }
@@ -0,0 +1,65 @@
1
+ const fs = require('node:fs');
2
+ const https = require('node:https');
3
+ const os = require('node:os');
4
+ const path = require('node:path');
5
+
6
+ const packageJson = require('../package.json');
7
+
8
+ const platform = process.platform;
9
+ const arch = process.arch;
10
+
11
+ if (platform !== 'linux' || arch !== 'x64') {
12
+ console.log('OpenLinear installer currently supports Linux x64 only.');
13
+ process.exit(0);
14
+ }
15
+
16
+ const baseUrl = process.env.OPENLINEAR_RELEASE_BASE_URL ||
17
+ `https://github.com/kaizen403/openlinear/releases/download/v${packageJson.version}`;
18
+ const fileName = `openlinear-${packageJson.version}-x86_64.AppImage`;
19
+ const downloadUrl = `${baseUrl}/${fileName}`;
20
+
21
+ const installDir = path.join(os.homedir(), '.openlinear');
22
+ const targetPath = path.join(installDir, 'openlinear.AppImage');
23
+
24
+ function download(url, destination) {
25
+ return new Promise((resolve, reject) => {
26
+ const request = https.get(url, (response) => {
27
+ if (response.statusCode && response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
28
+ response.resume();
29
+ download(response.headers.location, destination).then(resolve).catch(reject);
30
+ return;
31
+ }
32
+
33
+ if (response.statusCode !== 200) {
34
+ response.resume();
35
+ reject(new Error(`Download failed with status ${response.statusCode}`));
36
+ return;
37
+ }
38
+
39
+ const fileStream = fs.createWriteStream(destination);
40
+ response.pipe(fileStream);
41
+ fileStream.on('finish', () => {
42
+ fileStream.close(resolve);
43
+ });
44
+ fileStream.on('error', (err) => {
45
+ fileStream.close();
46
+ reject(err);
47
+ });
48
+ });
49
+
50
+ request.on('error', reject);
51
+ });
52
+ }
53
+
54
+ async function main() {
55
+ try {
56
+ fs.mkdirSync(installDir, { recursive: true });
57
+ await download(downloadUrl, targetPath);
58
+ fs.chmodSync(targetPath, 0o755);
59
+ console.log(`OpenLinear AppImage downloaded to ${targetPath}`);
60
+ } catch (error) {
61
+ console.error(`Failed to download OpenLinear AppImage: ${error.message}`);
62
+ }
63
+ }
64
+
65
+ main();
@@ -0,0 +1,121 @@
1
+ import { z } from 'zod';
2
+
3
+ export const FeatureFlagsSchema = z.object({
4
+ LOCAL_EXECUTION_ENABLED: z
5
+ .enum(['true', 'false'])
6
+ .default('false')
7
+ .transform((v) => v === 'true'),
8
+ SERVER_EXECUTION_ENABLED: z
9
+ .enum(['true', 'false'])
10
+ .default('true')
11
+ .transform((v) => v === 'true'),
12
+ CANARY_PERCENTAGE: z
13
+ .string()
14
+ .default('0')
15
+ .transform((v) => parseInt(v, 10))
16
+ .refine((v) => v >= 0 && v <= 100, {
17
+ message: 'CANARY_PERCENTAGE must be between 0 and 100',
18
+ }),
19
+ FORCE_LOCAL_EXECUTION: z
20
+ .enum(['true', 'false'])
21
+ .default('false')
22
+ .transform((v) => v === 'true'),
23
+ KILL_SWITCH_LOCAL_EXECUTION: z
24
+ .enum(['true', 'false'])
25
+ .default('false')
26
+ .transform((v) => v === 'true'),
27
+ });
28
+
29
+ export type FeatureFlags = z.infer<typeof FeatureFlagsSchema>;
30
+
31
+ export function parseFeatureFlags(env: Record<string, string | undefined> = process.env): FeatureFlags {
32
+ return FeatureFlagsSchema.parse(env);
33
+ }
34
+
35
+ export function getFeatureFlags(): FeatureFlags {
36
+ return parseFeatureFlags();
37
+ }
38
+
39
+ export function isLocalExecutionEnabled(userId: string, flags: FeatureFlags = getFeatureFlags()): boolean {
40
+ if (flags.KILL_SWITCH_LOCAL_EXECUTION) {
41
+ return false;
42
+ }
43
+
44
+ if (flags.FORCE_LOCAL_EXECUTION) {
45
+ return true;
46
+ }
47
+
48
+ if (!flags.LOCAL_EXECUTION_ENABLED) {
49
+ return false;
50
+ }
51
+
52
+ if (flags.CANARY_PERCENTAGE >= 100) {
53
+ return true;
54
+ }
55
+
56
+ if (flags.CANARY_PERCENTAGE <= 0) {
57
+ return false;
58
+ }
59
+
60
+ const hash = hashString(userId);
61
+ const userPercentage = (hash % 100) + 1;
62
+
63
+ return userPercentage <= flags.CANARY_PERCENTAGE;
64
+ }
65
+
66
+ export function isServerExecutionEnabled(flags: FeatureFlags = getFeatureFlags()): boolean {
67
+ return flags.SERVER_EXECUTION_ENABLED;
68
+ }
69
+
70
+ export function validateFlagConfiguration(flags: FeatureFlags): { valid: boolean; errors: string[] } {
71
+ const errors: string[] = [];
72
+
73
+ if (flags.FORCE_LOCAL_EXECUTION && flags.KILL_SWITCH_LOCAL_EXECUTION) {
74
+ errors.push('Cannot enable both FORCE_LOCAL_EXECUTION and KILL_SWITCH_LOCAL_EXECUTION');
75
+ }
76
+
77
+ if (!flags.LOCAL_EXECUTION_ENABLED && !flags.SERVER_EXECUTION_ENABLED) {
78
+ errors.push('At least one execution mode must be enabled');
79
+ }
80
+
81
+ return {
82
+ valid: errors.length === 0,
83
+ errors,
84
+ };
85
+ }
86
+
87
+ function hashString(str: string): number {
88
+ let hash = 0;
89
+ for (let i = 0; i < str.length; i++) {
90
+ const char = str.charCodeAt(i);
91
+ hash = (hash << 5) - hash + char;
92
+ hash = hash & hash;
93
+ }
94
+ return Math.abs(hash);
95
+ }
96
+
97
+ export function getMigrationPhase(flags: FeatureFlags = getFeatureFlags()):
98
+ | 'shadow'
99
+ | 'canary'
100
+ | 'cutover'
101
+ | 'rollback'
102
+ | 'unknown' {
103
+
104
+ if (flags.KILL_SWITCH_LOCAL_EXECUTION) {
105
+ return 'rollback';
106
+ }
107
+
108
+ if (!flags.SERVER_EXECUTION_ENABLED) {
109
+ return 'cutover';
110
+ }
111
+
112
+ if (flags.LOCAL_EXECUTION_ENABLED && flags.CANARY_PERCENTAGE > 0) {
113
+ return 'canary';
114
+ }
115
+
116
+ if (flags.LOCAL_EXECUTION_ENABLED && flags.CANARY_PERCENTAGE === 0) {
117
+ return 'shadow';
118
+ }
119
+
120
+ return 'unknown';
121
+ }
@@ -0,0 +1 @@
1
+ export * from './feature-flags';
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ export * from './config/feature-flags';
2
+ export {
3
+ isForbiddenField,
4
+ sanitizePayload
5
+ } from './validation/security';
6
+ export * from './types';
@@ -0,0 +1,116 @@
1
+ import { z } from 'zod';
2
+
3
+ export const ErrorCategory = z.enum([
4
+ 'AUTH',
5
+ 'RATE_LIMIT',
6
+ 'MERGE_CONFLICT',
7
+ 'TIMEOUT',
8
+ 'UNKNOWN'
9
+ ]);
10
+
11
+ export const ExecutionStatus = z.enum([
12
+ 'pending',
13
+ 'running',
14
+ 'completed',
15
+ 'failed',
16
+ 'cancelled'
17
+ ]);
18
+
19
+ export const ExecutionMetadataSyncSchema = z.object({
20
+ taskId: z.string(),
21
+ runId: z.string(),
22
+ status: ExecutionStatus,
23
+ startedAt: z.string().datetime().optional(),
24
+ completedAt: z.string().datetime().optional(),
25
+ durationMs: z.number().int().min(0).optional(),
26
+ progress: z.number().int().min(0).max(100).optional(),
27
+ branch: z.string().optional(),
28
+ commitSha: z.string().optional(),
29
+ prUrl: z.string().url().optional(),
30
+ prNumber: z.number().int().positive().optional(),
31
+ outcome: z.string().max(500).optional(),
32
+ errorCategory: ErrorCategory.optional(),
33
+ filesChanged: z.number().int().min(0).optional(),
34
+ toolsExecuted: z.number().int().min(0).optional(),
35
+ }).strict();
36
+
37
+ export type ExecutionMetadataSync = z.infer<typeof ExecutionMetadataSyncSchema>;
38
+
39
+ export function validateExecutionMetadataSync(payload: unknown): ExecutionMetadataSync {
40
+ return ExecutionMetadataSyncSchema.parse(payload);
41
+ }
42
+
43
+ export function safeValidateExecutionMetadataSync(payload: unknown):
44
+ | { success: true; data: ExecutionMetadataSync }
45
+ | { success: false; error: z.ZodError } {
46
+ const result = ExecutionMetadataSyncSchema.safeParse(payload);
47
+
48
+ if (result.success) {
49
+ return { success: true, data: result.data };
50
+ } else {
51
+ return { success: false, error: result.error };
52
+ }
53
+ }
54
+
55
+ export function checkExecutionMetadataSync(payload: unknown): {
56
+ valid: boolean;
57
+ issues?: string[];
58
+ } {
59
+ const result = ExecutionMetadataSyncSchema.safeParse(payload);
60
+
61
+ if (result.success) {
62
+ return { valid: true };
63
+ } else {
64
+ return {
65
+ valid: false,
66
+ issues: result.error.errors.map(e =>
67
+ `${e.path.join('.')}: ${e.message}`
68
+ )
69
+ };
70
+ }
71
+ }
72
+
73
+ export function validateExecutionMetadataMiddleware() {
74
+ return (req: any, res: any, next: any) => {
75
+ const result = safeValidateExecutionMetadataSync(req.body);
76
+
77
+ if (!result.success) {
78
+ const hasUnknownKeys = result.error.errors.some(e =>
79
+ e.message.includes('Unrecognized key') ||
80
+ e.code === 'unrecognized_keys'
81
+ );
82
+
83
+ return res.status(400).json({
84
+ error: 'Invalid sync payload',
85
+ code: hasUnknownKeys ? 'FORBIDDEN_FIELDS' : 'VALIDATION_ERROR',
86
+ details: result.error.errors.map(e => ({
87
+ field: e.path.join('.'),
88
+ message: e.message
89
+ }))
90
+ });
91
+ }
92
+
93
+ req.validatedMetadata = result.data;
94
+ next();
95
+ };
96
+ }
97
+
98
+ export const FORBIDDEN_SYNC_FIELDS = [
99
+ 'prompt',
100
+ 'logs',
101
+ 'toolLogs',
102
+ 'executionLogs',
103
+ 'repoPath',
104
+ 'accessToken',
105
+ 'apiKey',
106
+ 'passwordHash',
107
+ 'jwt',
108
+ 'client',
109
+ 'timeoutId',
110
+ 'rawOutput',
111
+ 'diff',
112
+ 'fileContents',
113
+ 'env',
114
+ 'environment',
115
+ 'processEnv',
116
+ ] as const;
@@ -0,0 +1 @@
1
+ export * from './execution-metadata';
@@ -0,0 +1 @@
1
+ export * from './security';