@getpaseo/server 0.9.2 → 0.10.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 (148) hide show
  1. package/dist/scripts/supervisor.js +51 -21
  2. package/dist/server/server/agent/agent-manager.js +22 -2
  3. package/dist/server/server/agent/agent-prompt.js +12 -0
  4. package/dist/server/server/agent/agent-sdk-types.d.ts +3 -0
  5. package/dist/server/server/agent/mcp-shared.d.ts +5 -1
  6. package/dist/server/server/agent/mcp-shared.js +2 -1
  7. package/dist/server/server/agent/provider-launch-config.d.ts +2 -2
  8. package/dist/server/server/agent/provider-launch-config.js +1 -1
  9. package/dist/server/server/agent/provider-registry.js +2 -2
  10. package/dist/server/server/agent/providers/acp-agent.js +20 -11
  11. package/dist/server/server/agent/providers/claude/agent.d.ts +1 -2
  12. package/dist/server/server/agent/providers/claude/agent.js +10 -9
  13. package/dist/server/server/agent/providers/claude/models.d.ts +1 -1
  14. package/dist/server/server/agent/providers/claude/models.js +1 -5
  15. package/dist/server/server/agent/providers/claude/project-dir.d.ts +1 -0
  16. package/dist/server/server/agent/providers/claude/project-dir.js +5 -1
  17. package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +6 -1
  18. package/dist/server/server/agent/providers/codex-app-server-agent.js +10 -1
  19. package/dist/server/server/agent/providers/generic-acp-agent.js +3 -1
  20. package/dist/server/server/agent/providers/omp/agent.js +23 -6
  21. package/dist/server/server/agent/providers/omp/rpc-types.d.ts +1 -0
  22. package/dist/server/server/agent/providers/omp/rpc-types.js +1 -0
  23. package/dist/server/server/agent/providers/opencode/bridge.d.ts +5 -1
  24. package/dist/server/server/agent/providers/opencode/bridge.js +56 -5
  25. package/dist/server/server/agent/providers/opencode/http-error.d.ts +8 -0
  26. package/dist/server/server/agent/providers/opencode/http-error.js +13 -0
  27. package/dist/server/server/agent/providers/opencode/runtime-client.d.ts +38 -0
  28. package/dist/server/server/agent/providers/opencode/runtime-client.js +131 -0
  29. package/dist/server/server/agent/providers/opencode/runtime-notice.d.ts +3 -0
  30. package/dist/server/server/agent/providers/opencode/runtime-notice.js +47 -0
  31. package/dist/server/server/agent/providers/opencode/server-manager.js +19 -8
  32. package/dist/server/server/agent/providers/opencode/v2/agent.d.ts +36 -0
  33. package/dist/server/server/agent/providers/opencode/v2/agent.js +211 -0
  34. package/dist/server/server/agent/providers/opencode/v2/api.d.ts +18 -0
  35. package/dist/server/server/agent/providers/opencode/v2/api.js +2 -0
  36. package/dist/server/server/agent/providers/opencode/v2/bridge-plugin.bundle.mjs +6693 -0
  37. package/dist/server/server/agent/providers/opencode/v2/capabilities.d.ts +3 -0
  38. package/dist/server/server/agent/providers/opencode/v2/capabilities.js +13 -0
  39. package/dist/server/server/agent/providers/opencode/v2/children.d.ts +20 -0
  40. package/dist/server/server/agent/providers/opencode/v2/children.js +75 -0
  41. package/dist/server/server/agent/providers/opencode/v2/commands.d.ts +4 -0
  42. package/dist/server/server/agent/providers/opencode/v2/commands.js +36 -0
  43. package/dist/server/server/agent/providers/opencode/v2/configuration.d.ts +8 -0
  44. package/dist/server/server/agent/providers/opencode/v2/configuration.js +64 -0
  45. package/dist/server/server/agent/providers/opencode/v2/history.d.ts +4 -0
  46. package/dist/server/server/agent/providers/opencode/v2/history.js +15 -0
  47. package/dist/server/server/agent/providers/opencode/v2/mapping.d.ts +7 -0
  48. package/dist/server/server/agent/providers/opencode/v2/mapping.js +42 -0
  49. package/dist/server/server/agent/providers/opencode/v2/permissions.d.ts +18 -0
  50. package/dist/server/server/agent/providers/opencode/v2/permissions.js +157 -0
  51. package/dist/server/server/agent/providers/opencode/v2/readiness.d.ts +18 -0
  52. package/dist/server/server/agent/providers/opencode/v2/readiness.js +51 -0
  53. package/dist/server/server/agent/providers/opencode/v2/runtime.d.ts +36 -0
  54. package/dist/server/server/agent/providers/opencode/v2/runtime.js +230 -0
  55. package/dist/server/server/agent/providers/opencode/v2/session.d.ts +84 -0
  56. package/dist/server/server/agent/providers/opencode/v2/session.js +468 -0
  57. package/dist/server/server/agent/providers/opencode/v2/structured-output.d.ts +8 -0
  58. package/dist/server/server/agent/providers/opencode/v2/structured-output.js +32 -0
  59. package/dist/server/server/agent/providers/opencode/v2/timeline.d.ts +28 -0
  60. package/dist/server/server/agent/providers/opencode/v2/timeline.js +154 -0
  61. package/dist/server/server/agent/providers/opencode/v2/turns.d.ts +40 -0
  62. package/dist/server/server/agent/providers/opencode/v2/turns.js +226 -0
  63. package/dist/server/server/agent/providers/opencode-agent.d.ts +26 -7
  64. package/dist/server/server/agent/providers/opencode-agent.js +100 -40
  65. package/dist/server/server/agent/providers/pi/agent.d.ts +6 -6
  66. package/dist/server/server/agent/providers/pi/agent.js +114 -165
  67. package/dist/server/server/agent/providers/pi/extensions/child-session.d.ts +4 -0
  68. package/dist/server/server/agent/providers/pi/extensions/child-session.js +59 -0
  69. package/dist/server/server/agent/providers/pi/extensions/contract.d.ts +68 -0
  70. package/dist/server/server/agent/providers/pi/extensions/contract.js +2 -0
  71. package/dist/server/server/agent/providers/pi/extensions/gotgenes-pi-subagents/index.d.ts +3 -0
  72. package/dist/server/server/agent/providers/pi/extensions/gotgenes-pi-subagents/index.js +159 -0
  73. package/dist/server/server/agent/providers/pi/extensions/host.d.ts +28 -0
  74. package/dist/server/server/agent/providers/pi/extensions/host.js +94 -0
  75. package/dist/server/server/agent/providers/pi/extensions/index.d.ts +7 -0
  76. package/dist/server/server/agent/providers/pi/extensions/index.js +6 -0
  77. package/dist/server/server/agent/providers/pi/extensions/pi-ask-user/index.d.ts +3 -0
  78. package/dist/server/server/agent/providers/pi/extensions/pi-ask-user/index.js +138 -0
  79. package/dist/server/server/agent/providers/pi/extensions/pi-example-todo/index.d.ts +3 -0
  80. package/dist/server/server/agent/providers/pi/extensions/pi-example-todo/index.js +38 -0
  81. package/dist/server/server/agent/providers/pi/extensions/pi-goal-x/index.d.ts +3 -0
  82. package/dist/server/server/agent/providers/pi/extensions/pi-goal-x/index.js +63 -0
  83. package/dist/server/server/agent/providers/pi/extensions/pi-mcp-adapter/index.d.ts +3 -0
  84. package/dist/server/server/agent/providers/pi/extensions/pi-mcp-adapter/index.js +48 -0
  85. package/dist/server/server/agent/providers/pi/extensions/pi-subagents/index.d.ts +3 -0
  86. package/dist/server/server/agent/providers/pi/extensions/pi-subagents/index.js +131 -0
  87. package/dist/server/server/agent/providers/pi/extensions/registry.d.ts +2 -0
  88. package/dist/server/server/agent/providers/pi/extensions/registry.js +21 -0
  89. package/dist/server/server/agent/providers/pi/extensions/rpiv-ask-user-question/index.d.ts +3 -0
  90. package/dist/server/server/agent/providers/pi/extensions/rpiv-ask-user-question/index.js +180 -0
  91. package/dist/server/server/agent/providers/pi/extensions/rpiv-todo/index.d.ts +3 -0
  92. package/dist/server/server/agent/providers/pi/extensions/rpiv-todo/index.js +51 -0
  93. package/dist/server/server/agent/providers/pi/extensions/subagent-fixture-test.d.ts +22 -0
  94. package/dist/server/server/agent/providers/pi/extensions/subagent-fixture-test.js +66 -0
  95. package/dist/server/server/agent/providers/pi/extensions/task-fixture-test.d.ts +4 -0
  96. package/dist/server/server/agent/providers/pi/extensions/task-fixture-test.js +79 -0
  97. package/dist/server/server/agent/providers/pi/extensions/tintinweb-pi-subagents/index.d.ts +3 -0
  98. package/dist/server/server/agent/providers/pi/extensions/tintinweb-pi-subagents/index.js +149 -0
  99. package/dist/server/server/agent/providers/pi/history-mapper.d.ts +7 -2
  100. package/dist/server/server/agent/providers/pi/history-mapper.js +78 -35
  101. package/dist/server/server/agent/providers/pi/rpc-types.d.ts +3 -0
  102. package/dist/server/server/agent/providers/pi/test-utils/fake-pi.d.ts +170 -0
  103. package/dist/server/server/agent/providers/pi/test-utils/fake-pi.js +355 -0
  104. package/dist/server/server/agent/providers/pi/tool-call-mapper.d.ts +1 -6
  105. package/dist/server/server/agent/providers/pi/tool-call-mapper.js +1 -97
  106. package/dist/server/server/agent/tools/paseo-tools.js +22 -15
  107. package/dist/server/server/auth.d.ts +1 -2
  108. package/dist/server/server/auth.js +8 -14
  109. package/dist/server/server/bootstrap.js +10 -2
  110. package/dist/server/server/daemon-instance.d.ts +1 -0
  111. package/dist/server/server/daemon-instance.js +1 -0
  112. package/dist/server/server/exports.d.ts +1 -1
  113. package/dist/server/server/exports.js +1 -1
  114. package/dist/server/server/local-credential.d.ts +6 -0
  115. package/dist/server/server/local-credential.js +82 -0
  116. package/dist/server/server/session-admission-auth.d.ts +16 -0
  117. package/dist/server/server/session-admission-auth.js +26 -0
  118. package/dist/server/server/websocket-server.d.ts +6 -1
  119. package/dist/server/server/websocket-server.js +132 -55
  120. package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-bridge-f41bce08c3c4ac2de0652d20234d19e9.js → desktop-attachment-bridge-9da07adb97f5e0eb726f7762afee43f5.js} +1 -1
  121. package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-bridge-f41bce08c3c4ac2de0652d20234d19e9.js.br → desktop-attachment-bridge-9da07adb97f5e0eb726f7762afee43f5.js.br} +0 -0
  122. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-9da07adb97f5e0eb726f7762afee43f5.js.gz +0 -0
  123. package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-store-9e271e161480b0d1dd35e58616a37341.js → desktop-attachment-store-d5d3402a752965d3037191484127123b.js} +1 -1
  124. package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-store-9e271e161480b0d1dd35e58616a37341.js.br → desktop-attachment-store-d5d3402a752965d3037191484127123b.js.br} +0 -0
  125. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-d5d3402a752965d3037191484127123b.js.gz +0 -0
  126. package/dist/server/web-ui/_expo/static/js/web/{index-8868523fc6d311c5da524c067d1cd426.js → index-136fa41d4adb7ec5c6392839cc354136.js} +1580 -1576
  127. package/dist/server/web-ui/_expo/static/js/web/index-136fa41d4adb7ec5c6392839cc354136.js.br +0 -0
  128. package/dist/server/web-ui/_expo/static/js/web/index-136fa41d4adb7ec5c6392839cc354136.js.gz +0 -0
  129. package/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-369cdb67f5856fd2c72d640df0b7b79e.js → indexeddb-attachment-store-3afc19e43c8152bd3c6d71b3ea8776dc.js} +1 -1
  130. package/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-369cdb67f5856fd2c72d640df0b7b79e.js.br → indexeddb-attachment-store-3afc19e43c8152bd3c6d71b3ea8776dc.js.br} +0 -0
  131. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-3afc19e43c8152bd3c6d71b3ea8776dc.js.gz +0 -0
  132. package/dist/server/web-ui/_expo/static/js/web/{native-file-attachment-store-bcd89f6ce714279a8f4fa0e024f3a610.js → native-file-attachment-store-187a9d5c32188f357dbbf037a0f89073.js} +3 -3
  133. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-187a9d5c32188f357dbbf037a0f89073.js.br +0 -0
  134. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-187a9d5c32188f357dbbf037a0f89073.js.gz +0 -0
  135. package/dist/server/web-ui/index.html +1 -1
  136. package/dist/server/web-ui/index.html.br +0 -0
  137. package/dist/server/web-ui/index.html.gz +0 -0
  138. package/dist/src/server/agent/provider-launch-config.js +1 -1
  139. package/dist/src/server/daemon-instance.js +1 -0
  140. package/dist/src/server/local-credential.js +82 -0
  141. package/package.json +8 -7
  142. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-f41bce08c3c4ac2de0652d20234d19e9.js.gz +0 -0
  143. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-9e271e161480b0d1dd35e58616a37341.js.gz +0 -0
  144. package/dist/server/web-ui/_expo/static/js/web/index-8868523fc6d311c5da524c067d1cd426.js.br +0 -0
  145. package/dist/server/web-ui/_expo/static/js/web/index-8868523fc6d311c5da524c067d1cd426.js.gz +0 -0
  146. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-369cdb67f5856fd2c72d640df0b7b79e.js.gz +0 -0
  147. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-bcd89f6ce714279a8f4fa0e024f3a610.js.br +0 -0
  148. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-bcd89f6ce714279a8f4fa0e024f3a610.js.gz +0 -0
