@zhanguym/chatroom 1.0.0 → 1.1.0-beta.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/dist/app/application.d.ts +0 -1
  2. package/dist/app/application.js +8 -7
  3. package/dist/app/event-bus.d.ts +13 -10
  4. package/dist/app/git-access.d.ts +50 -0
  5. package/dist/app/git-access.js +2 -0
  6. package/dist/app/service-registry.d.ts +11 -0
  7. package/dist/app/service-registry.js +17 -0
  8. package/dist/app/workspace-access.d.ts +24 -0
  9. package/dist/app/workspace-access.js +2 -0
  10. package/dist/auth/ingress-policy.d.ts +2 -0
  11. package/dist/auth/ingress-policy.js +14 -2
  12. package/dist/auth/passkey-service.js +1 -1
  13. package/dist/cli/run-cli.js +1 -1
  14. package/dist/core/fs/safe-directory.d.ts +9 -0
  15. package/dist/core/fs/safe-directory.js +129 -0
  16. package/dist/core/operations/repository.d.ts +2 -0
  17. package/dist/core/runtime/line-process.d.ts +19 -0
  18. package/dist/core/runtime/line-process.js +51 -0
  19. package/dist/infrastructure/database/operation-repository.js +8 -2
  20. package/dist/infrastructure/database/schema.d.ts +1 -1
  21. package/dist/infrastructure/database/schema.js +62 -0
  22. package/dist/infrastructure/http/http-server.js +1 -1
  23. package/dist/native/linux/chatroom-computer-helper +0 -0
  24. package/dist/native/macos/ChatRoomComputerHelper.app/Contents/MacOS/chatroom-computer-helper +0 -0
  25. package/dist/native/windows/chatroom-computer-helper.exe +0 -0
  26. package/dist/operations/operation-log.js +16 -4
  27. package/dist/plugins/agent/async-queue.d.ts +10 -0
  28. package/dist/plugins/agent/async-queue.js +49 -0
  29. package/dist/plugins/agent/mcp.d.ts +3 -0
  30. package/dist/plugins/agent/mcp.js +502 -0
  31. package/dist/plugins/agent/plugin.d.ts +4 -0
  32. package/dist/plugins/agent/plugin.js +35 -0
  33. package/dist/plugins/agent/provider.d.ts +132 -0
  34. package/dist/plugins/agent/providers/codex/mapping.d.ts +56 -0
  35. package/dist/plugins/agent/providers/codex/mapping.js +427 -0
  36. package/dist/plugins/agent/providers/codex/provider.d.ts +84 -0
  37. package/dist/plugins/agent/providers/codex/provider.js +828 -0
  38. package/dist/plugins/agent/providers/codex/rpc.d.ts +40 -0
  39. package/dist/plugins/agent/providers/codex/rpc.js +227 -0
  40. package/dist/plugins/agent/providers/common.d.ts +11 -0
  41. package/dist/plugins/agent/providers/common.js +75 -0
  42. package/dist/plugins/agent/providers/index.d.ts +3 -0
  43. package/dist/plugins/agent/providers/index.js +4 -0
  44. package/dist/plugins/agent/repository.d.ts +21 -0
  45. package/dist/plugins/agent/repository.js +226 -0
  46. package/dist/plugins/agent/runtime-config.d.ts +5 -0
  47. package/dist/plugins/agent/runtime-config.js +60 -0
  48. package/dist/plugins/agent/runtime-files.d.ts +8 -0
  49. package/dist/plugins/agent/runtime-files.js +170 -0
  50. package/dist/plugins/agent/runtime-state.d.ts +17 -0
  51. package/dist/plugins/agent/runtime-state.js +133 -0
  52. package/dist/plugins/agent/runtime.d.ts +60 -0
  53. package/dist/plugins/agent/runtime.js +928 -0
  54. package/dist/plugins/agent/store.d.ts +17 -0
  55. package/dist/plugins/agent/store.js +1 -0
  56. package/dist/plugins/agent/types.d.ts +320 -0
  57. package/dist/plugins/agent/types.js +13 -0
  58. package/dist/plugins/cloud/plugin.d.ts +1 -1
  59. package/dist/plugins/cloud/plugin.js +3 -3
  60. package/dist/plugins/cloud/tunnel-client.js +6 -7
  61. package/dist/plugins/computer/computer-schemas.d.ts +7 -7
  62. package/dist/plugins/computer/computer-service.d.ts +3 -0
  63. package/dist/plugins/computer/computer-service.js +33 -1
  64. package/dist/plugins/computer/plugin.d.ts +1 -1
  65. package/dist/plugins/computer/plugin.js +1 -1
  66. package/dist/plugins/git/git-service.d.ts +3 -2
  67. package/dist/plugins/git/git-service.js +37 -1
  68. package/dist/plugins/git/plugin.d.ts +0 -2
  69. package/dist/plugins/git/plugin.js +3 -3
  70. package/dist/plugins/process/plugin.d.ts +1 -1
  71. package/dist/plugins/process/plugin.js +3 -3
  72. package/dist/plugins/process/process-supervisor.d.ts +1 -0
  73. package/dist/plugins/process/process-supervisor.js +15 -4
  74. package/dist/plugins/types.d.ts +1 -11
  75. package/dist/plugins/types.js +1 -17
  76. package/dist/plugins/web/api-types.d.ts +20 -5
  77. package/dist/plugins/web/http/agent-api-router.d.ts +3 -0
  78. package/dist/plugins/web/http/agent-api-router.js +254 -0
  79. package/dist/plugins/web/http/api-router.js +9 -0
  80. package/dist/plugins/web/http/computer-api-router.js +21 -6
  81. package/dist/plugins/web/http/process-api-router.js +3 -0
  82. package/dist/plugins/web/http/workspace-api-router.js +79 -6
  83. package/dist/plugins/web/plugin.d.ts +1 -1
  84. package/dist/plugins/web/plugin.js +5 -4
  85. package/dist/plugins/web/runtime.d.ts +6 -3
  86. package/dist/plugins/web/runtime.js +6 -1
  87. package/dist/plugins/workspace/mcp.js +16 -0
  88. package/dist/plugins/workspace/metadata.d.ts +1 -1
  89. package/dist/plugins/workspace/plugin.d.ts +1 -1
  90. package/dist/plugins/workspace/plugin.js +5 -2
  91. package/dist/plugins/workspace/types.d.ts +1 -18
  92. package/dist/plugins/workspace/workspace-fs.d.ts +9 -3
  93. package/dist/plugins/workspace/workspace-fs.js +78 -125
  94. package/dist/plugins/workspace/workspace-root-policy.d.ts +9 -0
  95. package/dist/plugins/workspace/workspace-root-policy.js +56 -0
  96. package/dist/plugins/workspace/workspace-service.d.ts +11 -6
  97. package/dist/plugins/workspace/workspace-service.js +39 -49
  98. package/dist/web/assets/AgentView-DKuspiki.js +4 -0
  99. package/dist/web/assets/AgentView-DYJeMJLX.css +1 -0
  100. package/dist/web/assets/{CloudView-CHjVbp-5.css → CloudView-DVVvwuWW.css} +1 -1
  101. package/dist/web/assets/CloudView-PbREbJgz.js +1 -0
  102. package/dist/web/assets/CodeViewer.vue_vue_type_script_setup_true_lang-CiFNEpWo.js +3 -0
  103. package/dist/web/assets/ComputerView-BM0u3wSF.css +1 -0
  104. package/dist/web/assets/ComputerView-BRb2sE0Z.js +1 -0
  105. package/dist/web/assets/McpToolsView-B8NSFdf4.js +1 -0
  106. package/dist/web/assets/McpToolsView-C22ZbSuV.css +1 -0
  107. package/dist/web/assets/OperationsView-BjTY2lIh.css +1 -0
  108. package/dist/web/assets/OperationsView-Cavi-6SZ.js +4 -0
  109. package/dist/web/assets/ProcessesView-Ce6iVwjA.css +1 -0
  110. package/dist/web/assets/ProcessesView-UO48Nh2q.js +4 -0
  111. package/dist/web/assets/StateChip.vue_vue_type_script_setup_true_lang-Bvc9wRyA.js +1 -0
  112. package/dist/web/assets/SystemLogsView-BXmOrmu5.js +1 -0
  113. package/dist/web/assets/SystemLogsView-CofP4Jvi.css +1 -0
  114. package/dist/web/assets/VSelect-BPRXx8KM.js +1 -0
  115. package/dist/web/assets/VSpacer-Cl-QiwaM.js +1 -0
  116. package/dist/web/assets/VSwitch-C0XNj1lR.js +1 -0
  117. package/dist/web/assets/{VTabs-qBcuuXh3.js → VTabs-CHj39Ket.js} +1 -1
  118. package/dist/web/assets/VTextarea-BIcUWOU6.js +16 -0
  119. package/dist/web/assets/VTextarea-DG1zE1as.css +1 -0
  120. package/dist/web/assets/WorkspacesView-DPCt6kYy.css +1 -0
  121. package/dist/web/assets/WorkspacesView-rY6RXeiR.js +2 -0
  122. package/dist/web/assets/entity-refresh-queue-wQii8Dl5.js +1 -0
  123. package/dist/web/assets/{index-CkjqXRSj.css → index-BPpl3-sP.css} +1 -1
  124. package/dist/web/assets/index-Dt-pWiW1.js +19 -0
  125. package/dist/web/assets/{syntax-highlight-B5ArnyrC.js → syntax-highlight-C_fuMcwC.js} +1 -1
  126. package/dist/web/assets/useMasterDetailFocus-D0j-KcXv.js +1 -0
  127. package/dist/web/assets/useOperationLabels-DR8r6Vrl.js +1 -0
  128. package/dist/web/index.html +2 -2
  129. package/package.json +4 -2
  130. package/dist/plugins/git/types.d.ts +0 -32
  131. package/dist/web/assets/CloudView-CvX0dkgu.js +0 -1
  132. package/dist/web/assets/CodeViewer.vue_vue_type_script_setup_true_lang-B5TxGkUW.js +0 -3
  133. package/dist/web/assets/ComputerView-91Z9Cefw.css +0 -1
  134. package/dist/web/assets/ComputerView-OOyEqWml.js +0 -1
  135. package/dist/web/assets/McpToolsView-BTnolyS6.css +0 -1
  136. package/dist/web/assets/McpToolsView-DjXWTKrZ.js +0 -1
  137. package/dist/web/assets/OperationsView-DqTY51Cr.js +0 -4
  138. package/dist/web/assets/ProcessesView-C13BykIa.js +0 -4
  139. package/dist/web/assets/StateChip.vue_vue_type_script_setup_true_lang-DyOhJmR6.js +0 -1
  140. package/dist/web/assets/SystemLogsView-Ci0u4BTb.js +0 -1
  141. package/dist/web/assets/VSelect-DrRpKyYI.js +0 -1
  142. package/dist/web/assets/VSpacer-C3wAY3F0.js +0 -1
  143. package/dist/web/assets/VSwitch-CxusR4iO.js +0 -1
  144. package/dist/web/assets/WorkspacesView-BzQ0aH74.css +0 -1
  145. package/dist/web/assets/WorkspacesView-CijIvfsp.js +0 -2
  146. package/dist/web/assets/index-BegKQ3Yd.js +0 -19
  147. package/dist/web/assets/useOperationLabels-BDjzGDkT.js +0 -1
  148. /package/dist/{plugins/process → core/runtime}/head-tail-buffer.d.ts +0 -0
  149. /package/dist/{plugins/process → core/runtime}/head-tail-buffer.js +0 -0
  150. /package/dist/plugins/{git/types.js → agent/provider.js} +0 -0
