paseo-plugin-zcode-provider 0.0.0-stage → 0.2.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 (141) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +29 -0
  3. package/README.md +112 -2
  4. package/client/account.tsx +827 -0
  5. package/client/diagnostics.tsx +379 -0
  6. package/client/runtime.tsx +296 -0
  7. package/client/settings.tsx +84 -0
  8. package/client/value.tsx +20 -0
  9. package/icon.svg +1 -0
  10. package/index.client.tsx +22 -0
  11. package/index.server.ts +39 -0
  12. package/package.json +77 -4
  13. package/paseo-plugin.json +6 -0
  14. package/server/account.ts +781 -0
  15. package/server/attachments.ts +150 -0
  16. package/server/build-info.ts +2 -0
  17. package/server/conversation.ts +319 -0
  18. package/server/diagnostics.ts +252 -0
  19. package/server/discovery/discover.ts +225 -0
  20. package/server/discovery/manifest.ts +36 -0
  21. package/server/discovery/types.ts +30 -0
  22. package/server/errors.ts +36 -0
  23. package/server/host/bridge.ts +490 -0
  24. package/server/host/schemas.ts +119 -0
  25. package/server/logger.ts +19 -0
  26. package/server/mapping.ts +270 -0
  27. package/server/models.ts +68 -0
  28. package/server/persistence.ts +146 -0
  29. package/server/presentation.ts +470 -0
  30. package/server/provider-status.ts +81 -0
  31. package/server/provider.ts +838 -0
  32. package/server/runtime/managed.ts +501 -0
  33. package/server/runtime/pins.ts +72 -0
  34. package/server/runtime-setup.ts +77 -0
  35. package/server/session-types.ts +49 -0
  36. package/server/session.ts +866 -0
  37. package/server/status.ts +89 -0
  38. package/server/timeline.ts +18 -0
  39. package/server/usage.ts +362 -0
  40. package/server/vendor/zcode/LICENSE +202 -0
  41. package/server/vendor/zcode/NOTICE.md +70 -0
  42. package/server/vendor/zcode/THIRD-PARTY-NOTICES.md +37 -0
  43. package/server/vendor/zcode/packages/model-option-map/src/compiler.ts +92 -0
  44. package/server/vendor/zcode/packages/model-option-map/src/evaluator.ts +214 -0
  45. package/server/vendor/zcode/packages/model-option-map/src/index.ts +5 -0
  46. package/server/vendor/zcode/packages/model-option-map/src/merge-patch.ts +97 -0
  47. package/server/vendor/zcode/packages/model-option-map/src/option-maps.ts +42 -0
  48. package/server/vendor/zcode/packages/model-option-map/src/parser.ts +240 -0
  49. package/server/vendor/zcode/packages/model-option-map/src/tokenizer.ts +141 -0
  50. package/server/vendor/zcode/packages/model-option-map/src/types.ts +36 -0
  51. package/server/vendor/zcode/packages/rpc/src/buffer.ts +88 -0
  52. package/server/vendor/zcode/packages/rpc/src/channelClient.ts +275 -0
  53. package/server/vendor/zcode/packages/rpc/src/channelServer.ts +283 -0
  54. package/server/vendor/zcode/packages/rpc/src/channels.shared.ts +66 -0
  55. package/server/vendor/zcode/packages/rpc/src/channels.ts +4 -0
  56. package/server/vendor/zcode/packages/rpc/src/delayedChannel.ts +17 -0
  57. package/server/vendor/zcode/packages/rpc/src/foundation.ts +260 -0
  58. package/server/vendor/zcode/packages/rpc/src/protocol.ts +397 -0
  59. package/server/vendor/zcode/packages/rpc/src/proxy-channel.ts +213 -0
  60. package/server/vendor/zcode/packages/rpc/src/serialization.ts +291 -0
  61. package/server/vendor/zcode/packages/shared/src/account-provider-state.ts +13 -0
  62. package/server/vendor/zcode/packages/shared/src/background-bash-output.ts +24 -0
  63. package/server/vendor/zcode/packages/shared/src/background-task-controls.ts +404 -0
  64. package/server/vendor/zcode/packages/shared/src/bash-output-display.ts +11 -0
  65. package/server/vendor/zcode/packages/shared/src/bots.ts +558 -0
  66. package/server/vendor/zcode/packages/shared/src/browser-use/backend.ts +80 -0
  67. package/server/vendor/zcode/packages/shared/src/browser-use/command-metadata.ts +170 -0
  68. package/server/vendor/zcode/packages/shared/src/browser-use/commands.ts +588 -0
  69. package/server/vendor/zcode/packages/shared/src/browser-use/result.ts +130 -0
  70. package/server/vendor/zcode/packages/shared/src/browser-use/snapshot.ts +77 -0
  71. package/server/vendor/zcode/packages/shared/src/command-types.ts +96 -0
  72. package/server/vendor/zcode/packages/shared/src/config-schema.ts +8 -0
  73. package/server/vendor/zcode/packages/shared/src/cuaAccessibilitySettings.ts +41 -0
  74. package/server/vendor/zcode/packages/shared/src/database-startup.ts +178 -0
  75. package/server/vendor/zcode/packages/shared/src/env.ts +63 -0
  76. package/server/vendor/zcode/packages/shared/src/execution-output-preview.ts +14 -0
  77. package/server/vendor/zcode/packages/shared/src/localTtft.ts +192 -0
  78. package/server/vendor/zcode/packages/shared/src/model-config.ts +123 -0
  79. package/server/vendor/zcode/packages/shared/src/model-execution.ts +23 -0
  80. package/server/vendor/zcode/packages/shared/src/model-provider-family.ts +171 -0
  81. package/server/vendor/zcode/packages/shared/src/model-provider-types.ts +81 -0
  82. package/server/vendor/zcode/packages/shared/src/model-selection.ts +60 -0
  83. package/server/vendor/zcode/packages/shared/src/oauth.ts +203 -0
  84. package/server/vendor/zcode/packages/shared/src/official-mcp-auth.ts +272 -0
  85. package/server/vendor/zcode/packages/shared/src/official-mcp-tool-error.ts +68 -0
  86. package/server/vendor/zcode/packages/shared/src/process-diagnostic.ts +42 -0
  87. package/server/vendor/zcode/packages/shared/src/protocol.ts +369 -0
  88. package/server/vendor/zcode/packages/shared/src/provider-family-connection-selection.ts +32 -0
  89. package/server/vendor/zcode/packages/shared/src/remoteAssetInstallMode.ts +11 -0
  90. package/server/vendor/zcode/packages/shared/src/remoteResourcePackages.ts +91 -0
  91. package/server/vendor/zcode/packages/shared/src/runtimeEnv.ts +315 -0
  92. package/server/vendor/zcode/packages/shared/src/settings-source.ts +10 -0
  93. package/server/vendor/zcode/packages/shared/src/usage-quota.ts +74 -0
  94. package/server/vendor/zcode/packages/shared/src/usage-stats.ts +462 -0
  95. package/server/vendor/zcode/packages/shared/src/validationAppSettings.ts +562 -0
  96. package/server/vendor/zcode/packages/shared/src/workspacePurpose.ts +2 -0
  97. package/server/vendor/zcode/packages/shared/src/wslUserValidation.ts +33 -0
  98. package/server/vendor/zcode/packages/shared/src/zcode-agent-policy.ts +25 -0
  99. package/server/vendor/zcode/packages/shared/src/zcode-media-policy.ts +10 -0
  100. package/server/vendor/zcode/packages/shared/src/zcode-protocol/index.ts +3720 -0
  101. package/server/vendor/zcode/packages/shared/src/zcode-protocol-legacy-types.ts +529 -0
  102. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/apply.ts +218 -0
  103. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/attachment-ref.ts +14 -0
  104. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/command.ts +482 -0
  105. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/core.ts +100 -0
  106. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/create-workflow-display.ts +156 -0
  107. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/cuaPermission.ts +41 -0
  108. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/delta.ts +147 -0
  109. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/input-intent.ts +69 -0
  110. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/rows.ts +432 -0
  111. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/session-config.ts +43 -0
  112. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/sessions-index-workflow-activity.ts +195 -0
  113. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/sessions-index.ts +85 -0
  114. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/shared-context-import.ts +38 -0
  115. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/shared-context-ref.ts +10 -0
  116. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/snapshot.ts +509 -0
  117. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/submission.ts +5 -0
  118. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/toolDisplay.ts +264 -0
  119. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/transport.ts +1152 -0
  120. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/wire-assembler.ts +574 -0
  121. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/wire-binary.ts +65 -0
  122. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/wire-codec.ts +240 -0
  123. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/wire-fault.ts +39 -0
  124. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/wire.ts +159 -0
  125. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-artifacts.ts +291 -0
  126. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-observation-display.ts +281 -0
  127. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-row-meta.ts +163 -0
  128. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-run-settings-command.ts +62 -0
  129. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-runs-delta.ts +517 -0
  130. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-runs.ts +512 -0
  131. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workspace-config.ts +81 -0
  132. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workspace-hook-review.ts +210 -0
  133. package/server/vendor/zcode/packages/shared/src/zcode-task-mode-schema.ts +6 -0
  134. package/server/vendor/zcode/packages/shared/src/zcode-task-types-core.ts +1187 -0
  135. package/server/vendor/zcode/packages/shared/src/zcodeEndpoint.ts +296 -0
  136. package/server/vendor/zcode/provenance.json +405 -0
  137. package/shared/account.ts +201 -0
  138. package/shared/diagnostics.ts +52 -0
  139. package/shared/runtime-setup.ts +73 -0
  140. package/vendor/acp-registry/LICENSE +176 -0
  141. package/vendor/paseo/LICENSE +211 -0
