@fungi.computer/truffle 0.1.1 → 0.2.1

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 (174) hide show
  1. package/README.md +282 -34
  2. package/dist/auth-cli.d.ts +10 -0
  3. package/dist/auth-cli.js +36 -14
  4. package/dist/fungi-account-command.d.ts +1 -1
  5. package/dist/fungi-account-command.js +6 -3
  6. package/dist/index.d.ts +10 -2
  7. package/dist/index.js +8 -2
  8. package/dist/internal/image-fit-metafile.json +106 -0
  9. package/dist/internal/local-image-fit-worker.mjs +960 -0
  10. package/dist/internal/private-workerd-sandbox-worker.mjs +11 -12
  11. package/dist/internal/sandbox-metafile.json +7 -7
  12. package/dist/local-archive-handoff.d.ts +12 -0
  13. package/dist/local-archive-handoff.js +21 -0
  14. package/dist/local-extensions.d.ts +58 -12
  15. package/dist/local-extensions.js +195 -55
  16. package/dist/local-image-fit.d.ts +30 -0
  17. package/dist/local-image-fit.js +105 -0
  18. package/dist/local-models.d.ts +4 -2
  19. package/dist/local-models.js +11 -6
  20. package/dist/local-session-archives.d.ts +8 -0
  21. package/dist/local-session-archives.js +152 -0
  22. package/dist/local-skill-source.d.ts +18 -3
  23. package/dist/local-skill-source.js +216 -140
  24. package/dist/log-event.d.ts +7 -0
  25. package/dist/log-event.js +8 -4
  26. package/dist/private-bounded-response.d.ts +2 -0
  27. package/dist/private-bounded-response.js +41 -0
  28. package/dist/private-file-credential-store.d.ts +28 -3
  29. package/dist/private-file-credential-store.js +57 -9
  30. package/dist/private-files-patch.d.ts +2 -1
  31. package/dist/private-files-patch.js +21 -3
  32. package/dist/private-fungi-account.d.ts +40 -23
  33. package/dist/private-fungi-account.js +201 -21
  34. package/dist/private-fungi-mcp-connection.d.ts +4 -0
  35. package/dist/private-fungi-mcp-connection.js +25 -6
  36. package/dist/private-fungi-mcp-selection-schema.d.ts +7 -0
  37. package/dist/private-fungi-mcp-selection-schema.js +15 -0
  38. package/dist/private-fungi-mcp-selection.d.ts +6 -6
  39. package/dist/private-fungi-mcp-selection.js +29 -16
  40. package/dist/private-fungi-model-api.js +4 -4
  41. package/dist/private-fungi-model-catalog.d.ts +10 -0
  42. package/dist/private-fungi-model-catalog.js +10 -2
  43. package/dist/private-fungi-model-provider.d.ts +1 -1
  44. package/dist/private-fungi-model-provider.js +6 -1
  45. package/dist/private-fungi-pending-logouts.d.ts +1 -1
  46. package/dist/private-fungi-pending-logouts.js +1 -2
  47. package/dist/private-fungi-service-logout.d.ts +44 -0
  48. package/dist/private-fungi-service-logout.js +59 -0
  49. package/dist/private-invocation-computer.d.ts +24 -3
  50. package/dist/private-invocation-computer.js +101 -62
  51. package/dist/private-invocation-files.d.ts +16 -1
  52. package/dist/private-invocation-files.js +154 -83
  53. package/dist/private-local-acp-stdio.js +3 -0
  54. package/dist/private-local-admission-gate.d.ts +14 -0
  55. package/dist/private-local-admission-gate.js +52 -0
  56. package/dist/private-local-agent-control.d.ts +101 -0
  57. package/dist/private-local-agent-control.js +30 -0
  58. package/dist/private-local-agent-default-model.d.ts +12 -0
  59. package/dist/private-local-agent-default-model.js +31 -0
  60. package/dist/private-local-auth-rpc.d.ts +67 -7
  61. package/dist/private-local-auth-rpc.js +140 -17
  62. package/dist/private-local-bwrap.d.ts +13 -0
  63. package/dist/private-local-bwrap.js +70 -0
  64. package/dist/private-local-client-version.d.ts +5 -0
  65. package/dist/private-local-client-version.js +43 -0
  66. package/dist/private-local-computer-attach.d.ts +3 -3
  67. package/dist/private-local-computer-attach.js +17 -3
  68. package/dist/private-local-computer-processes.d.ts +6 -3
  69. package/dist/private-local-computer-processes.js +55 -31
  70. package/dist/private-local-config-root.d.ts +21 -0
  71. package/dist/private-local-config-root.js +19 -0
  72. package/dist/private-local-containment.d.ts +51 -0
  73. package/dist/private-local-containment.js +161 -0
  74. package/dist/private-local-delegation.d.ts +10 -3
  75. package/dist/private-local-delegation.js +70 -15
  76. package/dist/private-local-effective-model.d.ts +9 -1
  77. package/dist/private-local-effective-model.js +3 -0
  78. package/dist/private-local-exec-environment.d.ts +16 -0
  79. package/dist/private-local-exec-environment.js +11 -0
  80. package/dist/private-local-linux-sandbox.d.ts +8 -0
  81. package/dist/private-local-linux-sandbox.js +67 -0
  82. package/dist/private-local-mail.d.ts +4 -2
  83. package/dist/private-local-mail.js +41 -33
  84. package/dist/private-local-mesh-enrollment.d.ts +34 -0
  85. package/dist/private-local-mesh-enrollment.js +188 -0
  86. package/dist/private-local-mesh-links.d.ts +21 -0
  87. package/dist/private-local-mesh-links.js +229 -0
  88. package/dist/private-local-mesh-record.d.ts +120 -0
  89. package/dist/private-local-mesh-record.js +55 -0
  90. package/dist/private-local-process-identity.d.ts +20 -0
  91. package/dist/private-local-process-identity.js +40 -0
  92. package/dist/private-local-runtime-host.d.ts +64 -13
  93. package/dist/private-local-runtime-host.js +361 -172
  94. package/dist/private-local-sandbox-policy.d.ts +21 -0
  95. package/dist/private-local-sandbox-policy.js +121 -0
  96. package/dist/private-local-sandbox.d.ts +37 -0
  97. package/dist/private-local-sandbox.js +114 -0
  98. package/dist/private-local-seatbelt.d.ts +24 -0
  99. package/dist/private-local-seatbelt.js +68 -0
  100. package/dist/private-local-service-contract.d.ts +91 -11
  101. package/dist/private-local-service-discovery.d.ts +129 -13
  102. package/dist/private-local-service-discovery.js +148 -47
  103. package/dist/private-local-service-lease.d.ts +16 -0
  104. package/dist/private-local-service-lease.js +105 -0
  105. package/dist/private-local-service-listener.d.ts +9 -2
  106. package/dist/private-local-service-listener.js +260 -64
  107. package/dist/private-local-service-log.d.ts +128 -0
  108. package/dist/private-local-service-log.js +321 -0
  109. package/dist/private-local-service-owner.d.ts +87 -1519
  110. package/dist/private-local-service-owner.js +1069 -71
  111. package/dist/private-local-service-process.js +3 -1
  112. package/dist/private-local-service-termination.d.ts +7 -0
  113. package/dist/private-local-service-termination.js +67 -0
  114. package/dist/private-local-service.d.ts +31 -2
  115. package/dist/private-local-service.js +402 -126
  116. package/dist/private-local-session-discovery.d.ts +52 -5
  117. package/dist/private-local-session-discovery.js +132 -11
  118. package/dist/private-local-shiitake-host.js +2 -2
  119. package/dist/private-local-startup-model.d.ts +51 -0
  120. package/dist/private-local-startup-model.js +86 -0
  121. package/dist/private-local-stop-all.d.ts +27 -0
  122. package/dist/private-local-stop-all.js +26 -0
  123. package/dist/private-local-ui-attachment.d.ts +19 -0
  124. package/dist/private-local-ui-attachment.js +71 -0
  125. package/dist/private-local-worker-server.d.ts +1 -0
  126. package/dist/private-local-worker-server.js +13 -5
  127. package/dist/private-mcp-form-contract.d.ts +186 -0
  128. package/dist/private-mcp-form-contract.js +53 -0
  129. package/dist/private-mcp-form-elicitation.d.ts +18 -0
  130. package/dist/private-mcp-form-elicitation.js +97 -0
  131. package/dist/private-mcp-form-session.d.ts +172 -0
  132. package/dist/private-mcp-form-session.js +148 -0
  133. package/dist/private-openai-claims.d.ts +30 -0
  134. package/dist/private-openai-claims.js +69 -0
  135. package/dist/private-oyster-mcp-auth.d.ts +13 -0
  136. package/dist/private-oyster-mcp-auth.js +57 -0
  137. package/dist/private-provider-rejection.d.ts +15 -0
  138. package/dist/private-provider-rejection.js +24 -0
  139. package/dist/private-sqlite-owner.d.ts +34 -2
  140. package/dist/private-sqlite-owner.js +103 -37
  141. package/dist/private-team-computers.d.ts +4 -4
  142. package/dist/private-team-computers.js +11 -2
  143. package/dist/seatbelt/safe-base.sbpl +79 -0
  144. package/dist/subscription-activation.d.ts +9 -0
  145. package/dist/subscription-activation.js +62 -0
  146. package/dist/subscription-identity.d.ts +23 -0
  147. package/dist/subscription-identity.js +124 -0
  148. package/dist/subscription-turn.d.ts +17 -0
  149. package/dist/subscription-turn.js +143 -0
  150. package/dist/team-apps.d.ts +2 -2
  151. package/dist/team-apps.js +7 -2
  152. package/native/bin/LICENSE.bubblewrap +502 -0
  153. package/native/bin/LICENSE.libcap +112 -0
  154. package/native/bin/LICENSE.sandbox-runtime +201 -0
  155. package/native/bin/SOURCE.bubblewrap.tar.xz +0 -0
  156. package/native/bin/bwrap-build-source/Dockerfile +48 -0
  157. package/native/bin/bwrap-build-source/README.md +96 -0
  158. package/native/bin/bwrap-build-source/build.mjs +52 -0
  159. package/native/bin/bwrap-build-source/linux-arm64.ini +14 -0
  160. package/native/bin/bwrap-build-source/pin.mjs +21 -0
  161. package/native/bin/bwrap-build-source/record.mjs +74 -0
  162. package/native/bin/bwrap-build-source/vendor/LICENSE.sandbox-runtime +201 -0
  163. package/native/bin/bwrap-build-source/vendor/README.md +23 -0
  164. package/native/bin/bwrap-build-source/vendor/seccomp-unix-block.c +280 -0
  165. package/native/bin/bwrap-build.json +44 -0
  166. package/native/bin/fungi-bwrap +0 -0
  167. package/native/bin/fungi-bwrap.sha256 +1 -0
  168. package/native/bin/fungi-seccomp.bpf +0 -0
  169. package/native/bin/fungi-seccomp.bpf.sha256 +1 -0
  170. package/package.json +44 -31
  171. package/dist/private-local-model-settings.d.ts +0 -5
  172. package/dist/private-local-model-settings.js +0 -31
  173. package/dist/private-local-subagents.d.ts +0 -27
  174. package/dist/private-local-subagents.js +0 -77