@@ -0,0 +1,132 @@
1
+ import type { AgentAttachment, AgentError, AgentInteractionOption, AgentPlanStep, AgentSessionConfig, AgentTokenUsage, AgentFileChange, AgentInputQuestion, AgentInteractionResponse, AgentModel, AgentProviderFeatures, AgentProviderId, AgentProviderNativeSetting, AgentProviderProbe, AgentProviderDetails, AgentReviewTarget } from "./types.js";
2
+ export interface AgentProviderContext extends AgentSessionConfig {
3
+ workspaceRoot: string;
4
+ workspacePrompt: string | null;
5
+ continuityContext: string | null;
6
+ continuityDelta: string | null;
7
+ }
8
+ export interface AgentProvider {
9
+ readonly id: AgentProviderId;
10
+ readonly displayName: string;
11
+ readonly icon: string | null;
12
+ readonly features: AgentProviderFeatures;
13
+ readonly nativeSettings: readonly AgentProviderNativeSetting[];
14
+ probe(): Promise<AgentProviderProbe>;
15
+ details(): Promise<AgentProviderDetails>;
16
+ listModels(): Promise<AgentModel[]>;
17
+ createSession(context: AgentProviderContext): Promise<ProviderSession>;
18
+ resumeSession(context: AgentProviderContext, providerSessionId: string): Promise<ProviderSession>;
19
+ close(): Promise<void>;
20
+ }
21
+ export interface ProviderSession {
22
+ readonly providerSessionId: string;
23
+ runTurn(input: ProviderTurnInput): AsyncIterable<ProviderEvent>;
24
+ runReview?(target: AgentReviewTarget): AsyncIterable<ProviderEvent>;
25
+ steer?(input: Pick<ProviderTurnInput, "text" | "attachments">): Promise<void>;
26
+ interrupt(): Promise<void>;
27
+ configure(config: AgentSessionConfig): Promise<void>;
28
+ resolveInteraction(interactionId: string, response: AgentInteractionResponse): Promise<void>;
29
+ close(): Promise<void>;
30
+ }
31
+ export interface ProviderTurnInput {
32
+ outputSchema: unknown | null;
33
+ text: string;
34
+ attachments: AgentAttachment[];
35
+ }
36
+ export type ProviderItem = {
37
+ type: "assistant_message";
38
+ text: string;
39
+ phase: "commentary" | "final_answer" | null;
40
+ } | {
41
+ type: "command";
42
+ command: string;
43
+ cwd: string | null;
44
+ output: string;
45
+ exitCode: number | null;
46
+ } | {
47
+ type: "tool";
48
+ progress: string | null;
49
+ name: string;
50
+ server: string | null;
51
+ input: unknown;
52
+ output: unknown;
53
+ error: string | null;
54
+ } | {
55
+ type: "turn_diff";
56
+ diff: string;
57
+ } | {
58
+ type: "file_change";
59
+ changes: AgentFileChange[];
60
+ } | {
61
+ type: "plan";
62
+ text: string;
63
+ steps: AgentPlanStep[];
64
+ } | {
65
+ type: "reasoning_summary";
66
+ text: string;
67
+ } | {
68
+ type: "artifact";
69
+ artifact: {
70
+ kind: "image" | "file";
71
+ name: string;
72
+ path: string;
73
+ mimeType: string | null;
74
+ };
75
+ } | {
76
+ type: "context_compaction";
77
+ trigger: "auto" | "manual" | null;
78
+ error: string | null;
79
+ } | {
80
+ type: "notice";
81
+ level: "info" | "warning" | "error";
82
+ text: string;
83
+ };
84
+ export interface ProviderInteraction {
85
+ id: string;
86
+ kind: "approval" | "input";
87
+ title: string;
88
+ description: string | null;
89
+ questions: AgentInputQuestion[];
90
+ approvalOptions: AgentInteractionOption[];
91
+ }
92
+ export type ProviderEvent = {
93
+ type: "interaction.resolved";
94
+ providerRequestId: string;
95
+ } | {
96
+ type: "token.usage";
97
+ usage: AgentTokenUsage;
98
+ } | {
99
+ type: "model.rerouted";
100
+ fromModel: string;
101
+ toModel: string;
102
+ reason: string;
103
+ } | {
104
+ type: "item.updated";
105
+ providerItemId: string;
106
+ item: ProviderItem;
107
+ } | {
108
+ type: "turn.started";
109
+ providerTurnId: string | null;
110
+ } | {
111
+ type: "item.started";
112
+ providerItemId: string;
113
+ item: ProviderItem;
114
+ } | {
115
+ type: "item.delta";
116
+ providerItemId: string;
117
+ field: "text" | "output";
118
+ delta: string;
119
+ } | {
120
+ type: "item.completed";
121
+ providerItemId: string;
122
+ item: ProviderItem;
123
+ failed?: boolean;
124
+ } | {
125
+ type: "interaction.requested";
126
+ providerItemId: string;
127
+ interaction: ProviderInteraction;
128
+ } | {
129
+ type: "turn.completed";
130
+ status: "completed" | "interrupted" | "failed";
131
+ error: AgentError | null;
132
+ };
@@ -0,0 +1,56 @@
1
+ import type { AgentProviderContext, ProviderEvent, ProviderItem, ProviderSession, ProviderTurnInput } from "#plugins/agent/provider";
2
+ import type { AgentError, AgentInputQuestion, AgentInteractionOption, AgentProviderDetails, AgentReviewTarget } from "#plugins/agent/types";
3
+ import { CodexRpcClient } from "./rpc.js";
4
+ type SessionConfig = Parameters<ProviderSession["configure"]>[0];
5
+ type ApprovalChoice = AgentInteractionOption & {
6
+ result: unknown;
7
+ };
8
+ export declare function codexItem(item: Record<string, unknown>, workspaceRoot: string): ProviderItem | null;
9
+ export declare function codexFileChanges(value: unknown): {
10
+ path: string;
11
+ kind: string;
12
+ movePath: string | null;
13
+ diff: string;
14
+ }[];
15
+ export declare function codexItemFailed(item: Record<string, unknown>): boolean;
16
+ export declare function grantedPermissions(requested: Record<string, unknown>): Record<string, unknown>;
17
+ export declare function codexQuestions(value: unknown): AgentInputQuestion[];
18
+ export declare function stringOrNull(value: unknown): string | null;
19
+ export declare function codexVersion(userAgent: string): string | null;
20
+ export declare function injectWorkspacePrompt(client: CodexRpcClient, threadId: string, prompt: string | null): Promise<void>;
21
+ export declare function injectContinuity(client: CodexRpcClient, threadId: string, context: string | null): Promise<void>;
22
+ export declare function sessionConfig(context: AgentProviderContext): SessionConfig;
23
+ export declare function standardApprovalChoices(): ApprovalChoice[];
24
+ export declare function turnError(value: unknown): AgentError | null;
25
+ export declare function codexAccountUsage(value: unknown): AgentProviderDetails["accountUsage"];
26
+ export declare function tokenUsage(value: unknown): Extract<ProviderEvent, {
27
+ type: "token.usage";
28
+ }>["usage"] | null;
29
+ export declare function codexInput(input: Pick<ProviderTurnInput, "text" | "attachments">, workspaceRoot: string): unknown[];
30
+ export declare function reviewTarget(target: AgentReviewTarget): {
31
+ type: "uncommittedChanges";
32
+ branch?: never;
33
+ sha?: never;
34
+ title?: never;
35
+ instructions?: never;
36
+ } | {
37
+ type: "baseBranch";
38
+ branch: string;
39
+ sha?: never;
40
+ title?: never;
41
+ instructions?: never;
42
+ } | {
43
+ type: "commit";
44
+ sha: string;
45
+ title: string | null;
46
+ branch?: never;
47
+ instructions?: never;
48
+ } | {
49
+ type: "custom";
50
+ instructions: string;
51
+ branch?: never;
52
+ sha?: never;
53
+ title?: never;
54
+ };
55
+ export declare function codexWarning(method: string, params: Record<string, unknown>): string | null;
56
+ export {};
@@ -0,0 +1,427 @@
1
+ import { existsSync, statSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { array, questionOptions, record, stringifyOptional, continuityInstructions, workspaceInstructions, } from "../common.js";
4
+ export function codexItem(item, workspaceRoot) {
5
+ const type = item.type;
6
+ if (type === "agentMessage")
7
+ return {
8
+ type: "assistant_message",
9
+ phase: item.phase === "commentary" || item.phase === "final_answer"
10
+ ? item.phase
11
+ : null,
12
+ text: typeof item.text === "string" ? item.text : "",
13
+ };
14
+ if (type === "contextCompaction")
15
+ return { type: "context_compaction", trigger: null, error: null };
16
+ if (type === "reasoning")
17
+ return {
18
+ type: "reasoning_summary",
19
+ text: array(item.summary)
20
+ .filter((part) => typeof part === "string")
21
+ .join("\n"),
22
+ };
23
+ if (type === "plan")
24
+ return {
25
+ type: "plan",
26
+ text: typeof item.text === "string" ? item.text : "",
27
+ steps: [],
28
+ };
29
+ if (type === "commandExecution")
30
+ return {
31
+ type: "command",
32
+ command: typeof item.command === "string" ? item.command : "",
33
+ cwd: stringOrNull(item.cwd),
34
+ output: stringOrNull(item.aggregatedOutput) ?? "",
35
+ exitCode: typeof item.exitCode === "number" ? item.exitCode : null,
36
+ };
37
+ if (type === "fileChange")
38
+ return {
39
+ type: "file_change",
40
+ changes: codexFileChanges(item.changes),
41
+ };
42
+ if (type === "mcpToolCall")
43
+ return {
44
+ type: "tool",
45
+ name: stringOrNull(item.tool) ?? "MCP tool",
46
+ server: stringOrNull(item.server),
47
+ input: item.arguments ?? null,
48
+ output: item.result ?? null,
49
+ error: stringOrNull(record(item.error)?.message),
50
+ progress: null,
51
+ };
52
+ if (type === "functionCallOutput")
53
+ return {
54
+ type: "tool",
55
+ name: stringOrNull(item.name) ?? "Tool",
56
+ server: stringOrNull(item.namespace),
57
+ input: null,
58
+ output: item.output ?? null,
59
+ error: null,
60
+ progress: null,
61
+ };
62
+ if (type === "dynamicToolCall")
63
+ return {
64
+ type: "tool",
65
+ progress: null,
66
+ name: typeof item.tool === "string" ? item.tool : "Tool",
67
+ server: stringOrNull(item.namespace),
68
+ input: item.arguments ?? null,
69
+ output: item.contentItems ?? null,
70
+ error: item.success === false ? "Tool call failed" : null,
71
+ };
72
+ if (type === "webSearch")
73
+ return {
74
+ type: "tool",
75
+ progress: null,
76
+ name: "web_search",
77
+ server: null,
78
+ input: null,
79
+ output: item,
80
+ error: null,
81
+ };
82
+ if (type === "imageView" && typeof item.path === "string")
83
+ return artifactFromPath(item.path, workspaceRoot);
84
+ if (type === "imageGeneration") {
85
+ if (typeof item.savedPath === "string")
86
+ return generatedArtifactFromPath(item.savedPath, workspaceRoot);
87
+ return {
88
+ type: "notice",
89
+ level: item.failure ? "error" : "info",
90
+ text: item.failure
91
+ ? (stringifyOptional(item.failure) ?? "Image generation failed")
92
+ : "Generating image…",
93
+ };
94
+ }
95
+ return null;
96
+ }
97
+ function generatedArtifactFromPath(value, workspaceRoot) {
98
+ const existing = artifactFromPath(value, workspaceRoot);
99
+ if (existing.type === "artifact")
100
+ return existing;
101
+ const source = path.resolve(value);
102
+ const mime = imageMime(source);
103
+ if (!mime || !existsSync(source) || !statSync(source).isFile())
104
+ return existing;
105
+ return {
106
+ type: "artifact",
107
+ artifact: {
108
+ kind: "image",
109
+ name: path.basename(source),
110
+ path: source,
111
+ mimeType: mime,
112
+ },
113
+ };
114
+ }
115
+ function artifactFromPath(value, workspaceRoot) {
116
+ const absolute = path.isAbsolute(value)
117
+ ? path.resolve(value)
118
+ : path.resolve(workspaceRoot, value);
119
+ const relative = path.relative(workspaceRoot, absolute);
120
+ if (relative.startsWith("..") || path.isAbsolute(relative)) {
121
+ return {
122
+ type: "notice",
123
+ level: "warning",
124
+ text: "Agent produced an artifact outside the workspace: " + value,
125
+ };
126
+ }
127
+ const safePath = relative.split(path.sep).join("/");
128
+ return {
129
+ type: "artifact",
130
+ artifact: {
131
+ kind: imageMime(safePath) ? "image" : "file",
132
+ name: path.basename(safePath),
133
+ path: safePath,
134
+ mimeType: imageMime(safePath),
135
+ },
136
+ };
137
+ }
138
+ export function codexFileChanges(value) {
139
+ return array(value)
140
+ .map(record)
141
+ .filter((change) => Boolean(change))
142
+ .map((change) => {
143
+ const kind = record(change.kind);
144
+ const type = kind?.type === "add" ||
145
+ kind?.type === "delete" ||
146
+ kind?.type === "update"
147
+ ? kind.type
148
+ : "update";
149
+ return {
150
+ path: typeof change.path === "string" ? change.path : "",
151
+ kind: type,
152
+ movePath: type === "update" && typeof kind?.move_path === "string"
153
+ ? kind.move_path
154
+ : null,
155
+ diff: typeof change.diff === "string" ? change.diff : "",
156
+ };
157
+ });
158
+ }
159
+ export function codexItemFailed(item) {
160
+ if (item.type === "commandExecution")
161
+ return typeof item.exitCode === "number" && item.exitCode !== 0;
162
+ if (item.type === "dynamicToolCall")
163
+ return item.success === false;
164
+ if (item.type === "mcpToolCall")
165
+ return item.status === "failed" || Boolean(item.error);
166
+ if (item.type === "imageGeneration")
167
+ return Boolean(item.failure);
168
+ return false;
169
+ }
170
+ export function grantedPermissions(requested) {
171
+ const output = {};
172
+ const network = record(requested.network);
173
+ const fileSystem = record(requested.fileSystem);
174
+ if (network)
175
+ output.network = network;
176
+ if (fileSystem)
177
+ output.fileSystem = fileSystem;
178
+ return output;
179
+ }
180
+ export function codexQuestions(value) {
181
+ return array(value)
182
+ .map(record)
183
+ .filter((question) => Boolean(question))
184
+ .map((question, index) => {
185
+ const id = typeof question.id === "string" ? question.id : "question_" + index;
186
+ const options = questionOptions(question.options);
187
+ return {
188
+ id,
189
+ label: typeof question.header === "string" ? question.header : id,
190
+ question: typeof question.question === "string"
191
+ ? question.question
192
+ : "Provide input",
193
+ options,
194
+ multiSelect: Boolean(question.isMultiSelect ?? question.multiSelect),
195
+ allowFreeText: Boolean(question.isOther) || options.length === 0,
196
+ secret: Boolean(question.isSecret),
197
+ };
198
+ });
199
+ }
200
+ function resolveAttachmentPath(root, attachmentPath) {
201
+ const absolute = path.resolve(root, attachmentPath);
202
+ const relative = path.relative(root, absolute);
203
+ if (relative.startsWith("..") || path.isAbsolute(relative))
204
+ throw new Error("Attachment is outside the workspace");
205
+ return absolute;
206
+ }
207
+ function imageMime(filePath) {
208
+ switch (path.extname(filePath).toLowerCase()) {
209
+ case ".png":
210
+ return "image/png";
211
+ case ".jpg":
212
+ case ".jpeg":
213
+ return "image/jpeg";
214
+ case ".gif":
215
+ return "image/gif";
216
+ case ".webp":
217
+ return "image/webp";
218
+ case ".avif":
219
+ return "image/avif";
220
+ default:
221
+ return null;
222
+ }
223
+ }
224
+ export function stringOrNull(value) {
225
+ return typeof value === "string" ? value : null;
226
+ }
227
+ export function codexVersion(userAgent) {
228
+ const match = userAgent.match(/\b(\d+\.\d+\.\d+)\b/);
229
+ return match?.[1] ?? null;
230
+ }
231
+ export async function injectWorkspacePrompt(client, threadId, prompt) {
232
+ if (!prompt)
233
+ return;
234
+ await client.request("thread/inject_items", {
235
+ threadId,
236
+ items: [
237
+ {
238
+ type: "message",
239
+ role: "developer",
240
+ content: [
241
+ {
242
+ type: "input_text",
243
+ text: workspaceInstructions(prompt),
244
+ },
245
+ ],
246
+ },
247
+ ],
248
+ });
249
+ }
250
+ export async function injectContinuity(client, threadId, context) {
251
+ if (!context)
252
+ return;
253
+ await client.request("thread/inject_items", {
254
+ threadId,
255
+ items: [
256
+ {
257
+ type: "message",
258
+ role: "developer",
259
+ content: [
260
+ {
261
+ type: "input_text",
262
+ text: continuityInstructions(context),
263
+ },
264
+ ],
265
+ },
266
+ ],
267
+ });
268
+ }
269
+ export function sessionConfig(context) {
270
+ return {
271
+ model: context.model,
272
+ reasoningEffort: context.reasoningEffort,
273
+ reasoningSummary: context.reasoningSummary,
274
+ serviceTier: context.serviceTier,
275
+ approvalPolicy: context.approvalPolicy,
276
+ approvalsReviewer: context.approvalsReviewer,
277
+ permissionMode: context.permissionMode,
278
+ };
279
+ }
280
+ export function standardApprovalChoices() {
281
+ return [
282
+ { id: "accept", label: "Allow", description: null },
283
+ {
284
+ id: "acceptForSession",
285
+ label: "Allow for this session",
286
+ description: null,
287
+ },
288
+ { id: "decline", label: "Deny", description: null },
289
+ { id: "cancel", label: "Cancel turn", description: null },
290
+ ].map((choice) => ({ ...choice, result: { decision: choice.id } }));
291
+ }
292
+ export function turnError(value) {
293
+ const error = record(value);
294
+ if (!error || typeof error.message !== "string")
295
+ return null;
296
+ const errorInfo = error.codexErrorInfo ?? null;
297
+ const misalignment = error.misalignment ?? null;
298
+ return {
299
+ message: error.message,
300
+ details: stringOrNull(error.additionalDetails),
301
+ providerData: errorInfo !== null || misalignment !== null
302
+ ? { errorInfo, misalignment }
303
+ : null,
304
+ };
305
+ }
306
+ export function codexAccountUsage(value) {
307
+ const response = record(value);
308
+ const limits = record(response?.rateLimits);
309
+ if (!limits)
310
+ return null;
311
+ const windows = [];
312
+ const addWindow = (id, raw) => {
313
+ const window = record(raw);
314
+ if (!window)
315
+ return;
316
+ const duration = typeof window.windowDurationMins === "number"
317
+ ? window.windowDurationMins
318
+ : null;
319
+ const resetSeconds = typeof window.resetsAt === "number" ? window.resetsAt : null;
320
+ windows.push({
321
+ id,
322
+ label: duration === 300 || duration === 10080 || duration === null
323
+ ? null
324
+ : formatCodexWindow(duration),
325
+ utilization: typeof window.usedPercent === "number" ? window.usedPercent : null,
326
+ resetsAt: resetSeconds === null
327
+ ? null
328
+ : new Date(resetSeconds * 1000).toISOString(),
329
+ });
330
+ };
331
+ addWindow("five_hour", limits.primary);
332
+ addWindow("seven_day", limits.secondary);
333
+ return {
334
+ subscriptionType: typeof limits.planType === "string" ? limits.planType : null,
335
+ windows,
336
+ extraUsage: null,
337
+ updatedAt: new Date().toISOString(),
338
+ };
339
+ }
340
+ function formatCodexWindow(minutes) {
341
+ if (minutes % 1440 === 0)
342
+ return minutes / 1440 + " days";
343
+ if (minutes % 60 === 0)
344
+ return minutes / 60 + " hours";
345
+ return minutes + " minutes";
346
+ }
347
+ export function tokenUsage(value) {
348
+ const usage = record(value);
349
+ if (!usage)
350
+ return null;
351
+ const breakdown = (value) => {
352
+ const entry = record(value);
353
+ if (!entry)
354
+ return null;
355
+ const { totalTokens, inputTokens, cachedInputTokens, cacheWriteInputTokens, outputTokens, reasoningOutputTokens, } = entry;
356
+ if (typeof totalTokens !== "number" ||
357
+ typeof inputTokens !== "number" ||
358
+ typeof cachedInputTokens !== "number" ||
359
+ typeof cacheWriteInputTokens !== "number" ||
360
+ typeof outputTokens !== "number" ||
361
+ typeof reasoningOutputTokens !== "number")
362
+ return null;
363
+ return {
364
+ totalTokens,
365
+ inputTokens,
366
+ cachedInputTokens,
367
+ cacheWriteInputTokens,
368
+ outputTokens,
369
+ reasoningOutputTokens,
370
+ };
371
+ };
372
+ const total = breakdown(usage.total);
373
+ const last = breakdown(usage.last);
374
+ if (!total ||
375
+ !last ||
376
+ (usage.modelContextWindow !== null &&
377
+ typeof usage.modelContextWindow !== "number"))
378
+ return null;
379
+ return { total, last, modelContextWindow: usage.modelContextWindow };
380
+ }
381
+ export function codexInput(input, workspaceRoot) {
382
+ return [
383
+ { type: "text", text: input.text, text_elements: [] },
384
+ ...input.attachments.map((attachment) => {
385
+ const resolved = resolveAttachmentPath(workspaceRoot, attachment.path);
386
+ if (attachment.kind === "image" || attachment.kind === "audio")
387
+ return {
388
+ type: attachment.kind === "image" ? "localImage" : "localAudio",
389
+ path: resolved,
390
+ };
391
+ return {
392
+ type: attachment.kind === "skill" ? "skill" : "mention",
393
+ name: attachment.name,
394
+ path: resolved,
395
+ };
396
+ }),
397
+ ];
398
+ }
399
+ export function reviewTarget(target) {
400
+ switch (target.type) {
401
+ case "uncommittedChanges":
402
+ return { type: target.type };
403
+ case "baseBranch":
404
+ return { type: target.type, branch: target.branch };
405
+ case "commit":
406
+ return {
407
+ type: target.type,
408
+ sha: target.sha,
409
+ title: target.title ?? null,
410
+ };
411
+ case "custom":
412
+ return { type: target.type, instructions: target.instructions };
413
+ default:
414
+ throw new Error("Unsupported Codex review target");
415
+ }
416
+ }
417
+ export function codexWarning(method, params) {
418
+ if (method === "warning")
419
+ return stringOrNull(params.message);
420
+ if (method === "configWarning" || method === "deprecationNotice") {
421
+ const summary = stringOrNull(params.summary);
422
+ return summary === null
423
+ ? null
424
+ : [summary, stringOrNull(params.details)].filter(Boolean).join("\n");
425
+ }
426
+ return null;
427
+ }
@@ -0,0 +1,84 @@
1
+ import type { LogWriter } from "#core/logging/types";
2
+ import type { AgentProvider, AgentProviderContext, ProviderSession } from "#plugins/agent/provider";
3
+ import type { AgentModel, AgentProviderProbe, AgentProviderDetails } from "#plugins/agent/types";
4
+ export declare class CodexProvider implements AgentProvider {
5
+ private readonly logs;
6
+ readonly id = "codex";
7
+ readonly displayName = "Codex";
8
+ readonly icon = "openai";
9
+ readonly features: {
10
+ readonly nativeReview: true;
11
+ readonly steering: true;
12
+ };
13
+ readonly nativeSettings: readonly [{
14
+ readonly id: "approvalPolicy";
15
+ readonly defaultValue: "on-request";
16
+ readonly options: readonly [{
17
+ readonly id: "untrusted";
18
+ readonly description: "Ask for approval before running commands outside the trusted set.";
19
+ }, {
20
+ readonly id: "on-request";
21
+ readonly description: "Let Codex request approval when it decides escalation is needed.";
22
+ }, {
23
+ readonly id: "granular";
24
+ readonly description: "Control individual Codex approval categories.";
25
+ }, {
26
+ readonly id: "never";
27
+ readonly description: "Never ask for approval; disallowed operations fail instead.";
28
+ }];
29
+ readonly granularFields: readonly [{
30
+ readonly id: "sandbox_approval";
31
+ readonly description: "Sandbox approval requests.";
32
+ }, {
33
+ readonly id: "rules";
34
+ readonly description: "Rule-based approval requests.";
35
+ }, {
36
+ readonly id: "skill_approval";
37
+ readonly description: "Skill approval requests.";
38
+ }, {
39
+ readonly id: "request_permissions";
40
+ readonly description: "Additional permission requests.";
41
+ }, {
42
+ readonly id: "mcp_elicitations";
43
+ readonly description: "MCP elicitation requests.";
44
+ }];
45
+ }, {
46
+ readonly id: "permissionMode";
47
+ readonly defaultValue: "workspace-write";
48
+ readonly options: readonly [{
49
+ readonly id: "read-only";
50
+ readonly description: "Read-only sandbox; changes require approval.";
51
+ }, {
52
+ readonly id: "workspace-write";
53
+ readonly description: "Allow workspace writes within the sandbox.";
54
+ }, {
55
+ readonly id: "danger-full-access";
56
+ readonly description: "Disable the sandbox; commands can access files and the network outside the workspace.";
57
+ }];
58
+ readonly granularFields: readonly [];
59
+ }, {
60
+ readonly id: "approvalsReviewer";
61
+ readonly defaultValue: "user";
62
+ readonly options: readonly [{
63
+ readonly id: "user";
64
+ readonly description: "Route approval requests to the user.";
65
+ }, {
66
+ readonly id: "auto_review";
67
+ readonly description: "Use Codex auto review to approve or deny requests with a risk-based subagent.";
68
+ }, {
69
+ readonly id: "guardian_subagent";
70
+ readonly description: "Route approval requests to the Codex guardian subagent.";
71
+ }];
72
+ readonly granularFields: readonly [];
73
+ }];
74
+ private readonly client;
75
+ private readonly modelNames;
76
+ constructor(logs: LogWriter);
77
+ probe(): Promise<AgentProviderProbe>;
78
+ details(): Promise<AgentProviderDetails>;
79
+ listModels(): Promise<AgentModel[]>;
80
+ createSession(context: AgentProviderContext): Promise<ProviderSession>;
81
+ resumeSession(context: AgentProviderContext, providerSessionId: string): Promise<ProviderSession>;
82
+ private resolveModel;
83
+ close(): Promise<void>;
84
+ }