@@ -0,0 +1,159 @@
1
+ import { z } from "zod";
2
+ import { extractTextFromToolResult } from "../../tool-call-mapper.js";
3
+ const SpawnArgs = z
4
+ .object({
5
+ subagent_type: z.string().trim().min(1),
6
+ prompt: z.string().trim().min(1),
7
+ description: z.string().optional(),
8
+ })
9
+ .passthrough();
10
+ const FollowupArgs = z.object({ agent_id: z.string().trim().min(1) }).passthrough();
11
+ const Details = z
12
+ .object({
13
+ agentId: z.string().trim().min(1),
14
+ status: z.string(),
15
+ displayName: z.string().optional(),
16
+ description: z.string().optional(),
17
+ transcriptPath: z.string().trim().min(1).optional(),
18
+ })
19
+ .passthrough();
20
+ const Notification = z
21
+ .object({
22
+ id: z.string().trim().min(1),
23
+ status: z.string(),
24
+ description: z.string().optional(),
25
+ outputFile: z.string().trim().min(1).optional(),
26
+ })
27
+ .passthrough();
28
+ const status = (value) => {
29
+ if (value === "completed")
30
+ return "completed";
31
+ if (value === "error")
32
+ return "failed";
33
+ if (value === "aborted" || value === "stopped")
34
+ return "canceled";
35
+ return "running";
36
+ };
37
+ export const gotgenesPiSubagents = {
38
+ id: "@gotgenes/pi-subagents",
39
+ createSession: () => {
40
+ const callsByAgent = new Map();
41
+ const readSessions = new Set();
42
+ const mapSpawn = (call) => {
43
+ const args = SpawnArgs.safeParse(call.args);
44
+ if (!args.success)
45
+ return undefined;
46
+ const details = Details.safeParse(typeof call.result === "object" ? call.result?.details : null);
47
+ const title = args.data.subagent_type;
48
+ const description = args.data.description ?? args.data.prompt;
49
+ const detail = {
50
+ type: "sub_agent",
51
+ subAgentType: title,
52
+ description,
53
+ log: extractTextFromToolResult(call.result)?.trim() ?? "",
54
+ };
55
+ if (call.status === "running")
56
+ return {
57
+ detail,
58
+ subagents: [
59
+ {
60
+ type: "upsert",
61
+ id: call.callId,
62
+ title,
63
+ description,
64
+ toolCallId: call.callId,
65
+ status: "running",
66
+ },
67
+ ],
68
+ };
69
+ if (!details.success)
70
+ return call.status === "failed"
71
+ ? {
72
+ detail,
73
+ subagents: [{ type: "upsert", id: call.callId, status: "failed" }],
74
+ }
75
+ : { detail };
76
+ callsByAgent.set(details.data.agentId, call.callId);
77
+ return {
78
+ detail,
79
+ subagents: [
80
+ {
81
+ type: "upsert",
82
+ id: call.callId,
83
+ title,
84
+ description,
85
+ toolCallId: call.callId,
86
+ status: status(details.data.status),
87
+ },
88
+ ],
89
+ };
90
+ };
91
+ const mapFollowup = (call) => {
92
+ const args = FollowupArgs.safeParse(call.args);
93
+ if (!args.success)
94
+ return undefined;
95
+ const id = callsByAgent.get(args.data.agent_id);
96
+ if (!id)
97
+ return undefined;
98
+ const details = Details.safeParse(typeof call.result === "object" ? call.result?.details : null);
99
+ const detail = {
100
+ type: "sub_agent",
101
+ description: details.success ? details.data.description : undefined,
102
+ log: extractTextFromToolResult(call.result)?.trim() ?? "",
103
+ };
104
+ if (call.status === "running" || !details.success)
105
+ return { detail };
106
+ const file = details.data.transcriptPath;
107
+ const childSessions = file && status(details.data.status) !== "running" && !readSessions.has(file)
108
+ ? [{ id, file }]
109
+ : [];
110
+ if (childSessions.length && file)
111
+ readSessions.add(file);
112
+ return {
113
+ detail,
114
+ subagents: [{ type: "upsert", id, status: status(details.data.status) }],
115
+ childSessions,
116
+ };
117
+ };
118
+ return {
119
+ mapToolCall(call) {
120
+ // This fork's result details resemble tintinweb's, but its spawn tool is `subagent` and its
121
+ // follow-up result shape differs. Keep each parser at its own package boundary.
122
+ if (call.toolName === "subagent")
123
+ return mapSpawn(call);
124
+ if (call.toolName === "get_subagent_result" || call.toolName === "steer_subagent")
125
+ return mapFollowup(call);
126
+ return undefined;
127
+ },
128
+ mapCustomMessage(message) {
129
+ if (message.customType !== "subagent-notification" &&
130
+ message.customType !== "subagent-update")
131
+ return undefined;
132
+ const details = Notification.safeParse(message.details);
133
+ if (!details.success)
134
+ return undefined;
135
+ const id = callsByAgent.get(details.data.id);
136
+ if (!id)
137
+ return undefined;
138
+ const file = details.data.outputFile;
139
+ const childSessions = file && status(details.data.status) !== "running" && !readSessions.has(file)
140
+ ? [{ id, file }]
141
+ : [];
142
+ if (childSessions.length && file)
143
+ readSessions.add(file);
144
+ return {
145
+ subagents: [
146
+ {
147
+ type: "upsert",
148
+ id,
149
+ description: details.data.description,
150
+ status: status(details.data.status),
151
+ },
152
+ ],
153
+ childSessions,
154
+ };
155
+ },
156
+ };
157
+ },
158
+ };
159
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,28 @@
1
+ import type { Logger } from "pino";
2
+ import type { AgentPermissionRequest, AgentPermissionResponse, AgentStreamEvent } from "../../../agent-sdk-types.js";
3
+ import type { PiAgentMessage } from "../rpc-types.js";
4
+ import { mapPiChildSession } from "./child-session.js";
5
+ import type { PiExtension, PiExtensionCustomMapping, PiExtensionDialog, PiExtensionDialogMapping, PiExtensionToolCall, PiExtensionToolMapping, PiExtensionUiReply } from "./contract.js";
6
+ export type PiExtensionOutput<T> = T & {
7
+ events: AgentStreamEvent[];
8
+ hydration: Promise<AgentStreamEvent[]>;
9
+ };
10
+ export type PiExtensionEventOutput = PiExtensionOutput<PiExtensionToolMapping | PiExtensionCustomMapping>;
11
+ export declare class PiExtensionHost {
12
+ private readonly logger?;
13
+ private readonly readChildSession;
14
+ private readonly sessions;
15
+ private remainingHydrationBytes;
16
+ constructor(extensions: readonly PiExtension[], logger?: Pick<Logger, "warn"> | undefined, hydrationByteBudget?: number, readChildSession?: typeof mapPiChildSession);
17
+ private safe;
18
+ mapToolCall(call: PiExtensionToolCall): PiExtensionOutput<PiExtensionToolMapping> | undefined;
19
+ mapCustomMessage(message: Extract<PiAgentMessage, {
20
+ role: "custom";
21
+ }>): PiExtensionOutput<PiExtensionCustomMapping> | undefined;
22
+ private prepare;
23
+ onToolStart(call: PiExtensionToolCall, provider?: string): AgentPermissionRequest | undefined;
24
+ onToolEnd(call: PiExtensionToolCall): void;
25
+ mapDialog(dialog: PiExtensionDialog, provider: string): PiExtensionDialogMapping | undefined;
26
+ respondToPermission(request: AgentPermissionRequest, response: AgentPermissionResponse): PiExtensionUiReply | undefined;
27
+ }
28
+ //# sourceMappingURL=host.d.ts.map
@@ -0,0 +1,94 @@
1
+ import { mapPiChildSession } from "./child-session.js";
2
+ export class PiExtensionHost {
3
+ constructor(extensions, logger, hydrationByteBudget = Number.POSITIVE_INFINITY, readChildSession = mapPiChildSession) {
4
+ this.logger = logger;
5
+ this.readChildSession = readChildSession;
6
+ this.sessions = [];
7
+ this.remainingHydrationBytes = hydrationByteBudget;
8
+ for (const extension of extensions) {
9
+ const adapter = this.safe(extension.id, "createSession", () => extension.createSession());
10
+ if (adapter)
11
+ this.sessions.push({ id: extension.id, adapter });
12
+ }
13
+ }
14
+ safe(id, operation, call) {
15
+ try {
16
+ return call();
17
+ }
18
+ catch (error) {
19
+ this.logger?.warn({ err: error, extensionId: id, operation }, "Pi extension adapter failed");
20
+ return undefined;
21
+ }
22
+ }
23
+ mapToolCall(call) {
24
+ for (const { id, adapter } of this.sessions) {
25
+ const mapping = this.safe(id, "mapToolCall", () => adapter.mapToolCall?.(call));
26
+ if (mapping) {
27
+ const prepared = this.safe(id, "prepare", () => this.prepare(id, mapping));
28
+ if (prepared)
29
+ return prepared;
30
+ }
31
+ }
32
+ return undefined;
33
+ }
34
+ mapCustomMessage(message) {
35
+ for (const { id, adapter } of this.sessions) {
36
+ const mapping = this.safe(id, "mapCustomMessage", () => adapter.mapCustomMessage?.(message));
37
+ if (mapping) {
38
+ const prepared = this.safe(id, "prepare", () => this.prepare(id, mapping));
39
+ if (prepared)
40
+ return prepared;
41
+ }
42
+ }
43
+ return undefined;
44
+ }
45
+ prepare(id, mapping) {
46
+ const events = [
47
+ ...("timeline" in mapping ? (mapping.timeline ?? []) : []).map((item) => ({ type: "timeline", provider: "pi", item })),
48
+ ...(mapping.subagents ?? []).map((event) => ({ type: "provider_subagent", provider: "pi", event })),
49
+ ];
50
+ const hydration = Promise.all((mapping.childSessions ?? []).map(async ({ id: childId, file }) => {
51
+ const bytes = Math.min(this.remainingHydrationBytes, 2 * 1024 * 1024);
52
+ if (bytes <= 0)
53
+ return [];
54
+ this.remainingHydrationBytes -= bytes;
55
+ return (await this.readChildSession(childId, file, bytes)).map((event) => ({ type: "provider_subagent", provider: "pi", event }));
56
+ }))
57
+ .then((groups) => groups.flat())
58
+ .catch((error) => {
59
+ this.logger?.warn({ err: error, extensionId: id, operation: "hydrate" }, "Pi extension adapter failed");
60
+ return [];
61
+ });
62
+ return { ...mapping, events, hydration };
63
+ }
64
+ onToolStart(call, provider = "pi") {
65
+ let request;
66
+ for (const { id, adapter } of this.sessions) {
67
+ const candidate = this.safe(id, "onToolStart", () => adapter.onToolStart?.(call, provider));
68
+ request ?? (request = candidate);
69
+ }
70
+ return request;
71
+ }
72
+ onToolEnd(call) {
73
+ for (const { id, adapter } of this.sessions) {
74
+ this.safe(id, "onToolEnd", () => adapter.onToolEnd?.(call));
75
+ }
76
+ }
77
+ mapDialog(dialog, provider) {
78
+ for (const { id, adapter } of this.sessions) {
79
+ const mapping = this.safe(id, "mapDialog", () => adapter.mapDialog?.(dialog, provider));
80
+ if (mapping)
81
+ return mapping;
82
+ }
83
+ return undefined;
84
+ }
85
+ respondToPermission(request, response) {
86
+ for (const { id, adapter } of this.sessions) {
87
+ const mapped = this.safe(id, "respondToPermission", () => adapter.respondToPermission?.(request, response));
88
+ if (mapped)
89
+ return mapped;
90
+ }
91
+ return undefined;
92
+ }
93
+ }
94
+ //# sourceMappingURL=host.js.map
@@ -0,0 +1,7 @@
1
+ import { PiExtensionHost } from "./host.js";
2
+ import type { Logger } from "pino";
3
+ import type { PiExtension } from "./contract.js";
4
+ export type { PiExtensionHost } from "./host.js";
5
+ export type { PiExtensionEventOutput } from "./host.js";
6
+ export declare function createPiExtensionHost(logger?: Pick<Logger, "warn">, extensions?: readonly PiExtension[], hydrationByteBudget?: number): PiExtensionHost;
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,6 @@
1
+ import { PiExtensionHost } from "./host.js";
2
+ import { piExtensions } from "./registry.js";
3
+ export function createPiExtensionHost(logger, extensions = piExtensions, hydrationByteBudget) {
4
+ return new PiExtensionHost(extensions, logger, hydrationByteBudget);
5
+ }
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,3 @@
1
+ import type { PiExtension } from "../contract.js";
2
+ export declare const piAskUser: PiExtension;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,138 @@
1
+ import { z } from "zod";
2
+ const QUESTION_RESPONSE_HEADER = "Response";
3
+ const QUESTION_COMMENT_HEADER = "Comment";
4
+ const FREEFORM_SENTINEL = "✏️ Type custom response...";
5
+ const COMBINED_METADATA = "ask_user_select_optional_comment";
6
+ const Args = z
7
+ .object({
8
+ allowComment: z.boolean().catch(false),
9
+ allowFreeform: z.boolean().catch(true),
10
+ allowMultiple: z.boolean().catch(false),
11
+ })
12
+ .passthrough();
13
+ const Select = z
14
+ .object({ title: z.string().optional(), options: z.array(z.string()).optional() })
15
+ .passthrough();
16
+ const Input = z.object({ placeholder: z.string().optional() }).passthrough();
17
+ function answer(input, header) {
18
+ const answers = input?.answers;
19
+ if (!answers || typeof answers !== "object" || Array.isArray(answers))
20
+ return null;
21
+ const value = Reflect.get(answers, header);
22
+ return typeof value === "string" ? value : null;
23
+ }
24
+ function optionalInput(placeholder) {
25
+ return /\boptional\b|\bskip\b/i.test(placeholder ?? "");
26
+ }
27
+ function combinedPermission(dialog, provider, options, allowFreeform, question) {
28
+ const visibleOptions = options.filter((option) => option !== FREEFORM_SENTINEL);
29
+ const allowOther = allowFreeform || visibleOptions.length !== options.length;
30
+ return {
31
+ id: dialog.id,
32
+ provider,
33
+ name: "Pi ask_user",
34
+ kind: "question",
35
+ title: question,
36
+ input: {
37
+ questions: [
38
+ {
39
+ question,
40
+ header: QUESTION_RESPONSE_HEADER,
41
+ options: visibleOptions.map((label) => ({ label })),
42
+ multiSelect: false,
43
+ ...(allowOther ? { allowOther: true } : {}),
44
+ },
45
+ {
46
+ question: "Optional comment",
47
+ header: QUESTION_COMMENT_HEADER,
48
+ options: [],
49
+ multiSelect: false,
50
+ placeholder: "Optional comment (press Enter to skip)...",
51
+ allowEmpty: true,
52
+ },
53
+ ],
54
+ },
55
+ metadata: {
56
+ extensionUiMethod: dialog.method,
57
+ answerHeader: QUESTION_RESPONSE_HEADER,
58
+ commentHeader: QUESTION_COMMENT_HEADER,
59
+ combinedAskUser: COMBINED_METADATA,
60
+ selectOptions: visibleOptions,
61
+ ...(allowOther ? { freeformSentinel: FREEFORM_SENTINEL } : {}),
62
+ },
63
+ };
64
+ }
65
+ export const piAskUser = {
66
+ id: "pi-ask-user",
67
+ createSession() {
68
+ let active = null;
69
+ let pending = null;
70
+ return {
71
+ onToolStart(call) {
72
+ active = call.toolName === "ask_user" ? (Args.safeParse(call.args).data ?? null) : null;
73
+ return undefined;
74
+ },
75
+ onToolEnd(call) {
76
+ if (call.toolName === "ask_user") {
77
+ active = null;
78
+ pending = null;
79
+ }
80
+ },
81
+ mapDialog(dialog, provider) {
82
+ if (pending && dialog.method === "input") {
83
+ const input = Input.safeParse(dialog);
84
+ const placeholder = input.success ? input.data.placeholder : undefined;
85
+ if (pending.freeform !== null && !optionalInput(placeholder)) {
86
+ const value = pending.freeform;
87
+ pending = { ...pending, freeform: null };
88
+ return { type: "response", response: { value } };
89
+ }
90
+ if (optionalInput(placeholder)) {
91
+ const value = pending.comment;
92
+ pending = null;
93
+ return { type: "response", response: { value } };
94
+ }
95
+ }
96
+ if (dialog.method !== "select" || !active?.allowComment || active.allowMultiple)
97
+ return undefined;
98
+ const select = Select.safeParse(dialog);
99
+ const options = select.success ? (select.data.options ?? []) : [];
100
+ const question = select.success
101
+ ? (select.data.title ?? "Select an option")
102
+ : "Select an option";
103
+ return {
104
+ type: "permission",
105
+ request: combinedPermission(dialog, provider, options, active.allowFreeform, question),
106
+ };
107
+ },
108
+ respondToPermission(request, response) {
109
+ if (request.metadata?.combinedAskUser !== COMBINED_METADATA)
110
+ return undefined;
111
+ if (response.behavior === "deny") {
112
+ pending = null;
113
+ return { responses: [{ id: request.id, response: { cancelled: true } }] };
114
+ }
115
+ const selected = answer(response.updatedInput, QUESTION_RESPONSE_HEADER);
116
+ if (selected === null) {
117
+ pending = null;
118
+ return { responses: [{ id: request.id, response: { cancelled: true } }] };
119
+ }
120
+ const selectOptions = Array.isArray(request.metadata?.selectOptions)
121
+ ? request.metadata.selectOptions.filter((item) => typeof item === "string")
122
+ : [];
123
+ const sentinel = typeof request.metadata?.freeformSentinel === "string"
124
+ ? request.metadata.freeformSentinel
125
+ : undefined;
126
+ const isFreeform = Boolean(sentinel) && !selectOptions.includes(selected);
127
+ pending = {
128
+ comment: answer(response.updatedInput, QUESTION_COMMENT_HEADER) ?? "",
129
+ freeform: isFreeform ? selected : null,
130
+ };
131
+ return {
132
+ responses: [{ id: request.id, response: { value: isFreeform ? sentinel : selected } }],
133
+ };
134
+ },
135
+ };
136
+ },
137
+ };
138
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,3 @@
1
+ import type { PiExtension } from "../contract.js";
2
+ export declare const piExampleTodo: PiExtension;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,38 @@
1
+ import { z } from "zod";
2
+ const Details = z.object({
3
+ action: z.enum(["list", "add", "toggle", "clear"]),
4
+ nextId: z.number().int(),
5
+ todos: z.array(z.object({ id: z.number().int(), text: z.string(), done: z.boolean() })),
6
+ error: z.string().optional(),
7
+ });
8
+ export const piExampleTodo = {
9
+ id: "pi-example-todo",
10
+ createSession: () => ({
11
+ mapToolCall(call) {
12
+ if (call.toolName !== "todo" ||
13
+ call.status !== "completed" ||
14
+ !call.result ||
15
+ typeof call.result === "string")
16
+ return undefined;
17
+ const parsed = Details.safeParse(call.result.details);
18
+ if (!parsed.success)
19
+ return undefined;
20
+ return {
21
+ timeline: parsed.data.error
22
+ ? []
23
+ : [
24
+ {
25
+ type: "todo",
26
+ items: parsed.data.todos.map((todo) => ({
27
+ id: String(todo.id),
28
+ text: todo.text,
29
+ status: todo.done ? "completed" : "pending",
30
+ completed: todo.done,
31
+ })),
32
+ },
33
+ ],
34
+ };
35
+ },
36
+ }),
37
+ };
38
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,3 @@
1
+ import type { PiExtension } from "../contract.js";
2
+ export declare const piGoalX: PiExtension;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,63 @@
1
+ import { z } from "zod";
2
+ const Task = z.lazy(() => z.object({
3
+ id: z.string(),
4
+ title: z.string(),
5
+ status: z.enum(["pending", "complete", "skipped"]),
6
+ subtasks: z.array(Task).optional(),
7
+ }));
8
+ const Details = z.object({
9
+ version: z.literal(3),
10
+ goal: z
11
+ .object({
12
+ currentTaskId: z.string().optional(),
13
+ taskList: z.object({ tasks: z.array(Task) }).optional(),
14
+ })
15
+ .nullable(),
16
+ });
17
+ const toolNames = new Set([
18
+ "create_goal",
19
+ "get_goal",
20
+ "update_goal",
21
+ "set_goal_tasks",
22
+ "update_goal_task",
23
+ ]);
24
+ function toItems(tasks, currentTaskId) {
25
+ return tasks.flatMap((task) => {
26
+ let status = "pending";
27
+ if (task.status !== "pending")
28
+ status = "completed";
29
+ else if (task.id === currentTaskId)
30
+ status = "in_progress";
31
+ return [
32
+ {
33
+ id: task.id,
34
+ text: task.title,
35
+ status,
36
+ completed: task.status !== "pending",
37
+ },
38
+ ...toItems(task.subtasks ?? [], currentTaskId),
39
+ ];
40
+ });
41
+ }
42
+ export const piGoalX = {
43
+ id: "pi-goal-x",
44
+ createSession: () => ({
45
+ mapToolCall(call) {
46
+ if (!toolNames.has(call.toolName) ||
47
+ call.status !== "completed" ||
48
+ !call.result ||
49
+ typeof call.result === "string")
50
+ return undefined;
51
+ const parsed = Details.safeParse(call.result.details);
52
+ if (!parsed.success)
53
+ return undefined;
54
+ const goal = parsed.data.goal;
55
+ if (!goal?.taskList)
56
+ return undefined;
57
+ return {
58
+ timeline: [{ type: "todo", items: toItems(goal.taskList.tasks, goal.currentTaskId) }],
59
+ };
60
+ },
61
+ }),
62
+ };
63
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,3 @@
1
+ import type { PiExtension } from "../contract.js";
2
+ export declare const piMcpAdapter: PiExtension;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,48 @@
1
+ import { z } from "zod";
2
+ const Args = z
3
+ .object({
4
+ tool: z.string().optional().catch(undefined),
5
+ server: z.string().optional().catch(undefined),
6
+ })
7
+ .passthrough();
8
+ const Details = z
9
+ .object({
10
+ server: z.string().optional().catch(undefined),
11
+ tool: z.string().optional().catch(undefined),
12
+ })
13
+ .passthrough();
14
+ const nonEmpty = (value) => value?.trim() || undefined;
15
+ export const piMcpAdapter = {
16
+ id: "pi-mcp-adapter",
17
+ createSession: () => ({
18
+ mapToolCall(call) {
19
+ if (call.toolName !== "mcp")
20
+ return undefined;
21
+ if (call.result && typeof call.result !== "string") {
22
+ const details = Details.safeParse(call.result.details);
23
+ if (details.success) {
24
+ const server = nonEmpty(details.data.server);
25
+ const tool = nonEmpty(details.data.tool);
26
+ if (server && tool)
27
+ return { name: `${server}.${tool}` };
28
+ }
29
+ }
30
+ const args = Args.safeParse(call.args);
31
+ if (!args.success)
32
+ return undefined;
33
+ const tool = nonEmpty(args.data.tool);
34
+ const server = nonEmpty(args.data.server);
35
+ if (tool && server)
36
+ return {
37
+ name: `${server}.${tool.startsWith(`${server}_`) ? tool.slice(server.length + 1) : tool}`,
38
+ };
39
+ if (tool) {
40
+ const [prefix, ...rest] = tool.split("_");
41
+ if (prefix && rest.length > 0)
42
+ return { name: `${prefix}.${rest.join("_")}` };
43
+ }
44
+ return undefined;
45
+ },
46
+ }),
47
+ };
48
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,3 @@
1
+ import type { PiExtension } from "../contract.js";
2
+ export declare const piSubagents: PiExtension;
3
+ //# sourceMappingURL=index.d.ts.map