@lapis-notes/ai 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 (266) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/LICENSE.md +8 -0
  3. package/README.md +20 -0
  4. package/dist/ai-plugin.d.ts +88 -0
  5. package/dist/ai-plugin.js +742 -0
  6. package/dist/bootstrap/build.d.ts +15 -0
  7. package/dist/bootstrap/build.js +28 -0
  8. package/dist/bootstrap/folder-instructions.d.ts +4 -0
  9. package/dist/bootstrap/folder-instructions.js +49 -0
  10. package/dist/bootstrap/format.d.ts +2 -0
  11. package/dist/bootstrap/format.js +46 -0
  12. package/dist/bootstrap/instructions.d.ts +1 -0
  13. package/dist/bootstrap/instructions.js +8 -0
  14. package/dist/bootstrap/types.d.ts +36 -0
  15. package/dist/bootstrap/types.js +3 -0
  16. package/dist/catalog/ai-catalog-panel.svelte +742 -0
  17. package/dist/catalog/ai-catalog-panel.svelte.d.ts +13 -0
  18. package/dist/catalog/ai-catalog-view-type.d.ts +1 -0
  19. package/dist/catalog/ai-catalog-view-type.js +1 -0
  20. package/dist/catalog/ai-catalog-view.d.ts +22 -0
  21. package/dist/catalog/ai-catalog-view.js +48 -0
  22. package/dist/catalog/filter.d.ts +3 -0
  23. package/dist/catalog/filter.js +24 -0
  24. package/dist/catalog/inventory.d.ts +21 -0
  25. package/dist/catalog/inventory.js +255 -0
  26. package/dist/catalog/tree.d.ts +12 -0
  27. package/dist/catalog/tree.js +60 -0
  28. package/dist/catalog/types.d.ts +44 -0
  29. package/dist/catalog/types.js +1 -0
  30. package/dist/chat/ai-approval-card.svelte +54 -0
  31. package/dist/chat/ai-approval-card.svelte.d.ts +9 -0
  32. package/dist/chat/ai-chat-panel.svelte +1288 -0
  33. package/dist/chat/ai-chat-panel.svelte.d.ts +50 -0
  34. package/dist/chat/ai-inventory-result.css +55 -0
  35. package/dist/chat/ai-inventory-result.svelte +63 -0
  36. package/dist/chat/ai-inventory-result.svelte.d.ts +5 -0
  37. package/dist/chat/ai-question-card.svelte +132 -0
  38. package/dist/chat/ai-question-card.svelte.d.ts +9 -0
  39. package/dist/chat/ai-view-bootstrap.d.ts +13 -0
  40. package/dist/chat/ai-view-bootstrap.js +86 -0
  41. package/dist/chat/ai-view-panel.svelte +89 -0
  42. package/dist/chat/ai-view-panel.svelte.d.ts +13 -0
  43. package/dist/chat/ai-view-type.d.ts +1 -0
  44. package/dist/chat/ai-view-type.js +1 -0
  45. package/dist/chat/ai-view.d.ts +60 -0
  46. package/dist/chat/ai-view.js +121 -0
  47. package/dist/chat/chat-controller.svelte.d.ts +82 -0
  48. package/dist/chat/chat-controller.svelte.js +1926 -0
  49. package/dist/chat/chat-items.d.ts +88 -0
  50. package/dist/chat/chat-items.js +9 -0
  51. package/dist/chat/chat-mentions.d.ts +15 -0
  52. package/dist/chat/chat-mentions.js +77 -0
  53. package/dist/chat/chat-result-views.d.ts +5 -0
  54. package/dist/chat/chat-result-views.js +15 -0
  55. package/dist/chat/chat-session.d.ts +28 -0
  56. package/dist/chat/chat-session.js +50 -0
  57. package/dist/chat/chat-status.d.ts +1 -0
  58. package/dist/chat/chat-status.js +3 -0
  59. package/dist/chat/chat-time.d.ts +18 -0
  60. package/dist/chat/chat-time.js +90 -0
  61. package/dist/chat/chat-tool-display.d.ts +17 -0
  62. package/dist/chat/chat-tool-display.js +213 -0
  63. package/dist/chat/chat-tool-identity.d.ts +4 -0
  64. package/dist/chat/chat-tool-identity.js +42 -0
  65. package/dist/chat/chat-trace.d.ts +6 -0
  66. package/dist/chat/chat-trace.js +256 -0
  67. package/dist/chat/live-runtime-unavailable.d.ts +1 -0
  68. package/dist/chat/live-runtime-unavailable.js +1 -0
  69. package/dist/commands/agent.d.ts +8 -0
  70. package/dist/commands/agent.js +38 -0
  71. package/dist/commands/catalog.d.ts +18 -0
  72. package/dist/commands/catalog.js +115 -0
  73. package/dist/commands/discovery.d.ts +36 -0
  74. package/dist/commands/discovery.js +151 -0
  75. package/dist/commands/groups.d.ts +16 -0
  76. package/dist/commands/groups.js +121 -0
  77. package/dist/commands/inspect.d.ts +18 -0
  78. package/dist/commands/inspect.js +29 -0
  79. package/dist/commands/markdown.d.ts +21 -0
  80. package/dist/commands/markdown.js +117 -0
  81. package/dist/commands/parser.d.ts +4 -0
  82. package/dist/commands/parser.js +24 -0
  83. package/dist/commands/reserved.d.ts +4 -0
  84. package/dist/commands/reserved.js +107 -0
  85. package/dist/commands/router.d.ts +17 -0
  86. package/dist/commands/router.js +170 -0
  87. package/dist/commands/seed.d.ts +4 -0
  88. package/dist/commands/seed.js +8 -0
  89. package/dist/commands/types.d.ts +54 -0
  90. package/dist/commands/types.js +1 -0
  91. package/dist/commands/user-agents-node.d.ts +3 -0
  92. package/dist/commands/user-agents-node.js +52 -0
  93. package/dist/commands/user-agents.d.ts +22 -0
  94. package/dist/commands/user-agents.js +40 -0
  95. package/dist/conversations/approval-grants.d.ts +20 -0
  96. package/dist/conversations/approval-grants.js +75 -0
  97. package/dist/conversations/binding-state.d.ts +6 -0
  98. package/dist/conversations/binding-state.js +35 -0
  99. package/dist/conversations/context-handoff.d.ts +25 -0
  100. package/dist/conversations/context-handoff.js +207 -0
  101. package/dist/conversations/conversation-index-coordinator.d.ts +18 -0
  102. package/dist/conversations/conversation-index-coordinator.js +81 -0
  103. package/dist/conversations/conversation-index.d.ts +16 -0
  104. package/dist/conversations/conversation-index.js +125 -0
  105. package/dist/conversations/conversation-locator.d.ts +2 -0
  106. package/dist/conversations/conversation-locator.js +20 -0
  107. package/dist/conversations/conversation-palette.d.ts +18 -0
  108. package/dist/conversations/conversation-palette.js +29 -0
  109. package/dist/conversations/conversation-repository.d.ts +39 -0
  110. package/dist/conversations/conversation-repository.js +213 -0
  111. package/dist/conversations/handoff-summary.d.ts +48 -0
  112. package/dist/conversations/handoff-summary.js +269 -0
  113. package/dist/conversations/hashes.d.ts +5 -0
  114. package/dist/conversations/hashes.js +40 -0
  115. package/dist/conversations/history-creation-scope.d.ts +12 -0
  116. package/dist/conversations/history-creation-scope.js +44 -0
  117. package/dist/conversations/jsonl.d.ts +10 -0
  118. package/dist/conversations/jsonl.js +41 -0
  119. package/dist/conversations/memory-transcript-store.d.ts +15 -0
  120. package/dist/conversations/memory-transcript-store.js +119 -0
  121. package/dist/conversations/paths.d.ts +14 -0
  122. package/dist/conversations/paths.js +92 -0
  123. package/dist/conversations/redaction.d.ts +13 -0
  124. package/dist/conversations/redaction.js +94 -0
  125. package/dist/conversations/reveal-scope.d.ts +3 -0
  126. package/dist/conversations/reveal-scope.js +8 -0
  127. package/dist/conversations/scope-resolver.d.ts +11 -0
  128. package/dist/conversations/scope-resolver.js +18 -0
  129. package/dist/conversations/scope-tree.d.ts +10 -0
  130. package/dist/conversations/scope-tree.js +71 -0
  131. package/dist/conversations/transcript-projection.d.ts +9 -0
  132. package/dist/conversations/transcript-projection.js +409 -0
  133. package/dist/conversations/transcript-store.d.ts +24 -0
  134. package/dist/conversations/transcript-store.js +27 -0
  135. package/dist/conversations/types.d.ts +224 -0
  136. package/dist/conversations/types.js +12 -0
  137. package/dist/conversations/validation.d.ts +4 -0
  138. package/dist/conversations/validation.js +383 -0
  139. package/dist/conversations/vault-transcript-store.d.ts +22 -0
  140. package/dist/conversations/vault-transcript-store.js +219 -0
  141. package/dist/core/event-queue.d.ts +6 -0
  142. package/dist/core/event-queue.js +39 -0
  143. package/dist/core/types.d.ts +241 -0
  144. package/dist/core/types.js +50 -0
  145. package/dist/history/ai-history-panel.svelte +937 -0
  146. package/dist/history/ai-history-panel.svelte.d.ts +17 -0
  147. package/dist/history/ai-history-view-type.d.ts +1 -0
  148. package/dist/history/ai-history-view-type.js +1 -0
  149. package/dist/history/ai-history-view.d.ts +26 -0
  150. package/dist/history/ai-history-view.js +51 -0
  151. package/dist/history/conversation-history-tree.d.ts +15 -0
  152. package/dist/history/conversation-history-tree.js +71 -0
  153. package/dist/host/agent-workspace.d.ts +6 -0
  154. package/dist/host/agent-workspace.js +16 -0
  155. package/dist/host/create-host-runtimes.d.ts +2 -0
  156. package/dist/host/create-host-runtimes.js +14 -0
  157. package/dist/host/desktop-process-host.d.ts +6 -0
  158. package/dist/host/desktop-process-host.js +74 -0
  159. package/dist/host/host-runtime-availability.d.ts +1 -0
  160. package/dist/host/host-runtime-availability.js +3 -0
  161. package/dist/host/process-host.d.ts +31 -0
  162. package/dist/host/process-host.js +6 -0
  163. package/dist/index.d.ts +69 -0
  164. package/dist/index.js +49 -0
  165. package/dist/jsonl/ai-jsonl-preview.d.ts +27 -0
  166. package/dist/jsonl/ai-jsonl-preview.js +68 -0
  167. package/dist/jsonl/ai-jsonl-view-type.d.ts +1 -0
  168. package/dist/jsonl/ai-jsonl-view-type.js +1 -0
  169. package/dist/jsonl/ai-jsonl-view.d.ts +16 -0
  170. package/dist/jsonl/ai-jsonl-view.js +57 -0
  171. package/dist/jsonl/ai-jsonl-view.svelte +260 -0
  172. package/dist/jsonl/ai-jsonl-view.svelte.d.ts +9 -0
  173. package/dist/memory/candidate-extractor.d.ts +25 -0
  174. package/dist/memory/candidate-extractor.js +191 -0
  175. package/dist/memory/forget-confirmation.d.ts +3 -0
  176. package/dist/memory/forget-confirmation.js +45 -0
  177. package/dist/memory/hashes.d.ts +5 -0
  178. package/dist/memory/hashes.js +37 -0
  179. package/dist/memory/memory-ingestion-coordinator.d.ts +19 -0
  180. package/dist/memory/memory-ingestion-coordinator.js +108 -0
  181. package/dist/memory/memory-record-store.d.ts +62 -0
  182. package/dist/memory/memory-record-store.js +369 -0
  183. package/dist/memory/memory-scheduler.d.ts +21 -0
  184. package/dist/memory/memory-scheduler.js +143 -0
  185. package/dist/memory/memory-tools.d.ts +61 -0
  186. package/dist/memory/memory-tools.js +99 -0
  187. package/dist/memory/native-memory-service.d.ts +72 -0
  188. package/dist/memory/native-memory-service.js +1256 -0
  189. package/dist/memory/paths.d.ts +13 -0
  190. package/dist/memory/paths.js +60 -0
  191. package/dist/memory/runtime-consolidation-provider.d.ts +18 -0
  192. package/dist/memory/runtime-consolidation-provider.js +154 -0
  193. package/dist/memory/types.d.ts +139 -0
  194. package/dist/memory/types.js +1 -0
  195. package/dist/providers/acp-model-provider.d.ts +11 -0
  196. package/dist/providers/acp-model-provider.js +99 -0
  197. package/dist/providers/codex-model-catalog.d.ts +7 -0
  198. package/dist/providers/codex-model-catalog.js +179 -0
  199. package/dist/providers/codex-model-provider.d.ts +12 -0
  200. package/dist/providers/codex-model-provider.js +42 -0
  201. package/dist/providers/model-provider.d.ts +26 -0
  202. package/dist/providers/model-provider.js +26 -0
  203. package/dist/public-components.d.ts +3 -0
  204. package/dist/public-components.js +3 -0
  205. package/dist/registry/runtime-registry.d.ts +11 -0
  206. package/dist/registry/runtime-registry.js +71 -0
  207. package/dist/registry/select-runtime.d.ts +9 -0
  208. package/dist/registry/select-runtime.js +31 -0
  209. package/dist/runtime-adapters.d.ts +16 -0
  210. package/dist/runtime-adapters.js +9 -0
  211. package/dist/runtimes/acp/acp-event-mapper.d.ts +56 -0
  212. package/dist/runtimes/acp/acp-event-mapper.js +237 -0
  213. package/dist/runtimes/acp/acp-runtime.d.ts +46 -0
  214. package/dist/runtimes/acp/acp-runtime.js +165 -0
  215. package/dist/runtimes/acp/desktop-acp-backend.d.ts +16 -0
  216. package/dist/runtimes/acp/desktop-acp-backend.js +243 -0
  217. package/dist/runtimes/codex/app-server-protocol.d.ts +28 -0
  218. package/dist/runtimes/codex/app-server-protocol.js +274 -0
  219. package/dist/runtimes/codex/codex-runtime.d.ts +24 -0
  220. package/dist/runtimes/codex/codex-runtime.js +318 -0
  221. package/dist/runtimes/fake/fake-runtime.d.ts +51 -0
  222. package/dist/runtimes/fake/fake-runtime.js +257 -0
  223. package/dist/sessions/plugin-data.d.ts +8 -0
  224. package/dist/sessions/plugin-data.js +29 -0
  225. package/dist/sessions/session-store.d.ts +47 -0
  226. package/dist/sessions/session-store.js +117 -0
  227. package/dist/settings/acp-agents.d.ts +8 -0
  228. package/dist/settings/acp-agents.js +11 -0
  229. package/dist/settings/ai-settings-tab.d.ts +8 -0
  230. package/dist/settings/ai-settings-tab.js +249 -0
  231. package/dist/settings/ai-settings.d.ts +43 -0
  232. package/dist/settings/ai-settings.js +147 -0
  233. package/dist/settings/app-tool-setting-rows.d.ts +16 -0
  234. package/dist/settings/app-tool-setting-rows.js +30 -0
  235. package/dist/settings/register-ai-settings.d.ts +3 -0
  236. package/dist/settings/register-ai-settings.js +393 -0
  237. package/dist/skills/activation.d.ts +2 -0
  238. package/dist/skills/activation.js +20 -0
  239. package/dist/skills/bundled/lapis-notes.d.ts +3 -0
  240. package/dist/skills/bundled/lapis-notes.js +52 -0
  241. package/dist/skills/bundled/research.d.ts +6 -0
  242. package/dist/skills/bundled/research.js +29 -0
  243. package/dist/skills/discovery.d.ts +21 -0
  244. package/dist/skills/discovery.js +227 -0
  245. package/dist/skills/manifest.d.ts +3 -0
  246. package/dist/skills/manifest.js +39 -0
  247. package/dist/skills/parser.d.ts +12 -0
  248. package/dist/skills/parser.js +124 -0
  249. package/dist/skills/registry.d.ts +21 -0
  250. package/dist/skills/registry.js +89 -0
  251. package/dist/skills/seed.d.ts +5 -0
  252. package/dist/skills/seed.js +18 -0
  253. package/dist/skills/skill-tools.d.ts +8 -0
  254. package/dist/skills/skill-tools.js +113 -0
  255. package/dist/skills/types.d.ts +67 -0
  256. package/dist/skills/types.js +1 -0
  257. package/dist/styles.css +514 -0
  258. package/dist/tools/app-tool-host.d.ts +47 -0
  259. package/dist/tools/app-tool-host.js +419 -0
  260. package/dist/tools/desktop-app-tool-bridge.d.ts +23 -0
  261. package/dist/tools/desktop-app-tool-bridge.js +223 -0
  262. package/dist/tools/mcp-server-registry.d.ts +7 -0
  263. package/dist/tools/mcp-server-registry.js +30 -0
  264. package/manifest.json +34 -0
  265. package/package.json +83 -0
  266. package/styles.css +1 -0