@@ -0,0 +1,470 @@
1
+ import type {
2
+ ProviderPermissionAction,
3
+ ProviderPermissionRequest,
4
+ ProviderPermissionResponse,
5
+ ProviderTimelineItem,
6
+ ProviderToolCallDetail,
7
+ ProviderUsage,
8
+ } from "@getpaseo/plugin/server/provider";
9
+ import type {
10
+ ConversationRow,
11
+ HookInvocationRow,
12
+ TimelineMarkerPayload,
13
+ } from "./vendor/zcode/packages/shared/src/zcode-protocol-v4/rows.js";
14
+ import type {
15
+ ConversationSnapshot,
16
+ PendingInteraction,
17
+ } from "./vendor/zcode/packages/shared/src/zcode-protocol-v4/snapshot.js";
18
+ import { AdapterError } from "./errors.js";
19
+ import { jsonValue, record, planMarkdown } from "./mapping.js";
20
+
21
+ export function rowTimeline(
22
+ row: ConversationRow,
23
+ clientMessageId?: string,
24
+ ): ProviderTimelineItem | undefined {
25
+ const id = `zcode:row:${row.rowId}`;
26
+ switch (row.kind) {
27
+ case "turnHeader":
28
+ return;
29
+ case "userInput":
30
+ return row.origin === "realUser"
31
+ ? {
32
+ id,
33
+ type: "user_message",
34
+ text: [
35
+ row.text,
36
+ ...(row.attachments ?? []).map(
37
+ (a) =>
38
+ `[Attachment: ${a.fileName} (${a.mime}, ${a.bytes} bytes)]`,
39
+ ),
40
+ ]
41
+ .filter(Boolean)
42
+ .join("\n\n"),
43
+ messageId: row.sourceCommandId ?? row.entityId,
44
+ ...(clientMessageId ? { clientMessageId } : {}),
45
+ }
46
+ : { id, type: "notification", level: "info", message: row.text };
47
+ case "assistantText":
48
+ return {
49
+ id,
50
+ type: "assistant_message",
51
+ text: row.text,
52
+ messageId: row.assistantResponseId ?? row.entityId,
53
+ };
54
+ case "reasoning":
55
+ return { id, type: "reasoning", text: row.text };
56
+ case "toolCall": {
57
+ const input = record(row.input);
58
+ const truncated =
59
+ !!row.output?.truncated ||
60
+ (row.output?.display?.kind === "bash_output" &&
61
+ row.output.display.truncated);
62
+ const text =
63
+ (row.output?.text ?? row.error?.message ?? "") +
64
+ (truncated
65
+ ? "\n[ZCode truncated this output; the full result has not been loaded.]"
66
+ : "");
67
+ let detail: ProviderToolCallDetail;
68
+ if (row.toolName === "Bash" && typeof input.command === "string")
69
+ detail = { type: "shell", command: input.command, output: text };
70
+ else if (row.toolName === "Read" && typeof input.file_path === "string")
71
+ detail = { type: "read", filePath: input.file_path, content: text };
72
+ else if (row.toolName === "Write" && typeof input.file_path === "string")
73
+ detail = {
74
+ type: "write",
75
+ filePath: input.file_path,
76
+ ...(typeof input.content === "string"
77
+ ? { content: input.content }
78
+ : {}),
79
+ };
80
+ else if (row.toolName === "Edit" && typeof input.file_path === "string")
81
+ detail = {
82
+ type: "edit",
83
+ filePath: input.file_path,
84
+ ...(typeof input.old_string === "string"
85
+ ? { oldString: input.old_string }
86
+ : {}),
87
+ ...(typeof input.new_string === "string"
88
+ ? { newString: input.new_string }
89
+ : {}),
90
+ };
91
+ else
92
+ detail = {
93
+ type: "unknown",
94
+ input: jsonValue(row.input ?? row.inputText),
95
+ output: jsonValue({
96
+ text,
97
+ ...(row.output?.display ? { display: row.output.display } : {}),
98
+ truncated,
99
+ }),
100
+ };
101
+ const base = {
102
+ id,
103
+ type: "tool_call" as const,
104
+ callId: row.toolCallId,
105
+ name: row.toolName,
106
+ detail,
107
+ metadata: {
108
+ truncated,
109
+ ...(row.backgrounded ? { backgrounded: true } : {}),
110
+ },
111
+ };
112
+ return row.status === "error"
113
+ ? { ...base, status: "failed", error: jsonValue(row.error ?? text) }
114
+ : {
115
+ ...base,
116
+ status:
117
+ row.status === "success"
118
+ ? "completed"
119
+ : row.status === "cancelled"
120
+ ? "canceled"
121
+ : "running",
122
+ error: null,
123
+ };
124
+ }
125
+ case "subagent": {
126
+ const base = {
127
+ id,
128
+ type: "tool_call" as const,
129
+ callId: row.entityId ?? `subagent:${row.rowId}`,
130
+ name: row.subagentType,
131
+ detail: {
132
+ type: "sub_agent" as const,
133
+ subAgentType: row.subagentType,
134
+ log: row.summaryText,
135
+ },
136
+ metadata: {
137
+ backgrounded: row.backgrounded === true,
138
+ ...(row.childSessionId
139
+ ? { zcodeChildSessionId: row.childSessionId }
140
+ : {}),
141
+ },
142
+ };
143
+ return row.status === "failed"
144
+ ? { ...base, status: "failed", error: row.summaryText }
145
+ : {
146
+ ...base,
147
+ status:
148
+ row.status === "success"
149
+ ? "completed"
150
+ : row.status === "cancelled"
151
+ ? "canceled"
152
+ : "running",
153
+ error: null,
154
+ };
155
+ }
156
+ case "artifact":
157
+ return {
158
+ id,
159
+ type: "notification",
160
+ level: "info",
161
+ message: `${row.displayName} (${row.artifactType}, ${row.sizeBytes} bytes)`,
162
+ };
163
+ case "hookInvocation":
164
+ return hookTimeline(id, row);
165
+ case "timelineMarker":
166
+ // Paseo appends every notification it receives, so a changing row is
167
+ // reported once, in its final state.
168
+ if (row.marker.type === "compact" && row.marker.status === "running")
169
+ return;
170
+ return {
171
+ id,
172
+ type: "notification",
173
+ level: "info",
174
+ message: markerText(row.marker),
175
+ };
176
+ }
177
+ }
178
+ // Like ZCode Desktop, which keeps hooks out of the conversation and lists
179
+ // them on request, successful hooks are not shown. Paseo appends every
180
+ // notification it receives, so an invocation is reported once, after it ends,
181
+ // and only when a hook that ran did not succeed.
182
+ function hookTimeline(
183
+ id: string,
184
+ row: HookInvocationRow,
185
+ ): ProviderTimelineItem | undefined {
186
+ if (
187
+ row.state === "running" ||
188
+ row.executions.some((h) => h.state === "running")
189
+ )
190
+ return;
191
+ const problems = row.executions.flatMap((hook) => {
192
+ if (!hook.didExecute) return [];
193
+ const outcome =
194
+ hook.outcome && hook.outcome !== "success"
195
+ ? hook.outcome
196
+ : hook.state === "failed"
197
+ ? "failed"
198
+ : undefined;
199
+ return outcome ? [{ hook, outcome }] : [];
200
+ });
201
+ if (problems.length === 0) return;
202
+ const outcomes = new Set(problems.map((p) => p.outcome));
203
+ return {
204
+ id,
205
+ type: "notification",
206
+ level: outcomes.has("failed")
207
+ ? "error"
208
+ : outcomes.has("blocked") || outcomes.has("timed_out")
209
+ ? "warning"
210
+ : "info",
211
+ message: `${row.hookEventName} hook ${problems
212
+ .map(
213
+ ({ hook, outcome }) =>
214
+ `${outcome.replace("_", " ")}: ${hook.displayName}${hook.blockReason ? ` (${hook.blockReason})` : ""}`,
215
+ )
216
+ .join("; ")}`,
217
+ };
218
+ }
219
+
220
+ export function usage(state: ConversationSnapshot): ProviderUsage {
221
+ return {
222
+ inputTokens: state.usage.cumulative.inputTokens,
223
+ cachedInputTokens: state.usage.cumulative.cacheReadTokens,
224
+ outputTokens: state.usage.cumulative.outputTokens,
225
+ ...(state.usage.contextWindow
226
+ ? {
227
+ contextWindowUsedTokens: state.usage.contextWindow.usedTokens,
228
+ contextWindowMaxTokens: state.usage.contextWindow.maxTokens,
229
+ }
230
+ : {}),
231
+ };
232
+ }
233
+ export interface PresentedInteraction {
234
+ request: ProviderPermissionRequest;
235
+ answer(response: ProviderPermissionResponse): Record<string, unknown>;
236
+ }
237
+ export function presentInteraction(
238
+ interaction: PendingInteraction,
239
+ ): PresentedInteraction | undefined {
240
+ const p = interaction.payload,
241
+ id = interaction.interactionId;
242
+ if (p.kind === "workspaceHookReview") return;
243
+ if (p.kind === "permission") {
244
+ const options = p.options.filter((o) => o.optionId !== "fullAccess");
245
+ const actions: ProviderPermissionAction[] = options.map((o) => {
246
+ const behavior =
247
+ o.response?.decision ??
248
+ (o.kind === "deny"
249
+ ? "deny"
250
+ : o.kind === "allowOnce" || o.kind === "allowAlways"
251
+ ? "allow"
252
+ : undefined);
253
+ if (behavior !== "allow" && behavior !== "deny")
254
+ throw new AdapterError(
255
+ "INTERACTION_UNSUPPORTED",
256
+ "ZCode permission option cannot be represented",
257
+ );
258
+ return {
259
+ id: o.optionId,
260
+ label: o.label,
261
+ behavior,
262
+ variant: behavior === "allow" ? "primary" : "danger",
263
+ };
264
+ });
265
+ if (!actions.some((a) => a.behavior === "deny"))
266
+ throw new AdapterError(
267
+ "NATIVE_PROTOCOL_ERROR",
268
+ "ZCode permission has no deny option",
269
+ );
270
+ const plan = p.toolName === "ExitPlanMode";
271
+ const markdown = plan ? planMarkdown(p.detail) : undefined;
272
+ return {
273
+ request: {
274
+ id,
275
+ name: plan ? "ZCodePlanApproval" : p.toolName,
276
+ kind: plan ? "plan" : "tool",
277
+ title: plan ? "Plan" : p.toolName,
278
+ description: p.summary,
279
+ actions,
280
+ ...(markdown
281
+ ? {
282
+ input: { plan: markdown },
283
+ metadata: { planText: markdown, source: "zcode_plan_approval" },
284
+ }
285
+ : {
286
+ detail: {
287
+ type: "unknown",
288
+ input: jsonValue(p.detail ?? null),
289
+ output: null,
290
+ },
291
+ }),
292
+ },
293
+ answer(response) {
294
+ const action = actions.find((a) => a.id === response.selectedActionId);
295
+ if (!action || action.behavior !== response.behavior)
296
+ throw new AdapterError(
297
+ "INVALID_CONFIGURATION",
298
+ "Permission response does not match an offered action",
299
+ );
300
+ return { optionId: action.id };
301
+ },
302
+ };
303
+ }
304
+ if (p.sensitive)
305
+ throw new AdapterError(
306
+ "INTERACTION_UNSUPPORTED",
307
+ "Sensitive ZCode input must be completed in the official CLI",
308
+ );
309
+ const questions = p.questions;
310
+ if (!questions?.length)
311
+ throw new AdapterError(
312
+ "INTERACTION_UNSUPPORTED",
313
+ "ZCode question has no representable fields",
314
+ );
315
+ const headers = new Set<string>();
316
+ const prompts = new Set<string>();
317
+ for (const q of questions) {
318
+ if (
319
+ headers.has(q.header) ||
320
+ prompts.has(q.question) ||
321
+ new Set(q.options.map((o) => o.label)).size !== q.options.length ||
322
+ new Set(q.options.map((o) => o.value)).size !== q.options.length ||
323
+ q.options.some((o) => q.multiSelect && o.label.includes(", "))
324
+ )
325
+ throw new AdapterError(
326
+ "INTERACTION_UNSUPPORTED",
327
+ "ZCode question has ambiguous labels",
328
+ );
329
+ headers.add(q.header);
330
+ prompts.add(q.question);
331
+ }
332
+ const plan = record(p.schema).interaction === "plan_approval";
333
+ const answerContent = (answers: Record<string, unknown>) => {
334
+ const content: Record<string, unknown> = {},
335
+ nativeAnswers: Record<string, string[]> = {};
336
+ questions.forEach((q, i) => {
337
+ const value = answers[q.header];
338
+ if (typeof value !== "string")
339
+ throw new AdapterError(
340
+ "INVALID_CONFIGURATION",
341
+ "A ZCode question answer is missing",
342
+ );
343
+ const labels =
344
+ value === "" ? [] : q.multiSelect ? value.split(", ") : [value];
345
+ if (new Set(labels).size !== labels.length)
346
+ throw new AdapterError(
347
+ "INVALID_CONFIGURATION",
348
+ "Duplicate question answer",
349
+ );
350
+ const values = labels.map((label) => {
351
+ const option = q.options.find((o) => o.label === label);
352
+ if (option) return option.value;
353
+ if (p.freeText) return label;
354
+ throw new AdapterError(
355
+ "INVALID_CONFIGURATION",
356
+ "Unknown question option",
357
+ );
358
+ });
359
+ nativeAnswers[q.question] = values;
360
+ content[`answer_${i}`] = q.multiSelect ? values : (values[0] ?? "");
361
+ if (i === 0) content.answer = content[`answer_${i}`];
362
+ });
363
+ return { ...content, answers: nativeAnswers };
364
+ };
365
+ if (plan) {
366
+ if (questions.length !== 1 || questions[0]!.multiSelect)
367
+ throw new AdapterError(
368
+ "INTERACTION_UNSUPPORTED",
369
+ "Unsupported ZCode Plan approval fields",
370
+ );
371
+ const question = questions[0]!,
372
+ markdown = planMarkdown(p.input);
373
+ const actions: ProviderPermissionAction[] = [
374
+ ...question.options.map((o) => ({
375
+ id: o.value,
376
+ label: o.label,
377
+ behavior: "allow" as const,
378
+ variant: "primary" as const,
379
+ intent: "implement" as const,
380
+ })),
381
+ {
382
+ id: `dismiss:${id}`,
383
+ label: "Dismiss",
384
+ behavior: "deny",
385
+ intent: "dismiss",
386
+ variant: "danger",
387
+ },
388
+ ];
389
+ return {
390
+ request: {
391
+ id,
392
+ name: "ZCodePlanApproval",
393
+ kind: "plan",
394
+ title: "Plan",
395
+ description: p.prompt,
396
+ input: { plan: markdown },
397
+ metadata: { planText: markdown, source: "zcode_plan_approval" },
398
+ actions,
399
+ },
400
+ answer(response) {
401
+ const action = actions.find((a) => a.id === response.selectedActionId);
402
+ if (!action || action.behavior !== response.behavior)
403
+ throw new AdapterError(
404
+ "INVALID_CONFIGURATION",
405
+ "Plan response does not match an offered action",
406
+ );
407
+ if (action.behavior === "deny") return { action: "decline" };
408
+ return {
409
+ action: "accept",
410
+ content: {
411
+ answer_0: action.id,
412
+ answer: action.id,
413
+ answers: { [question.question]: [action.id] },
414
+ },
415
+ };
416
+ },
417
+ };
418
+ }
419
+ return {
420
+ request: {
421
+ id,
422
+ name: "ZCodeQuestion",
423
+ kind: "question",
424
+ title: p.prompt,
425
+ input: {
426
+ questions: questions.map((q) => ({
427
+ question: q.question,
428
+ header: q.header,
429
+ options: q.options.map((o) => ({
430
+ label: o.label,
431
+ ...(o.description ? { description: o.description } : {}),
432
+ })),
433
+ multiSelect: q.multiSelect === true,
434
+ allowOther: p.freeText,
435
+ allowEmpty: true,
436
+ dismissLabel: "Dismiss",
437
+ })),
438
+ },
439
+ },
440
+ answer(response) {
441
+ return response.behavior === "deny"
442
+ ? { action: response.interrupt ? "cancel" : "decline" }
443
+ : {
444
+ action: "accept",
445
+ content: answerContent(record(response.updatedInput?.answers)),
446
+ };
447
+ },
448
+ };
449
+ }
450
+
451
+ function markerText(marker: TimelineMarkerPayload): string {
452
+ switch (marker.type) {
453
+ case "compact":
454
+ return `Context compaction: ${marker.status}`;
455
+ case "modelChange":
456
+ return `Model: ${marker.toModel} (${marker.toThought})`;
457
+ case "forkNotice":
458
+ return "Conversation continued from a parent conversation.";
459
+ case "forkCreated":
460
+ return "ZCode created a child conversation.";
461
+ case "goalSet":
462
+ return `Goal: ${marker.objective}`;
463
+ case "goalVerify":
464
+ return `Goal verification: ${marker.outcome}${marker.detail ? ` — ${marker.detail}` : ""}`;
465
+ case "retryNotice":
466
+ return `ZCode is retrying the model request (attempt ${marker.attempt}).`;
467
+ case "checkpointRestored":
468
+ return "ZCode restored a file checkpoint.";
469
+ }
470
+ }
@@ -0,0 +1,81 @@
1
+ import type {
2
+ ProviderStatus,
3
+ ProviderStatusRequest,
4
+ } from "@getpaseo/plugin/server/provider";
5
+ import {
6
+ assertRuntimeSupported,
7
+ discoverRuntime,
8
+ } from "./discovery/discover.js";
9
+ import { AdapterError } from "./errors.js";
10
+ import { logger } from "./logger.js";
11
+
12
+ export interface RuntimeStatusOptions {
13
+ readonly environment?: NodeJS.ProcessEnv;
14
+ readonly discover?: typeof discoverRuntime;
15
+ /** How long a result is reused. Paseo asks on every catalog load and agent start. */
16
+ readonly ttlMs?: number;
17
+ readonly now?: () => number;
18
+ }
19
+
20
+ // Same shape as Paseo's built-in provider diagnostics; the daemon appends the
21
+ // model count and snapshot status as further indented lines.
22
+ const format = (entries: readonly [string, string][]) =>
23
+ ["ZCode", ...entries.map(([label, value]) => ` ${label}: ${value}`)].join(
24
+ "\n",
25
+ );
26
+
27
+ async function check(
28
+ environment: NodeJS.ProcessEnv,
29
+ discover: typeof discoverRuntime,
30
+ ): Promise<ProviderStatus> {
31
+ try {
32
+ const runtime = await discover({ environment });
33
+ assertRuntimeSupported(runtime);
34
+ const { appVersion, cliVersion, nodeVersion, platform } = runtime.identity;
35
+ return {
36
+ available: true,
37
+ diagnostic: format([
38
+ [
39
+ "Runtime",
40
+ `${runtime.source === "managed" ? "managed" : "PASEO_ZCODE_RUNTIME"}, Server ${appVersion}, Agent ${cliVersion}`,
41
+ ],
42
+ ["Node.js", nodeVersion],
43
+ ["Platform", platform],
44
+ ]),
45
+ };
46
+ } catch (error) {
47
+ // Discovery errors carry fixed messages; anything else stays in the log.
48
+ if (!(error instanceof AdapterError))
49
+ logger.error("zcode.provider.status.failed", error);
50
+ return {
51
+ available: false,
52
+ diagnostic: format([
53
+ [
54
+ "Error",
55
+ error instanceof AdapterError
56
+ ? error.message
57
+ : "ZCode runtime could not be inspected",
58
+ ],
59
+ ]),
60
+ };
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Availability for Paseo's provider snapshot and diagnostics (Paseo 0.11+;
66
+ * older daemons ignore it). It inspects the runtime without starting a Server,
67
+ * so sign-in problems still surface when a session opens.
68
+ */
69
+ export function createRuntimeStatus(options: RuntimeStatusOptions = {}) {
70
+ const environment = options.environment ?? process.env;
71
+ const discover = options.discover ?? discoverRuntime;
72
+ const ttlMs = options.ttlMs ?? 30_000;
73
+ const now = options.now ?? Date.now;
74
+ let cached: { at: number; result: Promise<ProviderStatus> } | undefined;
75
+ return (_request?: ProviderStatusRequest): Promise<ProviderStatus> => {
76
+ if (cached && now() - cached.at < ttlMs) return cached.result;
77
+ const entry = { at: now(), result: check(environment, discover) };
78
+ cached = entry;
79
+ return entry.result;
80
+ };
81
+ }