@opengeni/contracts 0.39.0 → 0.40.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.
- package/dist/{chunk-PCTCJEAF.js → chunk-5HR2GPSC.js} +3350 -3118
- package/dist/chunk-5HR2GPSC.js.map +1 -0
- package/dist/event-preview.d.ts +6 -6
- package/dist/google-drive.js +1 -1
- package/dist/index.d.ts +563 -17
- package/dist/index.js +53 -17
- package/dist/mcp-receipts.d.ts +96 -0
- package/dist/retained-output.d.ts +59 -6
- package/package.json +1 -1
- package/src/event-preview.ts +6 -6
- package/src/index.ts +289 -37
- package/src/mcp-receipts.ts +281 -0
- package/src/retained-output.ts +101 -8
- package/dist/chunk-PCTCJEAF.js.map +0 -1
- package/dist/secret-redaction.d.ts +0 -40
- package/src/secret-redaction.ts +0 -364
package/src/index.ts
CHANGED
|
@@ -36,6 +36,19 @@ export {
|
|
|
36
36
|
normalizeWorkspaceArtifactSlug,
|
|
37
37
|
} from "./artifacts";
|
|
38
38
|
|
|
39
|
+
export {
|
|
40
|
+
MCP_MUTATION_RECEIPT_MAX_BYTES,
|
|
41
|
+
MCP_MUTATION_RECEIPT_VERSION,
|
|
42
|
+
McpMutationReceipt,
|
|
43
|
+
McpMutationReceiptIdempotencyStatus,
|
|
44
|
+
McpMutationReceiptOutcome,
|
|
45
|
+
McpMutationResource,
|
|
46
|
+
type McpMutationReceipt as McpMutationReceiptType,
|
|
47
|
+
type McpMutationReceiptIdempotencyStatus as McpMutationReceiptIdempotencyStatusType,
|
|
48
|
+
type McpMutationReceiptOutcome as McpMutationReceiptOutcomeType,
|
|
49
|
+
type McpMutationResource as McpMutationResourceType,
|
|
50
|
+
} from "./mcp-receipts";
|
|
51
|
+
|
|
39
52
|
export {
|
|
40
53
|
SESSION_EVENT_PAYLOAD_MAX_BYTES,
|
|
41
54
|
approximateSessionEventTokens,
|
|
@@ -53,6 +66,11 @@ export {
|
|
|
53
66
|
} from "./event-preview";
|
|
54
67
|
|
|
55
68
|
export {
|
|
69
|
+
COMPUTER_SCREENSHOT_MAX_BYTES,
|
|
70
|
+
COMPUTER_SCREENSHOT_MAX_DIMENSION,
|
|
71
|
+
COMPUTER_SCREENSHOT_MAX_PIXELS,
|
|
72
|
+
COMPUTER_SCREENSHOT_RETENTION_MS,
|
|
73
|
+
COMPUTER_SCREENSHOT_WORKSPACE_QUOTA_BYTES,
|
|
56
74
|
RETAINED_OUTPUT_DEFAULT_PAGE_BYTES,
|
|
57
75
|
RETAINED_OUTPUT_MAX_PAGE_BYTES,
|
|
58
76
|
RETAINED_OUTPUT_RECEIPT_MAX_BYTES,
|
|
@@ -63,12 +81,14 @@ export {
|
|
|
63
81
|
RetainedOutputKind,
|
|
64
82
|
RetainedOutputUnavailableReason,
|
|
65
83
|
retainedArtifactReferenceFromFile,
|
|
84
|
+
retainedScreenshotReferenceFromFile,
|
|
66
85
|
retainedOutputUnavailable,
|
|
67
86
|
resolveRetainedOutputRange,
|
|
68
87
|
validateRetainedOutputEvidence,
|
|
69
88
|
type RetainedArtifactFileInput,
|
|
70
89
|
type RetainedArtifactMetadata,
|
|
71
90
|
type RetainedArtifactReference,
|
|
91
|
+
type RetainedScreenshotArtifactInput,
|
|
72
92
|
type RetainedArtifactUnavailable,
|
|
73
93
|
type RetainedOutputAvailableEvidence,
|
|
74
94
|
type RetainedOutputEvidence,
|
|
@@ -596,9 +616,9 @@ export const Permission = z.enum([
|
|
|
596
616
|
"sessions:control",
|
|
597
617
|
// sandbox workspace (sandbox contract §C.3 / crosscut PART 1.2). stream:view is a
|
|
598
618
|
// REAL, distinct permission — strictly BROADER than sessions:read — because the
|
|
599
|
-
// pixel plane (Channel B)
|
|
600
|
-
//
|
|
601
|
-
//
|
|
619
|
+
// pixel plane (Channel B) exposes raw pixels: a viewer can see content the
|
|
620
|
+
// structured Channel-A event log never captured. sessions:read is NOT
|
|
621
|
+
// permission to watch raw pixels.
|
|
602
622
|
"stream:view",
|
|
603
623
|
// SEPARATE from stream:view: raw input to the desktop (bypasses approvalQueue /
|
|
604
624
|
// interrupt). NEVER granted by default in v1 (the input plane is OFF —
|
|
@@ -629,8 +649,14 @@ export const Permission = z.enum([
|
|
|
629
649
|
"environments:manage",
|
|
630
650
|
/** @deprecated alias of variable-sets:use */
|
|
631
651
|
"environments:use",
|
|
652
|
+
"variable-sets:list",
|
|
653
|
+
"variable-sets:read",
|
|
654
|
+
"variable-sets:write",
|
|
632
655
|
"variable-sets:manage",
|
|
633
656
|
"variable-sets:use",
|
|
657
|
+
"secrets:list",
|
|
658
|
+
"secrets:read",
|
|
659
|
+
"secrets:write",
|
|
634
660
|
// Attach or rotate per-session third-party MCP server credentials. Deliberately
|
|
635
661
|
// not part of the worker's default first-party MCP permission set: a sandboxed
|
|
636
662
|
// agent must not be able to hand itself new bearer credentials.
|
|
@@ -715,6 +741,7 @@ export const FIRST_PARTY_MCP_TOOL_NAMES = [
|
|
|
715
741
|
"sandbox_swap",
|
|
716
742
|
"run_on",
|
|
717
743
|
"sandbox_provision",
|
|
744
|
+
"connected_machine_remove",
|
|
718
745
|
"rig_list",
|
|
719
746
|
"rig_get",
|
|
720
747
|
"rig_propose_change",
|
|
@@ -731,6 +758,7 @@ export const FIRST_PARTY_MCP_TOOL_NAMES = [
|
|
|
731
758
|
"set_other_session_title",
|
|
732
759
|
"variable_set_list",
|
|
733
760
|
"environment_list",
|
|
761
|
+
"variable_set_get_variable",
|
|
734
762
|
"variable_set_set_variable",
|
|
735
763
|
"environment_set_variable",
|
|
736
764
|
"github_connect_link",
|
|
@@ -1262,6 +1290,9 @@ export const WorkspaceSettingsSchema = z
|
|
|
1262
1290
|
// Default compaction strategy for NEW Codex sessions created in this
|
|
1263
1291
|
// workspace. Absent ⇒ remote_v2. Non-Codex sessions always freeze portable.
|
|
1264
1292
|
codexCompactionDefault: CodexCompactionMode.optional(),
|
|
1293
|
+
// Whether agents may expose and invoke the built-in structured human-input
|
|
1294
|
+
// tool. Absent preserves the historical enabled behavior.
|
|
1295
|
+
agentHumanInputEnabled: z.boolean().optional(),
|
|
1265
1296
|
// Optional Slack reaction invocation. Absent/invalid fails closed to the
|
|
1266
1297
|
// disabled default via resolveWorkspaceSlackReactionSummonSettings.
|
|
1267
1298
|
slackReactionSummon: WorkspaceSlackReactionSummonSettings.optional(),
|
|
@@ -1282,6 +1313,12 @@ export function resolveWorkspaceCodexCompactionDefault(settings: unknown): Codex
|
|
|
1282
1313
|
return parsed.data.codexCompactionDefault ?? "remote_v2";
|
|
1283
1314
|
}
|
|
1284
1315
|
|
|
1316
|
+
/** Whether agents may request structured human input (enabled when unset). */
|
|
1317
|
+
export function resolveWorkspaceAgentHumanInputEnabled(settings: unknown): boolean {
|
|
1318
|
+
const parsed = WorkspaceSettingsSchema.safeParse(settings ?? {});
|
|
1319
|
+
return parsed.success ? parsed.data.agentHumanInputEnabled !== false : true;
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1285
1322
|
/**
|
|
1286
1323
|
* Resolve whether voice input is enabled for a workspace.
|
|
1287
1324
|
*
|
|
@@ -1307,7 +1344,9 @@ export function resolveWorkspaceSlackReactionSummonSettings(
|
|
|
1307
1344
|
return {
|
|
1308
1345
|
enabled: DEFAULT_WORKSPACE_SLACK_REACTION_SUMMON_SETTINGS.enabled,
|
|
1309
1346
|
emoji: DEFAULT_WORKSPACE_SLACK_REACTION_SUMMON_SETTINGS.emoji,
|
|
1310
|
-
channelPolicy: {
|
|
1347
|
+
channelPolicy: {
|
|
1348
|
+
...DEFAULT_WORKSPACE_SLACK_REACTION_SUMMON_SETTINGS.channelPolicy,
|
|
1349
|
+
},
|
|
1311
1350
|
};
|
|
1312
1351
|
}
|
|
1313
1352
|
return configured.channelPolicy.mode === "allowlist"
|
|
@@ -1342,6 +1381,7 @@ export const UpdateWorkspaceSettingsRequest = z
|
|
|
1342
1381
|
transcription: WorkspaceTranscriptionPolicy.optional(),
|
|
1343
1382
|
maxNestedAgentDepth: NestedAgentDepthValue.nullable().optional(),
|
|
1344
1383
|
codexCompactionDefault: CodexCompactionMode.optional(),
|
|
1384
|
+
agentHumanInputEnabled: z.boolean().optional(),
|
|
1345
1385
|
slackReactionSummon: WorkspaceSlackReactionSummonSettings.optional(),
|
|
1346
1386
|
})
|
|
1347
1387
|
.passthrough();
|
|
@@ -1669,6 +1709,11 @@ export const EnrollmentBearerPayload = z.object({
|
|
|
1669
1709
|
workspaceId: z.string().uuid(),
|
|
1670
1710
|
agentId: z.string().uuid(),
|
|
1671
1711
|
enrollmentId: z.string().uuid(),
|
|
1712
|
+
// Backward-compatible credential-family fence. Generationless bearers minted
|
|
1713
|
+
// before migration 0061 parse ONLY as generation 1, matching the migration's
|
|
1714
|
+
// default for existing rows. signEnrollmentBearer serializes the parsed output,
|
|
1715
|
+
// so every newly signed bearer carries this claim explicitly.
|
|
1716
|
+
credentialGeneration: z.number().int().positive().default(1),
|
|
1672
1717
|
// The Account-scoped control-plane subject prefix the agent subscribes to.
|
|
1673
1718
|
subjectPrefix: z.string().min(1),
|
|
1674
1719
|
exp: z.number().int().positive(),
|
|
@@ -1703,7 +1748,13 @@ export async function verifyEnrollmentBearer(
|
|
|
1703
1748
|
if (!constantTimeEqual(signature, expected)) {
|
|
1704
1749
|
return null;
|
|
1705
1750
|
}
|
|
1706
|
-
|
|
1751
|
+
let decoded: unknown;
|
|
1752
|
+
try {
|
|
1753
|
+
decoded = JSON.parse(base64UrlDecode(encodedPayload));
|
|
1754
|
+
} catch {
|
|
1755
|
+
return null;
|
|
1756
|
+
}
|
|
1757
|
+
const payload = EnrollmentBearerPayload.safeParse(decoded);
|
|
1707
1758
|
if (!payload.success || payload.data.exp < nowSeconds) {
|
|
1708
1759
|
return null;
|
|
1709
1760
|
}
|
|
@@ -2510,13 +2561,6 @@ export type RunCredentialAuthNeeded = {
|
|
|
2510
2561
|
message?: string;
|
|
2511
2562
|
};
|
|
2512
2563
|
|
|
2513
|
-
export type RunCredentialRedaction = {
|
|
2514
|
-
/** Bounded diagnostic label used only in the replacement marker. */
|
|
2515
|
-
name: string;
|
|
2516
|
-
/** One atomic secret value that must be removed from streamed/audit output. */
|
|
2517
|
-
value: string;
|
|
2518
|
-
};
|
|
2519
|
-
|
|
2520
2564
|
export type RunCredentialsRequest = {
|
|
2521
2565
|
accountId: string;
|
|
2522
2566
|
workspaceId: string;
|
|
@@ -2562,12 +2606,6 @@ export type RunCredentialsResolution =
|
|
|
2562
2606
|
files?: RunCredentialFile[];
|
|
2563
2607
|
/** Environment name to one returned relative file path. */
|
|
2564
2608
|
fileEnvironment?: Record<string, string>;
|
|
2565
|
-
/**
|
|
2566
|
-
* Atomic sensitive values embedded inside credential files or derived
|
|
2567
|
-
* material. Environment values are registered automatically; hosts list
|
|
2568
|
-
* additional file-contained values here so chunked output is redacted.
|
|
2569
|
-
*/
|
|
2570
|
-
redactions?: RunCredentialRedaction[];
|
|
2571
2609
|
/** Earliest material expiry. Null/omitted uses a bounded refresh cadence. */
|
|
2572
2610
|
expiresAt?: string | null;
|
|
2573
2611
|
/** Partial degradation: usable material may coexist with reconnect notices. */
|
|
@@ -2959,6 +2997,93 @@ export function gitCredentialBindingIdForRepository(
|
|
|
2959
2997
|
);
|
|
2960
2998
|
}
|
|
2961
2999
|
|
|
3000
|
+
type GitRemotePathSemantics = "dot_git_alias" | "exact";
|
|
3001
|
+
|
|
3002
|
+
/**
|
|
3003
|
+
* Provider-declared remote-path behavior. Keeping this exhaustive makes a new
|
|
3004
|
+
* provider choose its semantics instead of inheriting GitHub conventions.
|
|
3005
|
+
*/
|
|
3006
|
+
const GIT_REMOTE_PATH_SEMANTICS = {
|
|
3007
|
+
github: "dot_git_alias",
|
|
3008
|
+
gitlab: "dot_git_alias",
|
|
3009
|
+
azure_devops: "exact",
|
|
3010
|
+
} as const satisfies Record<GitCredentialProvider, GitRemotePathSemantics>;
|
|
3011
|
+
|
|
3012
|
+
function gitRemotePathSemantics(
|
|
3013
|
+
provider: GitCredentialProvider | null | undefined,
|
|
3014
|
+
): GitRemotePathSemantics {
|
|
3015
|
+
return provider ? GIT_REMOTE_PATH_SEMANTICS[provider] : "exact";
|
|
3016
|
+
}
|
|
3017
|
+
|
|
3018
|
+
export class RepositoryUriError extends Error {
|
|
3019
|
+
constructor(message: string) {
|
|
3020
|
+
super(message);
|
|
3021
|
+
this.name = "RepositoryUriError";
|
|
3022
|
+
}
|
|
3023
|
+
}
|
|
3024
|
+
|
|
3025
|
+
/**
|
|
3026
|
+
* Normalize only the safe, provider-neutral parts of an HTTPS clone URI.
|
|
3027
|
+
*
|
|
3028
|
+
* The provider-defined path is opaque: this helper never adds or removes a
|
|
3029
|
+
* `.git` suffix. Embedded user info, query parameters, and fragments are not
|
|
3030
|
+
* durable resource identity and are omitted, matching the existing secret-free
|
|
3031
|
+
* resource contract.
|
|
3032
|
+
*/
|
|
3033
|
+
export function normalizeRepositoryTransportUri(uri: string): string {
|
|
3034
|
+
let url: URL;
|
|
3035
|
+
try {
|
|
3036
|
+
url = new URL(uri.trim());
|
|
3037
|
+
} catch {
|
|
3038
|
+
throw new RepositoryUriError(`invalid repository URI: ${uri}`);
|
|
3039
|
+
}
|
|
3040
|
+
if (url.protocol !== "https:" || !url.hostname) {
|
|
3041
|
+
throw new RepositoryUriError("repository resources must use HTTPS Git URLs");
|
|
3042
|
+
}
|
|
3043
|
+
const path = url.pathname.replace(/^\/+|\/+$/g, "");
|
|
3044
|
+
if (path.split("/").filter(Boolean).length < 2) {
|
|
3045
|
+
throw new RepositoryUriError("repository URL must include owner and repo");
|
|
3046
|
+
}
|
|
3047
|
+
return `https://${url.host.toLowerCase()}/${path}`;
|
|
3048
|
+
}
|
|
3049
|
+
|
|
3050
|
+
/**
|
|
3051
|
+
* Return every URI spelling that a provider explicitly declares equivalent.
|
|
3052
|
+
* Exact-path and unqualified providers return only the normalized input URI.
|
|
3053
|
+
*/
|
|
3054
|
+
export function gitRemoteUriAliases(
|
|
3055
|
+
uri: string,
|
|
3056
|
+
provider: GitCredentialProvider | null | undefined,
|
|
3057
|
+
): string[] {
|
|
3058
|
+
const normalizedUri = normalizeRepositoryTransportUri(uri);
|
|
3059
|
+
if (gitRemotePathSemantics(provider) === "exact") {
|
|
3060
|
+
return [normalizedUri];
|
|
3061
|
+
}
|
|
3062
|
+
const base = normalizedUri.replace(/\.git$/, "");
|
|
3063
|
+
return [...new Set([normalizedUri, base, `${base}.git`])];
|
|
3064
|
+
}
|
|
3065
|
+
|
|
3066
|
+
/** Stable remote identity for deduplication and credential-binding ownership. */
|
|
3067
|
+
export function gitRemoteIdentity(
|
|
3068
|
+
uri: string,
|
|
3069
|
+
provider: GitCredentialProvider | null | undefined,
|
|
3070
|
+
): string {
|
|
3071
|
+
const normalizedUri = normalizeRepositoryTransportUri(uri);
|
|
3072
|
+
return gitRemotePathSemantics(provider) === "dot_git_alias"
|
|
3073
|
+
? normalizedUri.replace(/\.git$/, "")
|
|
3074
|
+
: normalizedUri;
|
|
3075
|
+
}
|
|
3076
|
+
|
|
3077
|
+
/** Provider-aware Git credential-helper path aliases, without a leading slash. */
|
|
3078
|
+
export function gitRemotePathAliases(
|
|
3079
|
+
uri: string,
|
|
3080
|
+
provider: GitCredentialProvider | null | undefined,
|
|
3081
|
+
): string[] {
|
|
3082
|
+
return gitRemoteUriAliases(uri, provider).map((alias) =>
|
|
3083
|
+
new URL(alias).pathname.replace(/^\/+|\/+$/g, ""),
|
|
3084
|
+
);
|
|
3085
|
+
}
|
|
3086
|
+
|
|
2962
3087
|
export const FileResourceRef = z.object({
|
|
2963
3088
|
kind: z.literal("file"),
|
|
2964
3089
|
fileId: z.string().uuid(),
|
|
@@ -3039,7 +3164,10 @@ export function resourceMountPathCollisionKey(path: string): string {
|
|
|
3039
3164
|
* GitLab, Azure DevOps, or a custom host do not collide. Encoding the host keeps
|
|
3040
3165
|
* IPv6/custom-port identities inside one portable path segment.
|
|
3041
3166
|
*/
|
|
3042
|
-
export function defaultRepositoryMountPath(
|
|
3167
|
+
export function defaultRepositoryMountPath(
|
|
3168
|
+
uri: string,
|
|
3169
|
+
provider?: GitCredentialProvider | null,
|
|
3170
|
+
): string {
|
|
3043
3171
|
let url: URL;
|
|
3044
3172
|
try {
|
|
3045
3173
|
url = new URL(uri);
|
|
@@ -3049,7 +3177,11 @@ export function defaultRepositoryMountPath(uri: string): string {
|
|
|
3049
3177
|
if (url.protocol !== "https:" || !url.host) {
|
|
3050
3178
|
throw new ResourceMountPathError(`invalid repository URI for mount path: ${uri}`);
|
|
3051
3179
|
}
|
|
3052
|
-
const
|
|
3180
|
+
const remotePath = url.pathname.replace(/^\/+|\/+$/g, "");
|
|
3181
|
+
const repositoryPath =
|
|
3182
|
+
gitRemotePathSemantics(provider) === "dot_git_alias"
|
|
3183
|
+
? remotePath.replace(/\.git$/, "")
|
|
3184
|
+
: remotePath;
|
|
3053
3185
|
const segments = repositoryPath.split("/").filter(Boolean);
|
|
3054
3186
|
if (segments.length < 2) {
|
|
3055
3187
|
throw new ResourceMountPathError(`repository URI must include owner and repo: ${uri}`);
|
|
@@ -3066,7 +3198,7 @@ export function resourceMountPath(resource: ResourceRef): string {
|
|
|
3066
3198
|
if (resource.mountPath) return normalizeResourceMountPath(resource.mountPath);
|
|
3067
3199
|
return resource.kind === "file"
|
|
3068
3200
|
? normalizeResourceMountPath(`${DEFAULT_FILE_RESOURCE_MOUNT_ROOT}/${resource.fileId}`)
|
|
3069
|
-
: defaultRepositoryMountPath(resource.uri);
|
|
3201
|
+
: defaultRepositoryMountPath(resource.uri, gitCredentialProviderForRepository(resource));
|
|
3070
3202
|
}
|
|
3071
3203
|
|
|
3072
3204
|
/** Fail before sandbox execution when two resources share a portable path. */
|
|
@@ -3757,7 +3889,10 @@ export function resourceIdentityKey(resource: ResourceRef): string {
|
|
|
3757
3889
|
if (resource.kind === "file") {
|
|
3758
3890
|
return `file:${resource.fileId}`;
|
|
3759
3891
|
}
|
|
3760
|
-
return `repository:${
|
|
3892
|
+
return `repository:${gitRemoteIdentity(
|
|
3893
|
+
resource.uri,
|
|
3894
|
+
gitCredentialProviderForRepository(resource),
|
|
3895
|
+
)}`;
|
|
3761
3896
|
}
|
|
3762
3897
|
|
|
3763
3898
|
function sortJson(value: unknown): unknown {
|
|
@@ -4314,6 +4449,7 @@ export const SessionAuthorizationOperation = z.enum([
|
|
|
4314
4449
|
"session.viewer.read",
|
|
4315
4450
|
"session.viewer.control",
|
|
4316
4451
|
"session.first_party_mcp.call",
|
|
4452
|
+
"session.secret.read",
|
|
4317
4453
|
"session.toolspace.call",
|
|
4318
4454
|
"session.pin.write",
|
|
4319
4455
|
"session.codex_account.write",
|
|
@@ -5035,9 +5171,9 @@ function withVariableSetIdAlias<T extends z.ZodRawShape>(shape: T) {
|
|
|
5035
5171
|
}, z.object(shape));
|
|
5036
5172
|
}
|
|
5037
5173
|
|
|
5038
|
-
//
|
|
5039
|
-
//
|
|
5040
|
-
//
|
|
5174
|
+
// Generic variable-set reads remain metadata-only. Exact plaintext has one
|
|
5175
|
+
// dedicated response schema so callers cannot accidentally widen another
|
|
5176
|
+
// workspace/session response with secret material.
|
|
5041
5177
|
export const VariableSetVariableMetadata = z.object({
|
|
5042
5178
|
name: VariableSetVariableName,
|
|
5043
5179
|
version: z.number().int().positive(),
|
|
@@ -5050,6 +5186,14 @@ export const WorkspaceEnvironmentVariableMetadata = VariableSetVariableMetadata;
|
|
|
5050
5186
|
/** @deprecated use VariableSetVariableMetadata */
|
|
5051
5187
|
export type WorkspaceEnvironmentVariableMetadata = VariableSetVariableMetadata;
|
|
5052
5188
|
|
|
5189
|
+
export const VariableSetSecret = z.object({
|
|
5190
|
+
variableSetId: z.string().uuid(),
|
|
5191
|
+
name: VariableSetVariableName,
|
|
5192
|
+
version: z.number().int().positive(),
|
|
5193
|
+
value: z.string(),
|
|
5194
|
+
});
|
|
5195
|
+
export type VariableSetSecret = z.infer<typeof VariableSetSecret>;
|
|
5196
|
+
|
|
5053
5197
|
export const VariableSet = z.object({
|
|
5054
5198
|
id: z.string().uuid(),
|
|
5055
5199
|
accountId: z.string().uuid(),
|
|
@@ -5251,7 +5395,11 @@ export type ScheduledTaskStatus = z.infer<typeof ScheduledTaskStatus>;
|
|
|
5251
5395
|
export const ScheduledTaskRunStatus = z.enum(["queued", "dispatched", "failed"]);
|
|
5252
5396
|
export type ScheduledTaskRunStatus = z.infer<typeof ScheduledTaskRunStatus>;
|
|
5253
5397
|
|
|
5254
|
-
export const ScheduledTaskRunMode = z.enum([
|
|
5398
|
+
export const ScheduledTaskRunMode = z.enum([
|
|
5399
|
+
"new_session_per_run",
|
|
5400
|
+
"reusable_session",
|
|
5401
|
+
"existing_session",
|
|
5402
|
+
]);
|
|
5255
5403
|
export type ScheduledTaskRunMode = z.infer<typeof ScheduledTaskRunMode>;
|
|
5256
5404
|
|
|
5257
5405
|
export const ScheduledTaskOverlapPolicy = z.enum(["allow_concurrent", "skip", "buffer_one"]);
|
|
@@ -5315,10 +5463,14 @@ export const ScheduledTask = z.object({
|
|
|
5315
5463
|
runMode: ScheduledTaskRunMode,
|
|
5316
5464
|
overlapPolicy: ScheduledTaskOverlapPolicy,
|
|
5317
5465
|
agentConfig: ScheduledTaskAgentConfig,
|
|
5318
|
-
createdBy: TurnInitiator.default({
|
|
5466
|
+
createdBy: TurnInitiator.default({
|
|
5467
|
+
kind: "service",
|
|
5468
|
+
subjectId: "unattributed-legacy",
|
|
5469
|
+
}),
|
|
5319
5470
|
createdByContext: TurnInitiatorContext.default({}),
|
|
5320
5471
|
personalConnections: z.array(McpPersonalConnectionSummary).default([]),
|
|
5321
5472
|
reusableSessionId: z.string().uuid().nullable(),
|
|
5473
|
+
targetSessionId: z.string().uuid().nullable().default(null),
|
|
5322
5474
|
variableSetId: z.string().uuid().nullable().default(null),
|
|
5323
5475
|
/** @deprecated use variableSetId */
|
|
5324
5476
|
environmentId: z.string().uuid().nullable().default(null),
|
|
@@ -5354,6 +5506,7 @@ export const CreateScheduledTaskRequest = withVariableSetIdAlias({
|
|
|
5354
5506
|
schedule: ScheduledTaskScheduleSpec,
|
|
5355
5507
|
runMode: ScheduledTaskRunMode.default("new_session_per_run"),
|
|
5356
5508
|
overlapPolicy: ScheduledTaskOverlapPolicy.default("allow_concurrent"),
|
|
5509
|
+
targetSessionId: z.string().uuid().nullable().optional(),
|
|
5357
5510
|
agentConfig: ScheduledTaskAgentConfig,
|
|
5358
5511
|
status: ScheduledTaskStatus.default("active"),
|
|
5359
5512
|
variableSetId: z.string().uuid().nullable().optional(),
|
|
@@ -5361,6 +5514,28 @@ export const CreateScheduledTaskRequest = withVariableSetIdAlias({
|
|
|
5361
5514
|
// The rig each run binds to (M3); its active version is resolved per fire.
|
|
5362
5515
|
rigId: z.string().uuid().nullable().optional(),
|
|
5363
5516
|
metadata: z.record(z.string(), z.unknown()).default({}),
|
|
5517
|
+
}).superRefine((value, context) => {
|
|
5518
|
+
if (value.runMode === "existing_session" && !value.targetSessionId) {
|
|
5519
|
+
context.addIssue({
|
|
5520
|
+
code: "custom",
|
|
5521
|
+
path: ["targetSessionId"],
|
|
5522
|
+
message: "targetSessionId is required when runMode=existing_session",
|
|
5523
|
+
});
|
|
5524
|
+
}
|
|
5525
|
+
if (value.runMode !== "existing_session" && value.targetSessionId) {
|
|
5526
|
+
context.addIssue({
|
|
5527
|
+
code: "custom",
|
|
5528
|
+
path: ["targetSessionId"],
|
|
5529
|
+
message: "targetSessionId requires runMode=existing_session",
|
|
5530
|
+
});
|
|
5531
|
+
}
|
|
5532
|
+
if (value.runMode === "existing_session" && value.agentConfig.goal) {
|
|
5533
|
+
context.addIssue({
|
|
5534
|
+
code: "custom",
|
|
5535
|
+
path: ["agentConfig", "goal"],
|
|
5536
|
+
message: "agentConfig.goal cannot be used with an existing-session target",
|
|
5537
|
+
});
|
|
5538
|
+
}
|
|
5364
5539
|
});
|
|
5365
5540
|
export type CreateScheduledTaskRequest = z.infer<typeof CreateScheduledTaskRequest>;
|
|
5366
5541
|
|
|
@@ -5369,6 +5544,7 @@ export const UpdateScheduledTaskRequest = withVariableSetIdAlias({
|
|
|
5369
5544
|
schedule: ScheduledTaskScheduleSpec.optional(),
|
|
5370
5545
|
runMode: ScheduledTaskRunMode.optional(),
|
|
5371
5546
|
overlapPolicy: ScheduledTaskOverlapPolicy.optional(),
|
|
5547
|
+
targetSessionId: z.string().uuid().nullable().optional(),
|
|
5372
5548
|
agentConfig: ScheduledTaskAgentConfig.optional(),
|
|
5373
5549
|
status: ScheduledTaskStatus.optional(),
|
|
5374
5550
|
variableSetId: z.string().uuid().nullable().optional(),
|
|
@@ -5377,6 +5553,31 @@ export const UpdateScheduledTaskRequest = withVariableSetIdAlias({
|
|
|
5377
5553
|
// resolved per fire, so an update takes effect on the next dispatch.
|
|
5378
5554
|
rigId: z.string().uuid().nullable().optional(),
|
|
5379
5555
|
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
5556
|
+
}).superRefine((value, context) => {
|
|
5557
|
+
if (value.targetSessionId && value.runMode && value.runMode !== "existing_session") {
|
|
5558
|
+
context.addIssue({
|
|
5559
|
+
code: "custom",
|
|
5560
|
+
path: ["targetSessionId"],
|
|
5561
|
+
message: "targetSessionId requires runMode=existing_session",
|
|
5562
|
+
});
|
|
5563
|
+
}
|
|
5564
|
+
if (value.runMode === "existing_session" && value.targetSessionId === null) {
|
|
5565
|
+
context.addIssue({
|
|
5566
|
+
code: "custom",
|
|
5567
|
+
path: ["targetSessionId"],
|
|
5568
|
+
message: "targetSessionId cannot be null when runMode=existing_session",
|
|
5569
|
+
});
|
|
5570
|
+
}
|
|
5571
|
+
if (
|
|
5572
|
+
value.agentConfig?.goal &&
|
|
5573
|
+
(value.runMode === "existing_session" || Boolean(value.targetSessionId))
|
|
5574
|
+
) {
|
|
5575
|
+
context.addIssue({
|
|
5576
|
+
code: "custom",
|
|
5577
|
+
path: ["agentConfig", "goal"],
|
|
5578
|
+
message: "agentConfig.goal cannot be used with an existing-session target",
|
|
5579
|
+
});
|
|
5580
|
+
}
|
|
5380
5581
|
});
|
|
5381
5582
|
export type UpdateScheduledTaskRequest = z.infer<typeof UpdateScheduledTaskRequest>;
|
|
5382
5583
|
|
|
@@ -6863,8 +7064,8 @@ export const RecordingFailedPayload = z.object({
|
|
|
6863
7064
|
recordingId: z.string().uuid(),
|
|
6864
7065
|
turnId: z.string().uuid().nullable(),
|
|
6865
7066
|
reason: RecordingFailedReason,
|
|
6866
|
-
// ffmpeg
|
|
6867
|
-
//
|
|
7067
|
+
// Exact ffmpeg stderr/error detail. Event transport limits must reject or
|
|
7068
|
+
// paginate rather than rewriting this canonical diagnostic.
|
|
6868
7069
|
detail: z.string().nullable().optional(),
|
|
6869
7070
|
});
|
|
6870
7071
|
export type RecordingFailedPayload = z.infer<typeof RecordingFailedPayload>;
|
|
@@ -6992,6 +7193,18 @@ export const FsListResponse = z.object({
|
|
|
6992
7193
|
});
|
|
6993
7194
|
export type FsListResponse = z.infer<typeof FsListResponse>;
|
|
6994
7195
|
|
|
7196
|
+
/** Several independent directory listings served behind one Channel-A lease.
|
|
7197
|
+
* The response order exactly matches `requests`; callers can paint a root and
|
|
7198
|
+
* hydrate a bounded lazy-tree frontier without repeating provider attach work. */
|
|
7199
|
+
export const FsListBatchRequest = z.object({
|
|
7200
|
+
requests: z.array(FsListRequest).min(1).max(16),
|
|
7201
|
+
});
|
|
7202
|
+
export type FsListBatchRequest = z.infer<typeof FsListBatchRequest>;
|
|
7203
|
+
export const FsListBatchResponse = z.object({
|
|
7204
|
+
results: z.array(FsListResponse),
|
|
7205
|
+
});
|
|
7206
|
+
export type FsListBatchResponse = z.infer<typeof FsListBatchResponse>;
|
|
7207
|
+
|
|
6995
7208
|
export const FsEncoding = z.enum(["utf8", "base64"]);
|
|
6996
7209
|
export type FsEncoding = z.infer<typeof FsEncoding>;
|
|
6997
7210
|
export const FsReadRequest = z.object({
|
|
@@ -7160,6 +7373,27 @@ export const GitDiffResponse = z.object({
|
|
|
7160
7373
|
});
|
|
7161
7374
|
export type GitDiffResponse = z.infer<typeof GitDiffResponse>;
|
|
7162
7375
|
|
|
7376
|
+
/** One repository read unit: status metadata plus an optional comparison.
|
|
7377
|
+
* Multiple units execute behind one Channel-A lease and preserve input order. */
|
|
7378
|
+
export const GitReadBatchItemRequest = z.object({
|
|
7379
|
+
status: GitStatusRequest,
|
|
7380
|
+
diff: GitDiffRequest.optional(),
|
|
7381
|
+
});
|
|
7382
|
+
export type GitReadBatchItemRequest = z.infer<typeof GitReadBatchItemRequest>;
|
|
7383
|
+
export const GitReadBatchRequest = z.object({
|
|
7384
|
+
requests: z.array(GitReadBatchItemRequest).min(1).max(32),
|
|
7385
|
+
});
|
|
7386
|
+
export type GitReadBatchRequest = z.infer<typeof GitReadBatchRequest>;
|
|
7387
|
+
export const GitReadBatchItemResponse = z.object({
|
|
7388
|
+
status: GitStatusResponse,
|
|
7389
|
+
diff: GitDiffResponse.optional(),
|
|
7390
|
+
});
|
|
7391
|
+
export type GitReadBatchItemResponse = z.infer<typeof GitReadBatchItemResponse>;
|
|
7392
|
+
export const GitReadBatchResponse = z.object({
|
|
7393
|
+
results: z.array(GitReadBatchItemResponse),
|
|
7394
|
+
});
|
|
7395
|
+
export type GitReadBatchResponse = z.infer<typeof GitReadBatchResponse>;
|
|
7396
|
+
|
|
7163
7397
|
// ─── Workbench v2 turn-end workspace capture ────────────
|
|
7164
7398
|
// A capture is a point-in-time snapshot of the session workspace's CHANGES,
|
|
7165
7399
|
// probed live off the box at turn end (detectRepos → gitStatus/gitDiff → fsRead
|
|
@@ -7191,10 +7425,10 @@ export const WorkspaceCaptureFile = z.object({
|
|
|
7191
7425
|
});
|
|
7192
7426
|
export type WorkspaceCaptureFile = z.infer<typeof WorkspaceCaptureFile>;
|
|
7193
7427
|
|
|
7194
|
-
// One repo discovered in the workspace. `diff` is
|
|
7195
|
-
//
|
|
7196
|
-
//
|
|
7197
|
-
//
|
|
7428
|
+
// One repo discovered in the workspace. `diff` is the working/index surface vs
|
|
7429
|
+
// HEAD; `branchDiff`, when available, is the complete current branch vs the
|
|
7430
|
+
// remote default branch and therefore retains committed agent work. `status`
|
|
7431
|
+
// is the full porcelain file list. root "" = the workspace root repo.
|
|
7198
7432
|
export const WorkspaceCaptureRepo = z.object({
|
|
7199
7433
|
root: z.string(),
|
|
7200
7434
|
head: z.string().nullable(),
|
|
@@ -7204,6 +7438,7 @@ export const WorkspaceCaptureRepo = z.object({
|
|
|
7204
7438
|
behind: z.number().int().nonnegative().default(0),
|
|
7205
7439
|
status: z.array(GitFileStatus),
|
|
7206
7440
|
diff: z.array(GitFileDiff),
|
|
7441
|
+
branchDiff: z.array(GitFileDiff).optional(),
|
|
7207
7442
|
});
|
|
7208
7443
|
export type WorkspaceCaptureRepo = z.infer<typeof WorkspaceCaptureRepo>;
|
|
7209
7444
|
|
|
@@ -9267,9 +9502,26 @@ export type ListEnrollmentsResponse = z.infer<typeof ListEnrollmentsResponse>;
|
|
|
9267
9502
|
|
|
9268
9503
|
export const RevokeEnrollmentResponse = z.object({
|
|
9269
9504
|
revoked: z.boolean(),
|
|
9505
|
+
outcome: z.enum(["removed", "already_removed", "blocked"]),
|
|
9506
|
+
enrollmentId: z.string().uuid(),
|
|
9507
|
+
machineName: z.string().nullable(),
|
|
9508
|
+
lastSeenAt: z.string().datetime({ offset: true }).nullable(),
|
|
9509
|
+
revokedAt: z.string().datetime({ offset: true }).nullable(),
|
|
9510
|
+
code: z
|
|
9511
|
+
.enum(["active_route", "active_commands", "active_lease", "recovery_pending", "not_selfhosted"])
|
|
9512
|
+
.nullable(),
|
|
9513
|
+
message: z.string(),
|
|
9514
|
+
action: z.string(),
|
|
9270
9515
|
});
|
|
9271
9516
|
export type RevokeEnrollmentResponse = z.infer<typeof RevokeEnrollmentResponse>;
|
|
9272
9517
|
|
|
9518
|
+
/** POST /v1/workspaces/:workspaceId/enrollments/:id/revoke body. */
|
|
9519
|
+
export const RemoveEnrollmentRequest = z.object({
|
|
9520
|
+
expectedUpdatedAt: z.string().datetime({ offset: true }).optional(),
|
|
9521
|
+
idempotencyKey: z.string().trim().min(1).max(200).optional(),
|
|
9522
|
+
});
|
|
9523
|
+
export type RemoveEnrollmentRequest = z.infer<typeof RemoveEnrollmentRequest>;
|
|
9524
|
+
|
|
9273
9525
|
// =============================================================================
|
|
9274
9526
|
// Enrollment UX (self-hosted enrollment UX, design 11): the click-Grant approve
|
|
9275
9527
|
// page lookup/deny + the headless enroll-token mint/exchange. These sit beside the
|
|
@@ -9615,9 +9867,10 @@ export const TurnExecutionReasoningSourceV1 =
|
|
|
9615
9867
|
);
|
|
9616
9868
|
export type TurnExecutionReasoningSourceV1 = z.infer<typeof TurnExecutionReasoningSourceV1>;
|
|
9617
9869
|
|
|
9618
|
-
export const TurnExecutionLatencyModeSourceV1 =
|
|
9619
|
-
|
|
9620
|
-
)
|
|
9870
|
+
export const TurnExecutionLatencyModeSourceV1 =
|
|
9871
|
+
/* @__PURE__ */ defineModelContractSchema(() =>
|
|
9872
|
+
z.enum(["explicit", "session", "deployment", "continuation"]),
|
|
9873
|
+
);
|
|
9621
9874
|
export type TurnExecutionLatencyModeSourceV1 = z.infer<typeof TurnExecutionLatencyModeSourceV1>;
|
|
9622
9875
|
|
|
9623
9876
|
/**
|
|
@@ -10082,7 +10335,6 @@ export function evaluateWorkspaceModelPolicy(
|
|
|
10082
10335
|
}
|
|
10083
10336
|
|
|
10084
10337
|
export * from "./codex-fleet-policy";
|
|
10085
|
-
export * from "./secret-redaction";
|
|
10086
10338
|
export * from "./workspace-instruction-policies";
|
|
10087
10339
|
export * from "./workspace-state";
|
|
10088
10340
|
export * from "./preference-registry";
|