@@ -0,0 +1,274 @@
1
+ import { DEFAULT_APPROVAL_OPTIONS, } from "../../core/types";
2
+ function asRecord(value) {
3
+ return value && typeof value === "object" && !Array.isArray(value)
4
+ ? value
5
+ : {};
6
+ }
7
+ function stringValue(value) {
8
+ return typeof value === "string" ? value : undefined;
9
+ }
10
+ function numberValue(value) {
11
+ return typeof value === "number" && Number.isFinite(value)
12
+ ? value
13
+ : undefined;
14
+ }
15
+ function streamedText(value) {
16
+ if (typeof value === "string")
17
+ return value;
18
+ const record = asRecord(value);
19
+ for (const key of ["text", "delta", "content", "message", "value"]) {
20
+ const candidate = record[key];
21
+ if (typeof candidate === "string")
22
+ return candidate;
23
+ }
24
+ return "";
25
+ }
26
+ function isToolItem(item) {
27
+ return [
28
+ "mcpToolCall",
29
+ "dynamicToolCall",
30
+ "commandExecution",
31
+ "fileChange",
32
+ ].includes(String(item.type ?? ""));
33
+ }
34
+ function toolName(item) {
35
+ if (item.type === "commandExecution")
36
+ return "command";
37
+ if (item.type === "fileChange")
38
+ return "file change";
39
+ return String(item.tool ?? item.command ?? item.type ?? "tool");
40
+ }
41
+ function toolInput(item) {
42
+ return item.command ?? item.arguments ?? item.input ?? item.changes;
43
+ }
44
+ export function mapCodexNotification(message) {
45
+ const params = asRecord(message.params);
46
+ const item = asRecord(params.item);
47
+ const method = message.method ?? "";
48
+ if (method === "item/agentMessage/delta" ||
49
+ method === "turn/agentMessage/delta") {
50
+ const text = streamedText(params.delta ?? params.text);
51
+ return text ? { type: "text", text } : null;
52
+ }
53
+ if (method === "item/reasoning/textDelta" ||
54
+ method === "item/reasoning/delta" ||
55
+ method === "turn/reasoning/delta") {
56
+ const text = streamedText(params.delta ?? params.text);
57
+ return text ? { type: "thinking", text, kind: "reasoning" } : null;
58
+ }
59
+ if (method === "item/reasoning/summaryTextDelta") {
60
+ const text = streamedText(params.delta ?? params.text);
61
+ return text ? { type: "thinking", text, kind: "summary" } : null;
62
+ }
63
+ if (method === "item/plan/delta") {
64
+ const text = streamedText(params.delta ?? params.text);
65
+ return text ? { type: "thinking", text, kind: "plan" } : null;
66
+ }
67
+ if (method === "thread/tokenUsage/updated") {
68
+ const tokenUsage = asRecord(params.tokenUsage);
69
+ const total = asRecord(tokenUsage.total);
70
+ const used = numberValue(total.totalTokens);
71
+ const limit = numberValue(tokenUsage.modelContextWindow);
72
+ return used !== undefined && used >= 0 && limit !== undefined && limit > 0
73
+ ? { type: "usage", usage: { used, limit } }
74
+ : null;
75
+ }
76
+ if (method === "item/started" || method === "item/toolCall/started") {
77
+ if (!isToolItem(item) && method !== "item/toolCall/started")
78
+ return null;
79
+ return {
80
+ type: "tool.start",
81
+ id: String(item.id ?? params.itemId ?? "codex-tool"),
82
+ name: toolName(item),
83
+ server: stringValue(item.server),
84
+ input: toolInput(item),
85
+ };
86
+ }
87
+ if (method === "item/completed") {
88
+ if (isToolItem(item)) {
89
+ return {
90
+ type: "tool.end",
91
+ id: String(item.id ?? params.itemId ?? "codex-tool"),
92
+ name: toolName(item),
93
+ server: stringValue(item.server),
94
+ output: item.result ??
95
+ item.aggregatedOutput ??
96
+ item.contentItems ??
97
+ item.output,
98
+ error: item.error,
99
+ };
100
+ }
101
+ return null;
102
+ }
103
+ if (method === "turn/completed") {
104
+ const turn = asRecord(params.turn);
105
+ if (turn.status === "failed") {
106
+ const error = asRecord(turn.error);
107
+ return {
108
+ type: "error",
109
+ error: new Error(stringValue(error.message) ?? "Codex turn failed"),
110
+ };
111
+ }
112
+ return { type: "completed", result: params };
113
+ }
114
+ if (method === "warning" ||
115
+ method === "guardianWarning" ||
116
+ method === "configWarning" ||
117
+ method === "deprecationNotice") {
118
+ return {
119
+ type: "status",
120
+ status: String(params.message ?? params.warning ?? "Codex warning"),
121
+ };
122
+ }
123
+ if (method === "error" || message.error) {
124
+ const record = asRecord(message.error);
125
+ const paramsError = asRecord(params.error);
126
+ return {
127
+ type: "error",
128
+ error: new Error(stringValue(record.message) ??
129
+ stringValue(params.message) ??
130
+ stringValue(paramsError.message) ??
131
+ "Codex app-server error"),
132
+ };
133
+ }
134
+ return null;
135
+ }
136
+ export function approvalRequestFromServerRequest(message) {
137
+ if (message.id === undefined || !message.method)
138
+ return null;
139
+ const request = asRecord(message.params);
140
+ const method = message.method;
141
+ if (![
142
+ "item/commandExecution/requestApproval",
143
+ "item/fileChange/requestApproval",
144
+ "item/permissions/requestApproval",
145
+ "applyPatchApproval",
146
+ "execCommandApproval",
147
+ ].includes(method)) {
148
+ return null;
149
+ }
150
+ const kind = mapCodexApprovalKind(method.includes("command") || method === "execCommandApproval"
151
+ ? "command"
152
+ : method.includes("file") || method === "applyPatchApproval"
153
+ ? "file_change"
154
+ : "permissions");
155
+ return {
156
+ id: String(message.id),
157
+ origin: "runtime",
158
+ kind,
159
+ title: stringValue(request.reason) ??
160
+ stringValue(request.header) ??
161
+ "Allow this Codex action?",
162
+ tool: request.command
163
+ ? { name: "command", input: request.command }
164
+ : undefined,
165
+ options: DEFAULT_APPROVAL_OPTIONS,
166
+ };
167
+ }
168
+ export function userInputRequestFromServerRequest(message) {
169
+ if (message.id === undefined ||
170
+ message.method !== "item/tool/requestUserInput") {
171
+ return null;
172
+ }
173
+ const params = asRecord(message.params);
174
+ const questions = Array.isArray(params.questions)
175
+ ? params.questions.flatMap((value, questionIndex) => {
176
+ const question = asRecord(value);
177
+ const id = stringValue(question.id);
178
+ const prompt = stringValue(question.question);
179
+ if (!id || !prompt)
180
+ return [];
181
+ const rawOptions = Array.isArray(question.options)
182
+ ? question.options
183
+ : [];
184
+ const options = rawOptions.flatMap((optionValue, optionIndex) => {
185
+ const option = asRecord(optionValue);
186
+ const label = stringValue(option.label);
187
+ if (!label)
188
+ return [];
189
+ return [
190
+ {
191
+ id: `${id}-option-${optionIndex + 1}`,
192
+ label,
193
+ description: stringValue(option.description),
194
+ },
195
+ ];
196
+ });
197
+ return [
198
+ {
199
+ id,
200
+ header: stringValue(question.header) ?? `Question ${questionIndex + 1}`,
201
+ prompt,
202
+ options: options.length > 0 ? options : undefined,
203
+ allowOther: question.isOther === true,
204
+ secret: question.isSecret === true,
205
+ },
206
+ ];
207
+ })
208
+ : [];
209
+ if (questions.length === 0)
210
+ return null;
211
+ return {
212
+ id: String(message.id),
213
+ title: "Agent needs input",
214
+ questions,
215
+ };
216
+ }
217
+ export function userInputReplyForServerRequest(message, answers) {
218
+ if (message.method !== "item/tool/requestUserInput") {
219
+ return { error: { code: -32601, message: "Unsupported input request" } };
220
+ }
221
+ return {
222
+ result: {
223
+ answers: Object.fromEntries(Object.entries(answers).map(([id, values]) => [
224
+ id,
225
+ { answers: [...values] },
226
+ ])),
227
+ },
228
+ };
229
+ }
230
+ export function approvalResponseForOption(optionId) {
231
+ if (optionId === "allow-always")
232
+ return { decision: "acceptForSession" };
233
+ if (optionId === "deny-once" || optionId === "deny-always") {
234
+ return { decision: "decline" };
235
+ }
236
+ return { decision: "accept" };
237
+ }
238
+ export function approvalReplyForServerRequest(message, optionId) {
239
+ if (message.method === "item/permissions/requestApproval") {
240
+ if (optionId.startsWith("deny")) {
241
+ return {
242
+ error: { code: -32000, message: "Permission request declined" },
243
+ };
244
+ }
245
+ const params = asRecord(message.params);
246
+ return {
247
+ result: {
248
+ permissions: params.permissions ?? {},
249
+ scope: optionId === "allow-always" ? "session" : "turn",
250
+ },
251
+ };
252
+ }
253
+ if (message.method === "applyPatchApproval" ||
254
+ message.method === "execCommandApproval") {
255
+ return {
256
+ result: {
257
+ decision: optionId.startsWith("deny") ? "denied" : "approved",
258
+ },
259
+ };
260
+ }
261
+ return { result: approvalResponseForOption(optionId) };
262
+ }
263
+ function mapCodexApprovalKind(kind) {
264
+ if (kind === "command" || kind === "execute")
265
+ return "execute";
266
+ if (kind === "file_change" || kind === "apply_patch" || kind === "write") {
267
+ return "write";
268
+ }
269
+ if (kind === "permissions" || kind === "network")
270
+ return "network";
271
+ if (kind === "read")
272
+ return "read";
273
+ return "other";
274
+ }
@@ -0,0 +1,24 @@
1
+ import { type AgentCapabilities, type AgentEvent, type AgentRequest, type AgentRuntime, type AgentSession, type AgentSessionConfiguration, type AgentSessionConfigurationResult, type AgentTurnOptions, type UserInputAnswers } from "../../core/types";
2
+ import type { AgentProcessHandle, AgentProcessHost } from "../../host/process-host";
3
+ export declare class CodexNativeSession implements AgentSession {
4
+ #private;
5
+ constructor(process: AgentProcessHandle, request: Omit<AgentRequest, "prompt">);
6
+ get id(): string;
7
+ initialize(resumeThreadId?: string): Promise<void>;
8
+ events(): AsyncIterable<AgentEvent>;
9
+ send(input: string, options?: AgentTurnOptions): Promise<void>;
10
+ configure(input: AgentSessionConfiguration): Promise<AgentSessionConfigurationResult>;
11
+ respondToApproval(requestId: string, optionId: string): Promise<void>;
12
+ respondToQuestion(requestId: string, answers: UserInputAnswers): Promise<void>;
13
+ cancel(): Promise<void>;
14
+ close(): Promise<void>;
15
+ }
16
+ export declare class CodexNativeRuntime implements AgentRuntime {
17
+ #private;
18
+ readonly id = "codex-native";
19
+ constructor(host: AgentProcessHost);
20
+ capabilities(): AgentCapabilities;
21
+ supports(request: AgentRequest): Promise<boolean>;
22
+ start(request: AgentRequest): Promise<AgentSession>;
23
+ resume(sessionId: string, request?: Omit<AgentRequest, "prompt">): Promise<AgentSession>;
24
+ }
@@ -0,0 +1,318 @@
1
+ import { AsyncEventQueue } from "../../core/event-queue";
2
+ import { NATIVE_CODEX_APPROVAL_CAPABILITIES, projectAgentTurnPrompt, } from "../../core/types";
3
+ import { approvalReplyForServerRequest, approvalRequestFromServerRequest, mapCodexNotification, userInputReplyForServerRequest, userInputRequestFromServerRequest, } from "./app-server-protocol";
4
+ export class CodexNativeSession {
5
+ #process;
6
+ #request;
7
+ #events = new AsyncEventQueue();
8
+ #pending = new Map();
9
+ #pendingServerRequests = new Map();
10
+ #buffer = "";
11
+ #rpcId = 1;
12
+ #threadId = null;
13
+ #activeTurnId = null;
14
+ #closed = false;
15
+ #consume;
16
+ constructor(process, request) {
17
+ this.#process = process;
18
+ this.#request = request;
19
+ this.#consume = this.#pump();
20
+ }
21
+ get id() {
22
+ return this.#threadId ?? `codex-${this.#process.id}`;
23
+ }
24
+ async initialize(resumeThreadId) {
25
+ await this.#requestRpc("initialize", {
26
+ clientInfo: {
27
+ name: "lapis_notes_ai",
28
+ title: "Lapis Notes AI",
29
+ version: "0.0.1",
30
+ },
31
+ capabilities: { experimentalApi: true },
32
+ });
33
+ await this.#notify("initialized", {});
34
+ const workspace = this.#request.workspace;
35
+ const common = {
36
+ model: this.#request.model?.model ?? null,
37
+ cwd: workspace ?? null,
38
+ runtimeWorkspaceRoots: workspace ? [workspace] : null,
39
+ approvalPolicy: this.#request.restricted ? "never" : "on-request",
40
+ sandbox: "read-only",
41
+ };
42
+ const response = (await this.#requestRpc(resumeThreadId ? "thread/resume" : "thread/start", resumeThreadId
43
+ ? { threadId: resumeThreadId, ...common }
44
+ : { ...common, ephemeral: false }));
45
+ const threadId = response.thread?.id ?? resumeThreadId;
46
+ if (!threadId)
47
+ throw new Error("Codex did not return a thread id.");
48
+ this.#threadId = threadId;
49
+ }
50
+ events() {
51
+ return this.#events;
52
+ }
53
+ async send(input, options) {
54
+ if (!this.#threadId)
55
+ throw new Error("Codex session has not initialized.");
56
+ const response = (await this.#requestRpc("turn/start", {
57
+ threadId: this.#threadId,
58
+ input: [
59
+ {
60
+ type: "text",
61
+ text: projectAgentTurnPrompt(input, options?.contextBlocks),
62
+ text_elements: [],
63
+ },
64
+ ],
65
+ ...(this.#request.workspace
66
+ ? {
67
+ cwd: this.#request.workspace,
68
+ runtimeWorkspaceRoots: [this.#request.workspace],
69
+ }
70
+ : {}),
71
+ approvalPolicy: this.#request.restricted ? "never" : "on-request",
72
+ sandboxPolicy: { type: "readOnly", networkAccess: false },
73
+ ...(this.#request.model?.model
74
+ ? { model: this.#request.model.model }
75
+ : {}),
76
+ ...(thinkingEffort(this.#request.thinking)
77
+ ? { effort: thinkingEffort(this.#request.thinking) }
78
+ : {}),
79
+ }));
80
+ this.#activeTurnId = response.turn?.id ?? this.#activeTurnId;
81
+ }
82
+ async configure(input) {
83
+ this.#request = {
84
+ ...this.#request,
85
+ ...(input.model ? { model: { ...input.model } } : {}),
86
+ ...(input.thinking ? { thinking: input.thinking } : {}),
87
+ };
88
+ return {
89
+ ...(input.model ? { model: { status: "applied" } } : {}),
90
+ ...(input.thinking ? { thinking: { status: "applied" } } : {}),
91
+ };
92
+ }
93
+ async respondToApproval(requestId, optionId) {
94
+ const pending = this.#pendingServerRequests.get(requestId);
95
+ if (!pending)
96
+ throw new Error(`Unknown Codex approval request: ${requestId}`);
97
+ this.#pendingServerRequests.delete(requestId);
98
+ const reply = approvalReplyForServerRequest(pending, optionId);
99
+ await this.#write({ id: pending.id, ...reply });
100
+ }
101
+ async respondToQuestion(requestId, answers) {
102
+ const pending = this.#pendingServerRequests.get(requestId);
103
+ if (!pending || pending.method !== "item/tool/requestUserInput") {
104
+ throw new Error(`Unknown Codex user-input request: ${requestId}`);
105
+ }
106
+ this.#pendingServerRequests.delete(requestId);
107
+ const reply = userInputReplyForServerRequest(pending, answers);
108
+ await this.#write({ id: pending.id, ...reply });
109
+ }
110
+ async cancel() {
111
+ if (!this.#threadId)
112
+ return;
113
+ try {
114
+ await this.#requestRpc("turn/interrupt", {
115
+ threadId: this.#threadId,
116
+ turnId: this.#activeTurnId ?? undefined,
117
+ });
118
+ }
119
+ catch {
120
+ // Cancellation is intentionally idempotent for the UI.
121
+ }
122
+ this.#events.push({ type: "status", status: "cancelled" });
123
+ }
124
+ async close() {
125
+ if (this.#closed)
126
+ return;
127
+ this.#closed = true;
128
+ this.#rejectAll(new Error("Codex session closed."));
129
+ this.#pendingServerRequests.clear();
130
+ await this.#process.kill();
131
+ await this.#consume;
132
+ this.#events.close();
133
+ }
134
+ async #pump() {
135
+ try {
136
+ for await (const message of this.#process.messages()) {
137
+ if (message.type === "stderr")
138
+ continue;
139
+ if (message.type === "exit") {
140
+ if (!this.#closed) {
141
+ const error = new Error(`Codex app-server exited with code ${message.exitCode}.`);
142
+ this.#events.push({ type: "error", error });
143
+ this.#rejectAll(error);
144
+ }
145
+ break;
146
+ }
147
+ this.#buffer += message.data;
148
+ const lines = this.#buffer.split("\n");
149
+ this.#buffer = lines.pop() ?? "";
150
+ for (const line of lines) {
151
+ if (line.trim())
152
+ this.#handleLine(line);
153
+ }
154
+ }
155
+ }
156
+ catch (error) {
157
+ const normalized = error instanceof Error ? error : new Error(String(error));
158
+ this.#events.push({ type: "error", error: normalized });
159
+ this.#rejectAll(normalized);
160
+ }
161
+ finally {
162
+ if (!this.#closed)
163
+ this.#events.close();
164
+ }
165
+ }
166
+ #handleLine(line) {
167
+ let parsed;
168
+ try {
169
+ parsed = JSON.parse(line);
170
+ }
171
+ catch {
172
+ this.#events.push({
173
+ type: "error",
174
+ error: new Error("Codex app-server returned invalid JSONL."),
175
+ });
176
+ return;
177
+ }
178
+ if (parsed.id !== undefined && !parsed.method) {
179
+ const pending = this.#pending.get(parsed.id);
180
+ if (!pending)
181
+ return;
182
+ this.#pending.delete(parsed.id);
183
+ if (parsed.error) {
184
+ const error = parsed.error;
185
+ pending.reject(new Error(String(error.message ?? "Codex request failed")));
186
+ }
187
+ else {
188
+ pending.resolve(parsed.result);
189
+ }
190
+ return;
191
+ }
192
+ const approval = approvalRequestFromServerRequest(parsed);
193
+ if (approval && parsed.id !== undefined) {
194
+ this.#pendingServerRequests.set(approval.id, parsed);
195
+ this.#events.push({ type: "permission.request", request: approval });
196
+ return;
197
+ }
198
+ const question = userInputRequestFromServerRequest(parsed);
199
+ if (question && parsed.id !== undefined) {
200
+ this.#pendingServerRequests.set(question.id, parsed);
201
+ this.#events.push({ type: "question.request", request: question });
202
+ return;
203
+ }
204
+ const event = mapCodexNotification(parsed);
205
+ if (!event)
206
+ return;
207
+ if (event.type === "completed" || event.type === "error") {
208
+ this.#activeTurnId = null;
209
+ }
210
+ this.#events.push(event);
211
+ }
212
+ async #requestRpc(method, params) {
213
+ const id = this.#rpcId++;
214
+ const result = new Promise((resolve, reject) => {
215
+ const timer = setTimeout(() => {
216
+ this.#pending.delete(id);
217
+ reject(new Error(`Codex ${method} request timed out.`));
218
+ }, 15_000);
219
+ this.#pending.set(id, {
220
+ resolve(value) {
221
+ clearTimeout(timer);
222
+ resolve(value);
223
+ },
224
+ reject(error) {
225
+ clearTimeout(timer);
226
+ reject(error);
227
+ },
228
+ });
229
+ });
230
+ try {
231
+ await this.#write({ id, method, params });
232
+ }
233
+ catch (error) {
234
+ const normalized = error instanceof Error ? error : new Error(String(error));
235
+ this.#pending.get(id)?.reject(normalized);
236
+ this.#pending.delete(id);
237
+ return result;
238
+ }
239
+ return result;
240
+ }
241
+ async #notify(method, params) {
242
+ await this.#write({ method, params });
243
+ }
244
+ async #write(message) {
245
+ await this.#process.write(`${JSON.stringify(message)}\n`);
246
+ }
247
+ #rejectAll(error) {
248
+ for (const [id, pending] of this.#pending) {
249
+ this.#pending.delete(id);
250
+ pending.reject(error);
251
+ }
252
+ }
253
+ }
254
+ export class CodexNativeRuntime {
255
+ id = "codex-native";
256
+ #host;
257
+ constructor(host) {
258
+ this.#host = host;
259
+ }
260
+ capabilities() {
261
+ return {
262
+ sessions: true,
263
+ resume: true,
264
+ cancel: true,
265
+ steer: false,
266
+ modelSelection: true,
267
+ nativeTools: true,
268
+ mcpTools: true,
269
+ approvals: NATIVE_CODEX_APPROVAL_CAPABILITIES,
270
+ };
271
+ }
272
+ async supports(request) {
273
+ return this.#host.available && request.agent !== "cursor";
274
+ }
275
+ async start(request) {
276
+ return this.#open(request);
277
+ }
278
+ async resume(sessionId, request = {}) {
279
+ return this.#open({ ...request, prompt: "" }, sessionId);
280
+ }
281
+ async #open(request, resumeThreadId) {
282
+ const process = await this.#host.spawn({
283
+ command: "codex",
284
+ args: codexArgsFor(request.mcpServers),
285
+ cwd: request.workspace,
286
+ appToolBridgeId: request.appToolSession?.bridgeId,
287
+ });
288
+ const session = new CodexNativeSession(process, request);
289
+ try {
290
+ await session.initialize(resumeThreadId);
291
+ return session;
292
+ }
293
+ catch (error) {
294
+ await session.close();
295
+ throw error;
296
+ }
297
+ }
298
+ }
299
+ function thinkingEffort(thinking) {
300
+ return thinking === "off" ? "none" : thinking;
301
+ }
302
+ function codexArgsFor(mcpServers) {
303
+ const args = ["app-server", "--stdio"];
304
+ for (const server of mcpServers ?? []) {
305
+ const prefix = `mcp_servers.${server.name}`;
306
+ args.push("-c", `${prefix}.command=${JSON.stringify(server.command)}`);
307
+ if (server.args) {
308
+ args.push("-c", `${prefix}.args=${JSON.stringify(server.args)}`);
309
+ }
310
+ if (server.cwd) {
311
+ args.push("-c", `${prefix}.cwd=${JSON.stringify(server.cwd)}`);
312
+ }
313
+ if (server.enabledTools) {
314
+ args.push("-c", `${prefix}.enabled_tools=${JSON.stringify(server.enabledTools)}`);
315
+ }
316
+ }
317
+ return args;
318
+ }
@@ -0,0 +1,51 @@
1
+ import { type AgentCapabilities, type AgentEvent, type AgentRequest, type AgentRuntime, type AgentSession, type AgentSessionConfiguration, type AgentSessionConfigurationResult, type AgentTurnOptions, type UserInputAnswers } from "../../core/types";
2
+ import type { NativeAgentCommand } from "../../skills/types";
3
+ export type FakeAgentTrace = "echo" | "rich";
4
+ export type FakeAgentRuntimeOptions = {
5
+ id?: string;
6
+ requireApproval?: boolean;
7
+ requireQuestion?: boolean;
8
+ resumeSupported?: boolean;
9
+ trace?: FakeAgentTrace;
10
+ nativeCommands?: NativeAgentCommand[];
11
+ };
12
+ export declare const FAKE_RICH_THINKING = "I will read the mentioned note, then summarize it.";
13
+ export declare const FAKE_RICH_TOOL: {
14
+ readonly id: "tool-vault-read";
15
+ readonly name: "vault.read";
16
+ readonly input: {
17
+ readonly path: "Notes/alpha.md";
18
+ };
19
+ readonly output: "heading: Notes";
20
+ };
21
+ export declare const FAKE_RICH_ASSISTANT_TEXT: string;
22
+ export declare class FakeAgentSession implements AgentSession {
23
+ #private;
24
+ readonly id: string;
25
+ readonly prompts: string[];
26
+ readonly contextBlocks: AgentTurnOptions["contextBlocks"][];
27
+ readonly configurations: AgentSessionConfiguration[];
28
+ cancelled: boolean;
29
+ closed: boolean;
30
+ detached: boolean;
31
+ constructor(id: string, requireApproval: boolean, trace?: FakeAgentTrace, requireQuestion?: boolean, nativeCommands?: NativeAgentCommand[]);
32
+ events(): AsyncIterable<AgentEvent>;
33
+ send(input: string, options?: AgentTurnOptions): Promise<void>;
34
+ configure(input: AgentSessionConfiguration): Promise<AgentSessionConfigurationResult>;
35
+ respondToApproval(requestId: string, optionId: string): Promise<void>;
36
+ respondToQuestion(requestId: string, answers: UserInputAnswers): Promise<void>;
37
+ cancel(): Promise<void>;
38
+ close(): Promise<void>;
39
+ detach(): Promise<void>;
40
+ }
41
+ export declare class FakeAgentRuntime implements AgentRuntime {
42
+ #private;
43
+ readonly id: string;
44
+ readonly sessions: FakeAgentSession[];
45
+ lastRequest: AgentRequest | null;
46
+ constructor(options?: FakeAgentRuntimeOptions);
47
+ capabilities(): AgentCapabilities;
48
+ supports(request: AgentRequest): Promise<boolean>;
49
+ start(request: AgentRequest): Promise<AgentSession>;
50
+ resume(sessionId: string): Promise<AgentSession>;
51
+ }