@@ -0,0 +1,186 @@
1
+ import * as Schema from "effect/Schema";
2
+ /** The actual MCP form, not a ledger record or an authorization decision. */
3
+ export declare const McpFormApprovalRequestSchema: Schema.Struct<{
4
+ readonly message: Schema.String;
5
+ readonly requestedSchema: Schema.Struct<{
6
+ readonly type: Schema.Literal<"object">;
7
+ readonly properties: Schema.Struct<{
8
+ readonly approve: Schema.Struct<{
9
+ readonly type: Schema.Literal<"boolean">;
10
+ readonly title: Schema.optionalKey<Schema.String>;
11
+ }>;
12
+ }>;
13
+ readonly required: Schema.Tuple<readonly [Schema.Literal<"approve">]>;
14
+ }>;
15
+ }>;
16
+ export type McpFormApprovalRequest = typeof McpFormApprovalRequestSchema.Type;
17
+ /** Human dispositions of one live protocol request. */
18
+ export type McpFormApprovalDecision = "approve" | "decline" | "cancel";
19
+ declare const answerResult: Schema.Union<readonly [Schema.Struct<{
20
+ readonly kind: Schema.Literal<"answered">;
21
+ readonly view: Schema.Struct<{
22
+ readonly record: Schema.Struct<{
23
+ readonly recordId: Schema.String;
24
+ readonly requester: Schema.Struct<{
25
+ readonly principalId: Schema.String;
26
+ readonly agentId: Schema.NullOr<Schema.String>;
27
+ readonly sessionId: Schema.NullOr<Schema.String>;
28
+ readonly displayName: Schema.String;
29
+ }>;
30
+ readonly module: Schema.String;
31
+ readonly operation: Schema.String;
32
+ readonly access: Schema.Literals<readonly ["write", "external"]>;
33
+ readonly description: Schema.Struct<{
34
+ readonly title: Schema.String;
35
+ readonly inputBytes: Schema.Int;
36
+ readonly inputSha256: Schema.String;
37
+ }>;
38
+ readonly evidence: Schema.optionalKey<Schema.$Array<Schema.Struct<{
39
+ readonly kind: Schema.Literal<"artifact">;
40
+ readonly ref: Schema.String;
41
+ readonly mediaType: Schema.Literal<"image/png">;
42
+ readonly bytes: Schema.Int;
43
+ }>>>;
44
+ readonly authorityFence: Schema.String;
45
+ readonly reversibility: Schema.Literals<readonly ["reversible", "irreversible-external"]>;
46
+ readonly state: Schema.Literals<readonly ["requested", "pending", "approved", "claimed", "applied", "denied", "expired", "outcome_unknown"]>;
47
+ readonly by: Schema.NullOr<Schema.Union<readonly [Schema.Struct<{
48
+ readonly kind: Schema.Literal<"human">;
49
+ readonly memberId: Schema.String;
50
+ }>, Schema.Struct<{
51
+ readonly kind: Schema.Literal<"policy">;
52
+ }>]>>;
53
+ readonly reason: Schema.NullOr<Schema.Literals<readonly ["not-found", "not-eligible", "already-answered", "stale-revision", "expired", "declined", "fenced", "not-granted", "read-only", "pending", "in-flight", "outcome-unknown", "identity-conflict"]>>;
54
+ readonly requestedAt: Schema.Int;
55
+ readonly expiresAt: Schema.Int;
56
+ readonly updatedAt: Schema.Int;
57
+ readonly revision: Schema.Int;
58
+ }>;
59
+ readonly canAnswer: Schema.Boolean;
60
+ readonly canSetAutoApprove: Schema.Boolean;
61
+ }>;
62
+ }>, Schema.Struct<{
63
+ readonly kind: Schema.Literal<"refused">;
64
+ readonly reason: Schema.Literals<readonly ["not-found", "not-eligible", "already-answered", "stale-revision", "expired", "declined", "fenced", "not-granted", "read-only", "pending", "in-flight", "outcome-unknown", "identity-conflict"]>;
65
+ }>, Schema.Struct<{
66
+ readonly kind: Schema.Literal<"submitted">;
67
+ }>, Schema.Struct<{
68
+ readonly kind: Schema.Literal<"refused">;
69
+ readonly reason: Schema.Literals<readonly ["not-attached", "not-pending"]>;
70
+ }>]>;
71
+ export type McpFormAnswerResult = typeof answerResult.Type;
72
+ /** The existing Session extension slot carries only display-safe form data. */
73
+ export declare const mcpFormApprovalContract: {
74
+ id: string & import("effect/Brand").Brand<"ExtensionId">;
75
+ commands: {
76
+ answer: {
77
+ scope: "session";
78
+ input: Schema.Struct<{
79
+ readonly id: Schema.String;
80
+ readonly decision: Schema.Literals<readonly ["approve", "deny"]>;
81
+ readonly expectedRevision: Schema.Int;
82
+ }>;
83
+ output: Schema.Union<readonly [Schema.Struct<{
84
+ readonly kind: Schema.Literal<"answered">;
85
+ readonly view: Schema.Struct<{
86
+ readonly record: Schema.Struct<{
87
+ readonly recordId: Schema.String;
88
+ readonly requester: Schema.Struct<{
89
+ readonly principalId: Schema.String;
90
+ readonly agentId: Schema.NullOr<Schema.String>;
91
+ readonly sessionId: Schema.NullOr<Schema.String>;
92
+ readonly displayName: Schema.String;
93
+ }>;
94
+ readonly module: Schema.String;
95
+ readonly operation: Schema.String;
96
+ readonly access: Schema.Literals<readonly ["write", "external"]>;
97
+ readonly description: Schema.Struct<{
98
+ readonly title: Schema.String;
99
+ readonly inputBytes: Schema.Int;
100
+ readonly inputSha256: Schema.String;
101
+ }>;
102
+ readonly evidence: Schema.optionalKey<Schema.$Array<Schema.Struct<{
103
+ readonly kind: Schema.Literal<"artifact">;
104
+ readonly ref: Schema.String;
105
+ readonly mediaType: Schema.Literal<"image/png">;
106
+ readonly bytes: Schema.Int;
107
+ }>>>;
108
+ readonly authorityFence: Schema.String;
109
+ readonly reversibility: Schema.Literals<readonly ["reversible", "irreversible-external"]>;
110
+ readonly state: Schema.Literals<readonly ["requested", "pending", "approved", "claimed", "applied", "denied", "expired", "outcome_unknown"]>;
111
+ readonly by: Schema.NullOr<Schema.Union<readonly [Schema.Struct<{
112
+ readonly kind: Schema.Literal<"human">;
113
+ readonly memberId: Schema.String;
114
+ }>, Schema.Struct<{
115
+ readonly kind: Schema.Literal<"policy">;
116
+ }>]>>;
117
+ readonly reason: Schema.NullOr<Schema.Literals<readonly ["not-found", "not-eligible", "already-answered", "stale-revision", "expired", "declined", "fenced", "not-granted", "read-only", "pending", "in-flight", "outcome-unknown", "identity-conflict"]>>;
118
+ readonly requestedAt: Schema.Int;
119
+ readonly expiresAt: Schema.Int;
120
+ readonly updatedAt: Schema.Int;
121
+ readonly revision: Schema.Int;
122
+ }>;
123
+ readonly canAnswer: Schema.Boolean;
124
+ readonly canSetAutoApprove: Schema.Boolean;
125
+ }>;
126
+ }>, Schema.Struct<{
127
+ readonly kind: Schema.Literal<"refused">;
128
+ readonly reason: Schema.Literals<readonly ["not-found", "not-eligible", "already-answered", "stale-revision", "expired", "declined", "fenced", "not-granted", "read-only", "pending", "in-flight", "outcome-unknown", "identity-conflict"]>;
129
+ }>, Schema.Struct<{
130
+ readonly kind: Schema.Literal<"submitted">;
131
+ }>, Schema.Struct<{
132
+ readonly kind: Schema.Literal<"refused">;
133
+ readonly reason: Schema.Literals<readonly ["not-attached", "not-pending"]>;
134
+ }>]>;
135
+ };
136
+ };
137
+ projection: {
138
+ schema: Schema.Struct<{
139
+ readonly pending: Schema.$Array<Schema.Struct<{
140
+ readonly id: Schema.String;
141
+ readonly approval: Schema.Struct<{
142
+ readonly record: Schema.Struct<{
143
+ readonly recordId: Schema.String;
144
+ readonly requester: Schema.Struct<{
145
+ readonly principalId: Schema.String;
146
+ readonly agentId: Schema.NullOr<Schema.String>;
147
+ readonly sessionId: Schema.NullOr<Schema.String>;
148
+ readonly displayName: Schema.String;
149
+ }>;
150
+ readonly module: Schema.String;
151
+ readonly operation: Schema.String;
152
+ readonly access: Schema.Literals<readonly ["write", "external"]>;
153
+ readonly description: Schema.Struct<{
154
+ readonly title: Schema.String;
155
+ readonly inputBytes: Schema.Int;
156
+ readonly inputSha256: Schema.String;
157
+ }>;
158
+ readonly evidence: Schema.optionalKey<Schema.$Array<Schema.Struct<{
159
+ readonly kind: Schema.Literal<"artifact">;
160
+ readonly ref: Schema.String;
161
+ readonly mediaType: Schema.Literal<"image/png">;
162
+ readonly bytes: Schema.Int;
163
+ }>>>;
164
+ readonly authorityFence: Schema.String;
165
+ readonly reversibility: Schema.Literals<readonly ["reversible", "irreversible-external"]>;
166
+ readonly state: Schema.Literals<readonly ["requested", "pending", "approved", "claimed", "applied", "denied", "expired", "outcome_unknown"]>;
167
+ readonly by: Schema.NullOr<Schema.Union<readonly [Schema.Struct<{
168
+ readonly kind: Schema.Literal<"human">;
169
+ readonly memberId: Schema.String;
170
+ }>, Schema.Struct<{
171
+ readonly kind: Schema.Literal<"policy">;
172
+ }>]>>;
173
+ readonly reason: Schema.NullOr<Schema.Literals<readonly ["not-found", "not-eligible", "already-answered", "stale-revision", "expired", "declined", "fenced", "not-granted", "read-only", "pending", "in-flight", "outcome-unknown", "identity-conflict"]>>;
174
+ readonly requestedAt: Schema.Int;
175
+ readonly expiresAt: Schema.Int;
176
+ readonly updatedAt: Schema.Int;
177
+ readonly revision: Schema.Int;
178
+ }>;
179
+ readonly canAnswer: Schema.Boolean;
180
+ readonly canSetAutoApprove: Schema.Boolean;
181
+ }>;
182
+ }>>;
183
+ }>;
184
+ };
185
+ };
186
+ export {};
@@ -0,0 +1,53 @@
1
+ import { ExtensionId, } from "@fungi.computer/shiitake/extensions";
2
+ import * as Schema from "effect/Schema";
3
+ import { ApprovalAnswerInputSchema, ApprovalRefusalSchema, ApprovalViewSchema, } from "@fungi.computer/approvals";
4
+ /** The actual MCP form, not a ledger record or an authorization decision. */
5
+ export const McpFormApprovalRequestSchema = Schema.Struct({
6
+ message: Schema.String,
7
+ requestedSchema: Schema.Struct({
8
+ type: Schema.Literal("object"),
9
+ properties: Schema.Struct({
10
+ approve: Schema.Struct({
11
+ type: Schema.Literal("boolean"),
12
+ title: Schema.optionalKey(Schema.String),
13
+ }),
14
+ }),
15
+ required: Schema.Tuple([Schema.Literal("approve")]),
16
+ }),
17
+ });
18
+ const answerResult = Schema.Union([
19
+ Schema.Struct({
20
+ kind: Schema.Literal("answered"),
21
+ view: ApprovalViewSchema,
22
+ }),
23
+ ApprovalRefusalSchema,
24
+ // The attached client awaits the private host's post-commit decision.
25
+ Schema.Struct({ kind: Schema.Literal("submitted") }),
26
+ Schema.Struct({
27
+ kind: Schema.Literal("refused"),
28
+ reason: Schema.Literals(["not-attached", "not-pending"]),
29
+ }),
30
+ ]);
31
+ /** The ephemeral id references the canonical record; it grants no authority. */
32
+ const McpFormPendingSchema = Schema.Struct({
33
+ id: Schema.String,
34
+ approval: ApprovalViewSchema,
35
+ });
36
+ /** The existing Session extension slot carries only display-safe form data. */
37
+ export const mcpFormApprovalContract = {
38
+ id: ExtensionId.make("botanical-local-mcp-form"),
39
+ commands: {
40
+ answer: {
41
+ scope: "session",
42
+ input: Schema.Struct({
43
+ id: Schema.String,
44
+ decision: ApprovalAnswerInputSchema.fields.decision,
45
+ expectedRevision: ApprovalAnswerInputSchema.fields.expectedRevision,
46
+ }),
47
+ output: answerResult,
48
+ },
49
+ },
50
+ projection: {
51
+ schema: Schema.Struct({ pending: Schema.Array(McpFormPendingSchema) }),
52
+ },
53
+ };
@@ -0,0 +1,18 @@
1
+ import type { Client } from "@modelcontextprotocol/client";
2
+ import { type McpFormApprovalRequest, type McpFormApprovalDecision } from "./private-mcp-form-contract.js";
3
+ /** Host-owned human interaction. No callback means immediate cancellation. */
4
+ export type RequestMcpFormApproval = (pending: McpFormApprovalRequest, signal: AbortSignal,
5
+ /** Session captured by source acquisition, never supplied by tool arguments. */
6
+ sessionId: string | undefined) => Promise<McpFormApprovalDecision>;
7
+ /** A refused form is a failed tool call, not an uncertain transport outcome. */
8
+ export declare class McpFormApprovalError extends Error {
9
+ readonly reason: "declined" | "cancelled";
10
+ readonly kind = "mcp_approval_refused";
11
+ constructor(reason: "declined" | "cancelled");
12
+ }
13
+ /** Discriminant carried in a failed MCP tool result's structuredContent. */
14
+ export type McpFormApprovalRefusal = Readonly<Pick<McpFormApprovalError, "kind" | "reason">>;
15
+ export declare function registerMcpFormElicitation(client: Client, requestApproval: RequestMcpFormApproval | undefined, sessionId: string | undefined): {
16
+ close: () => void;
17
+ run: <T>(signal: AbortSignal, invoke: (signal: AbortSignal) => Promise<T>) => Promise<T>;
18
+ };
@@ -0,0 +1,97 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ import { addAbortListener } from "node:events";
3
+ import * as Schema from "effect/Schema";
4
+ import { McpFormApprovalRequestSchema, } from "./private-mcp-form-contract.js";
5
+ const decodePendingForm = Schema.decodeUnknownSync(McpFormApprovalRequestSchema);
6
+ /** A refused form is a failed tool call, not an uncertain transport outcome. */
7
+ export class McpFormApprovalError extends Error {
8
+ reason;
9
+ kind = "mcp_approval_refused";
10
+ constructor(reason) {
11
+ super(`MCP approval was ${reason}.`);
12
+ this.reason = reason;
13
+ this.name = "McpFormApprovalError";
14
+ }
15
+ }
16
+ export function registerMcpFormElicitation(client, requestApproval, sessionId) {
17
+ // The producer sends its form on the requesting tools/call response stream.
18
+ // Keep that call's refusal local even when another call shares this client.
19
+ const calls = new AsyncLocalStorage();
20
+ const lifetime = new AbortController();
21
+ const close = () => {
22
+ lifetime.abort();
23
+ calls.disable();
24
+ };
25
+ client.onclose = close;
26
+ client.registerCapabilities({ elicitation: { form: {} } });
27
+ client.setRequestHandler("elicitation/create", async (request, context) => {
28
+ const call = calls.getStore();
29
+ if (call === undefined || call.failure !== undefined)
30
+ return { action: "cancel" };
31
+ const signal = AbortSignal.any([call.signal, context.mcpReq.signal]);
32
+ let abortListener;
33
+ call.pending++;
34
+ try {
35
+ signal.throwIfAborted();
36
+ const pending = decodePendingForm(request.params);
37
+ const aborted = new Promise((_resolve, reject) => {
38
+ abortListener = addAbortListener(signal, () => {
39
+ reject(new McpFormApprovalError("cancelled"));
40
+ });
41
+ });
42
+ const decision = await Promise.race([
43
+ requestApproval === undefined
44
+ ? Promise.resolve("cancel")
45
+ : Promise.resolve().then(() => requestApproval(pending, signal, sessionId)),
46
+ aborted,
47
+ ]);
48
+ // Cancellation wins over a late Approve, including a UI ignoring abort.
49
+ signal.throwIfAborted();
50
+ if (decision === "approve")
51
+ return { action: "accept", content: { approve: true } };
52
+ call.failure ??= new McpFormApprovalError(decision === "decline" ? "declined" : "cancelled");
53
+ call.cancel();
54
+ return { action: decision };
55
+ }
56
+ catch {
57
+ call.failure ??= new McpFormApprovalError("cancelled");
58
+ call.cancel();
59
+ return { action: "cancel" };
60
+ }
61
+ finally {
62
+ call.pending--;
63
+ abortListener?.[Symbol.dispose]();
64
+ }
65
+ });
66
+ return {
67
+ close,
68
+ run: (signal, invoke) => {
69
+ const settled = new AbortController();
70
+ const call = {
71
+ signal: AbortSignal.any([signal, lifetime.signal, settled.signal]),
72
+ cancel: () => {
73
+ settled.abort();
74
+ },
75
+ pending: 0,
76
+ };
77
+ return calls.run(call, async () => {
78
+ try {
79
+ const result = await invoke(call.signal);
80
+ if (call.failure !== undefined)
81
+ throw call.failure;
82
+ return result;
83
+ }
84
+ catch (cause) {
85
+ if (call.failure !== undefined)
86
+ throw call.failure;
87
+ if (call.pending > 0)
88
+ throw new McpFormApprovalError("cancelled");
89
+ throw cause;
90
+ }
91
+ finally {
92
+ settled.abort();
93
+ }
94
+ });
95
+ },
96
+ };
97
+ }
@@ -0,0 +1,172 @@
1
+ import type { Approvals, PendingApproval } from "@fungi.computer/approvals";
2
+ import type { ShiitakeSession } from "@fungi.computer/shiitake";
3
+ import { type LocalUiAttachment } from "./private-local-ui-attachment.js";
4
+ /** Host-owned references to canonical approvals; no suspended tool or second ledger. */
5
+ export declare function createMcpFormSession(): {
6
+ extension: import("@fungi.computer/shiitake/extensions").DefinedExtensionV0<{
7
+ answer: {
8
+ scope: "session";
9
+ input: import("effect/Schema").Struct<{
10
+ readonly id: import("effect/Schema").String;
11
+ readonly decision: import("effect/Schema").Literals<readonly ["approve", "deny"]>;
12
+ readonly expectedRevision: import("effect/Schema").Int;
13
+ }>;
14
+ output: import("effect/Schema").Union<readonly [import("effect/Schema").Struct<{
15
+ readonly kind: import("effect/Schema").Literal<"answered">;
16
+ readonly view: import("effect/Schema").Struct<{
17
+ readonly record: import("effect/Schema").Struct<{
18
+ readonly recordId: import("effect/Schema").String;
19
+ readonly requester: import("effect/Schema").Struct<{
20
+ readonly principalId: import("effect/Schema").String;
21
+ readonly agentId: import("effect/Schema").NullOr<import("effect/Schema").String>;
22
+ readonly sessionId: import("effect/Schema").NullOr<import("effect/Schema").String>;
23
+ readonly displayName: import("effect/Schema").String;
24
+ }>;
25
+ readonly module: import("effect/Schema").String;
26
+ readonly operation: import("effect/Schema").String;
27
+ readonly access: import("effect/Schema").Literals<readonly ["write", "external"]>;
28
+ readonly description: import("effect/Schema").Struct<{
29
+ readonly title: import("effect/Schema").String;
30
+ readonly inputBytes: import("effect/Schema").Int;
31
+ readonly inputSha256: import("effect/Schema").String;
32
+ }>;
33
+ readonly evidence: import("effect/Schema").optionalKey<import("effect/Schema").$Array<import("effect/Schema").Struct<{
34
+ readonly kind: import("effect/Schema").Literal<"artifact">;
35
+ readonly ref: import("effect/Schema").String;
36
+ readonly mediaType: import("effect/Schema").Literal<"image/png">;
37
+ readonly bytes: import("effect/Schema").Int;
38
+ }>>>;
39
+ readonly authorityFence: import("effect/Schema").String;
40
+ readonly reversibility: import("effect/Schema").Literals<readonly ["reversible", "irreversible-external"]>;
41
+ readonly state: import("effect/Schema").Literals<readonly ["requested", "pending", "approved", "claimed", "applied", "denied", "expired", "outcome_unknown"]>;
42
+ readonly by: import("effect/Schema").NullOr<import("effect/Schema").Union<readonly [import("effect/Schema").Struct<{
43
+ readonly kind: import("effect/Schema").Literal<"human">;
44
+ readonly memberId: import("effect/Schema").String;
45
+ }>, import("effect/Schema").Struct<{
46
+ readonly kind: import("effect/Schema").Literal<"policy">;
47
+ }>]>>;
48
+ readonly reason: import("effect/Schema").NullOr<import("effect/Schema").Literals<readonly ["not-found", "not-eligible", "already-answered", "stale-revision", "expired", "declined", "fenced", "not-granted", "read-only", "pending", "in-flight", "outcome-unknown", "identity-conflict"]>>;
49
+ readonly requestedAt: import("effect/Schema").Int;
50
+ readonly expiresAt: import("effect/Schema").Int;
51
+ readonly updatedAt: import("effect/Schema").Int;
52
+ readonly revision: import("effect/Schema").Int;
53
+ }>;
54
+ readonly canAnswer: import("effect/Schema").Boolean;
55
+ readonly canSetAutoApprove: import("effect/Schema").Boolean;
56
+ }>;
57
+ }>, import("effect/Schema").Struct<{
58
+ readonly kind: import("effect/Schema").Literal<"refused">;
59
+ readonly reason: import("effect/Schema").Literals<readonly ["not-found", "not-eligible", "already-answered", "stale-revision", "expired", "declined", "fenced", "not-granted", "read-only", "pending", "in-flight", "outcome-unknown", "identity-conflict"]>;
60
+ }>, import("effect/Schema").Struct<{
61
+ readonly kind: import("effect/Schema").Literal<"submitted">;
62
+ }>, import("effect/Schema").Struct<{
63
+ readonly kind: import("effect/Schema").Literal<"refused">;
64
+ readonly reason: import("effect/Schema").Literals<readonly ["not-attached", "not-pending"]>;
65
+ }>]>;
66
+ };
67
+ }, {
68
+ readonly pending: readonly {
69
+ readonly id: string;
70
+ readonly approval: {
71
+ readonly record: {
72
+ readonly operation: string;
73
+ readonly state: "pending" | "expired" | "requested" | "approved" | "claimed" | "applied" | "denied" | "outcome_unknown";
74
+ readonly access: "write" | "external";
75
+ readonly reason: "pending" | "not-found" | "not-eligible" | "already-answered" | "stale-revision" | "expired" | "declined" | "fenced" | "not-granted" | "read-only" | "in-flight" | "outcome-unknown" | "identity-conflict" | null;
76
+ readonly recordId: string;
77
+ readonly requester: {
78
+ readonly principalId: string;
79
+ readonly agentId: string | null;
80
+ readonly sessionId: string | null;
81
+ readonly displayName: string;
82
+ };
83
+ readonly module: string;
84
+ readonly description: {
85
+ readonly title: string;
86
+ readonly inputBytes: number;
87
+ readonly inputSha256: string;
88
+ };
89
+ readonly authorityFence: string;
90
+ readonly reversibility: "reversible" | "irreversible-external";
91
+ readonly by: {
92
+ readonly kind: "human";
93
+ readonly memberId: string;
94
+ } | {
95
+ readonly kind: "policy";
96
+ } | null;
97
+ readonly requestedAt: number;
98
+ readonly expiresAt: number;
99
+ readonly updatedAt: number;
100
+ readonly revision: number;
101
+ readonly evidence?: readonly {
102
+ readonly kind: "artifact";
103
+ readonly ref: string;
104
+ readonly mediaType: "image/png";
105
+ readonly bytes: number;
106
+ }[];
107
+ };
108
+ readonly canAnswer: boolean;
109
+ readonly canSetAutoApprove: boolean;
110
+ };
111
+ }[];
112
+ }, {
113
+ readonly pending: readonly {
114
+ readonly id: string;
115
+ readonly approval: {
116
+ readonly record: {
117
+ readonly operation: string;
118
+ readonly state: "pending" | "expired" | "requested" | "approved" | "claimed" | "applied" | "denied" | "outcome_unknown";
119
+ readonly access: "write" | "external";
120
+ readonly reason: "pending" | "not-found" | "not-eligible" | "already-answered" | "stale-revision" | "expired" | "declined" | "fenced" | "not-granted" | "read-only" | "in-flight" | "outcome-unknown" | "identity-conflict" | null;
121
+ readonly recordId: string;
122
+ readonly requester: {
123
+ readonly principalId: string;
124
+ readonly agentId: string | null;
125
+ readonly sessionId: string | null;
126
+ readonly displayName: string;
127
+ };
128
+ readonly module: string;
129
+ readonly description: {
130
+ readonly title: string;
131
+ readonly inputBytes: number;
132
+ readonly inputSha256: string;
133
+ };
134
+ readonly authorityFence: string;
135
+ readonly reversibility: "reversible" | "irreversible-external";
136
+ readonly by: {
137
+ readonly kind: "human";
138
+ readonly memberId: string;
139
+ } | {
140
+ readonly kind: "policy";
141
+ } | null;
142
+ readonly requestedAt: number;
143
+ readonly expiresAt: number;
144
+ readonly updatedAt: number;
145
+ readonly revision: number;
146
+ readonly evidence?: readonly {
147
+ readonly kind: "artifact";
148
+ readonly ref: string;
149
+ readonly mediaType: "image/png";
150
+ readonly bytes: number;
151
+ }[];
152
+ };
153
+ readonly canAnswer: boolean;
154
+ readonly canSetAutoApprove: boolean;
155
+ };
156
+ }[];
157
+ }>;
158
+ presentApproval: (sessionId: string, submitted: PendingApproval, approvals: Approvals) => Promise<{
159
+ readonly kind: "refused";
160
+ readonly reason: "not-pending";
161
+ readonly id?: never;
162
+ } | {
163
+ readonly kind: "presented";
164
+ readonly id: string;
165
+ reason?: never;
166
+ } | {
167
+ readonly kind: "refused";
168
+ readonly reason: "capacity";
169
+ readonly id?: never;
170
+ }>;
171
+ bindSession: (sessionId: string, session: ShiitakeSession, attachment: LocalUiAttachment | undefined) => ShiitakeSession;
172
+ };