toolhome 0.5.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 (214) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +295 -0
  3. package/README.zh.md +281 -0
  4. package/dist/server/app.d.ts +16 -0
  5. package/dist/server/app.d.ts.map +1 -0
  6. package/dist/server/app.js +166 -0
  7. package/dist/server/app.js.map +1 -0
  8. package/dist/server/cli/main.d.ts +3 -0
  9. package/dist/server/cli/main.d.ts.map +1 -0
  10. package/dist/server/cli/main.js +587 -0
  11. package/dist/server/cli/main.js.map +1 -0
  12. package/dist/server/cli-plane/allow-list.d.ts +18 -0
  13. package/dist/server/cli-plane/allow-list.d.ts.map +1 -0
  14. package/dist/server/cli-plane/allow-list.js +28 -0
  15. package/dist/server/cli-plane/allow-list.js.map +1 -0
  16. package/dist/server/cli-plane/cli-service.d.ts +41 -0
  17. package/dist/server/cli-plane/cli-service.d.ts.map +1 -0
  18. package/dist/server/cli-plane/cli-service.js +282 -0
  19. package/dist/server/cli-plane/cli-service.js.map +1 -0
  20. package/dist/server/cli-plane/frames.d.ts +26 -0
  21. package/dist/server/cli-plane/frames.d.ts.map +1 -0
  22. package/dist/server/cli-plane/frames.js +12 -0
  23. package/dist/server/cli-plane/frames.js.map +1 -0
  24. package/dist/server/cli-plane/models.d.ts +174 -0
  25. package/dist/server/cli-plane/models.d.ts.map +1 -0
  26. package/dist/server/cli-plane/models.js +169 -0
  27. package/dist/server/cli-plane/models.js.map +1 -0
  28. package/dist/server/cli-plane/routes.d.ts +32 -0
  29. package/dist/server/cli-plane/routes.d.ts.map +1 -0
  30. package/dist/server/cli-plane/routes.js +94 -0
  31. package/dist/server/cli-plane/routes.js.map +1 -0
  32. package/dist/server/cli-plane/runner.d.ts +41 -0
  33. package/dist/server/cli-plane/runner.d.ts.map +1 -0
  34. package/dist/server/cli-plane/runner.js +163 -0
  35. package/dist/server/cli-plane/runner.js.map +1 -0
  36. package/dist/server/cli-plane/status.d.ts +12 -0
  37. package/dist/server/cli-plane/status.d.ts.map +1 -0
  38. package/dist/server/cli-plane/status.js +24 -0
  39. package/dist/server/cli-plane/status.js.map +1 -0
  40. package/dist/server/config/harness-import.d.ts +44 -0
  41. package/dist/server/config/harness-import.d.ts.map +1 -0
  42. package/dist/server/config/harness-import.js +166 -0
  43. package/dist/server/config/harness-import.js.map +1 -0
  44. package/dist/server/config.d.ts +20 -0
  45. package/dist/server/config.d.ts.map +1 -0
  46. package/dist/server/config.js +80 -0
  47. package/dist/server/config.js.map +1 -0
  48. package/dist/server/control/client.d.ts +24 -0
  49. package/dist/server/control/client.d.ts.map +1 -0
  50. package/dist/server/control/client.js +115 -0
  51. package/dist/server/control/client.js.map +1 -0
  52. package/dist/server/control/control-api.d.ts +39 -0
  53. package/dist/server/control/control-api.d.ts.map +1 -0
  54. package/dist/server/control/control-api.js +291 -0
  55. package/dist/server/control/control-api.js.map +1 -0
  56. package/dist/server/control/control-service.d.ts +713 -0
  57. package/dist/server/control/control-service.d.ts.map +1 -0
  58. package/dist/server/control/control-service.js +693 -0
  59. package/dist/server/control/control-service.js.map +1 -0
  60. package/dist/server/control/openapi.d.ts +2 -0
  61. package/dist/server/control/openapi.d.ts.map +1 -0
  62. package/dist/server/control/openapi.js +370 -0
  63. package/dist/server/control/openapi.js.map +1 -0
  64. package/dist/server/data-plane/data-plane.d.ts +20 -0
  65. package/dist/server/data-plane/data-plane.d.ts.map +1 -0
  66. package/dist/server/data-plane/data-plane.js +335 -0
  67. package/dist/server/data-plane/data-plane.js.map +1 -0
  68. package/dist/server/data-plane/gateway-server.d.ts +13 -0
  69. package/dist/server/data-plane/gateway-server.d.ts.map +1 -0
  70. package/dist/server/data-plane/gateway-server.js +796 -0
  71. package/dist/server/data-plane/gateway-server.js.map +1 -0
  72. package/dist/server/data-plane/legacy-session.d.ts +18 -0
  73. package/dist/server/data-plane/legacy-session.d.ts.map +1 -0
  74. package/dist/server/data-plane/legacy-session.js +137 -0
  75. package/dist/server/data-plane/legacy-session.js.map +1 -0
  76. package/dist/server/data-plane/projection.d.ts +18 -0
  77. package/dist/server/data-plane/projection.d.ts.map +1 -0
  78. package/dist/server/data-plane/projection.js +44 -0
  79. package/dist/server/data-plane/projection.js.map +1 -0
  80. package/dist/server/data-plane/registry.d.ts +31 -0
  81. package/dist/server/data-plane/registry.d.ts.map +1 -0
  82. package/dist/server/data-plane/registry.js +129 -0
  83. package/dist/server/data-plane/registry.js.map +1 -0
  84. package/dist/server/data-plane/task-extension.d.ts +7 -0
  85. package/dist/server/data-plane/task-extension.d.ts.map +1 -0
  86. package/dist/server/data-plane/task-extension.js +33 -0
  87. package/dist/server/data-plane/task-extension.js.map +1 -0
  88. package/dist/server/data-plane/virtualization.d.ts +35 -0
  89. package/dist/server/data-plane/virtualization.d.ts.map +1 -0
  90. package/dist/server/data-plane/virtualization.js +228 -0
  91. package/dist/server/data-plane/virtualization.js.map +1 -0
  92. package/dist/server/domain/errors.d.ts +9 -0
  93. package/dist/server/domain/errors.d.ts.map +1 -0
  94. package/dist/server/domain/errors.js +19 -0
  95. package/dist/server/domain/errors.js.map +1 -0
  96. package/dist/server/domain/models.d.ts +720 -0
  97. package/dist/server/domain/models.d.ts.map +1 -0
  98. package/dist/server/domain/models.js +327 -0
  99. package/dist/server/domain/models.js.map +1 -0
  100. package/dist/server/main.d.ts +2 -0
  101. package/dist/server/main.d.ts.map +1 -0
  102. package/dist/server/main.js +37 -0
  103. package/dist/server/main.js.map +1 -0
  104. package/dist/server/manage/management-mcp.d.ts +27 -0
  105. package/dist/server/manage/management-mcp.d.ts.map +1 -0
  106. package/dist/server/manage/management-mcp.js +431 -0
  107. package/dist/server/manage/management-mcp.js.map +1 -0
  108. package/dist/server/market/catalog.d.ts +111 -0
  109. package/dist/server/market/catalog.d.ts.map +1 -0
  110. package/dist/server/market/catalog.js +784 -0
  111. package/dist/server/market/catalog.js.map +1 -0
  112. package/dist/server/market/installers.d.ts +64 -0
  113. package/dist/server/market/installers.d.ts.map +1 -0
  114. package/dist/server/market/installers.js +181 -0
  115. package/dist/server/market/installers.js.map +1 -0
  116. package/dist/server/market/market-service.d.ts +146 -0
  117. package/dist/server/market/market-service.d.ts.map +1 -0
  118. package/dist/server/market/market-service.js +930 -0
  119. package/dist/server/market/market-service.js.map +1 -0
  120. package/dist/server/observability/call-recorder.d.ts +22 -0
  121. package/dist/server/observability/call-recorder.d.ts.map +1 -0
  122. package/dist/server/observability/call-recorder.js +99 -0
  123. package/dist/server/observability/call-recorder.js.map +1 -0
  124. package/dist/server/observability/logger.d.ts +16 -0
  125. package/dist/server/observability/logger.d.ts.map +1 -0
  126. package/dist/server/observability/logger.js +25 -0
  127. package/dist/server/observability/logger.js.map +1 -0
  128. package/dist/server/security/api-keys.d.ts +15 -0
  129. package/dist/server/security/api-keys.d.ts.map +1 -0
  130. package/dist/server/security/api-keys.js +35 -0
  131. package/dist/server/security/api-keys.js.map +1 -0
  132. package/dist/server/security/auth-service.d.ts +26 -0
  133. package/dist/server/security/auth-service.d.ts.map +1 -0
  134. package/dist/server/security/auth-service.js +76 -0
  135. package/dist/server/security/auth-service.js.map +1 -0
  136. package/dist/server/security/control-session.d.ts +9 -0
  137. package/dist/server/security/control-session.d.ts.map +1 -0
  138. package/dist/server/security/control-session.js +51 -0
  139. package/dist/server/security/control-session.js.map +1 -0
  140. package/dist/server/security/credential-materializer.d.ts +20 -0
  141. package/dist/server/security/credential-materializer.d.ts.map +1 -0
  142. package/dist/server/security/credential-materializer.js +82 -0
  143. package/dist/server/security/credential-materializer.js.map +1 -0
  144. package/dist/server/security/cursor-codec.d.ts +13 -0
  145. package/dist/server/security/cursor-codec.d.ts.map +1 -0
  146. package/dist/server/security/cursor-codec.js +43 -0
  147. package/dist/server/security/cursor-codec.js.map +1 -0
  148. package/dist/server/security/oauth-routes.d.ts +21 -0
  149. package/dist/server/security/oauth-routes.d.ts.map +1 -0
  150. package/dist/server/security/oauth-routes.js +100 -0
  151. package/dist/server/security/oauth-routes.js.map +1 -0
  152. package/dist/server/security/oauth-server.d.ts +16 -0
  153. package/dist/server/security/oauth-server.d.ts.map +1 -0
  154. package/dist/server/security/oauth-server.js +544 -0
  155. package/dist/server/security/oauth-server.js.map +1 -0
  156. package/dist/server/security/secret-box.d.ts +7 -0
  157. package/dist/server/security/secret-box.d.ts.map +1 -0
  158. package/dist/server/security/secret-box.js +27 -0
  159. package/dist/server/security/secret-box.js.map +1 -0
  160. package/dist/server/security/secure-action.d.ts +21 -0
  161. package/dist/server/security/secure-action.d.ts.map +1 -0
  162. package/dist/server/security/secure-action.js +69 -0
  163. package/dist/server/security/secure-action.js.map +1 -0
  164. package/dist/server/storage/sqlite-store.d.ts +70 -0
  165. package/dist/server/storage/sqlite-store.d.ts.map +1 -0
  166. package/dist/server/storage/sqlite-store.js +1522 -0
  167. package/dist/server/storage/sqlite-store.js.map +1 -0
  168. package/dist/server/storage/store.d.ts +82 -0
  169. package/dist/server/storage/store.d.ts.map +1 -0
  170. package/dist/server/storage/store.js +2 -0
  171. package/dist/server/storage/store.js.map +1 -0
  172. package/dist/server/upstream/adapter.d.ts +52 -0
  173. package/dist/server/upstream/adapter.d.ts.map +1 -0
  174. package/dist/server/upstream/adapter.js +807 -0
  175. package/dist/server/upstream/adapter.js.map +1 -0
  176. package/dist/server/upstream/credential-resolver.d.ts +14 -0
  177. package/dist/server/upstream/credential-resolver.d.ts.map +1 -0
  178. package/dist/server/upstream/credential-resolver.js +56 -0
  179. package/dist/server/upstream/credential-resolver.js.map +1 -0
  180. package/dist/server/upstream/extension-transport.d.ts +17 -0
  181. package/dist/server/upstream/extension-transport.d.ts.map +1 -0
  182. package/dist/server/upstream/extension-transport.js +207 -0
  183. package/dist/server/upstream/extension-transport.js.map +1 -0
  184. package/dist/server/upstream/manager.d.ts +23 -0
  185. package/dist/server/upstream/manager.d.ts.map +1 -0
  186. package/dist/server/upstream/manager.js +324 -0
  187. package/dist/server/upstream/manager.js.map +1 -0
  188. package/dist/server/upstream/oauth-provider.d.ts +38 -0
  189. package/dist/server/upstream/oauth-provider.d.ts.map +1 -0
  190. package/dist/server/upstream/oauth-provider.js +225 -0
  191. package/dist/server/upstream/oauth-provider.js.map +1 -0
  192. package/dist/server/upstream/oauth-refresh.d.ts +65 -0
  193. package/dist/server/upstream/oauth-refresh.d.ts.map +1 -0
  194. package/dist/server/upstream/oauth-refresh.js +240 -0
  195. package/dist/server/upstream/oauth-refresh.js.map +1 -0
  196. package/dist/server/upstream/oauth-routes.d.ts +17 -0
  197. package/dist/server/upstream/oauth-routes.d.ts.map +1 -0
  198. package/dist/server/upstream/oauth-routes.js +87 -0
  199. package/dist/server/upstream/oauth-routes.js.map +1 -0
  200. package/dist/server/upstream/oauth-service.d.ts +143 -0
  201. package/dist/server/upstream/oauth-service.d.ts.map +1 -0
  202. package/dist/server/upstream/oauth-service.js +217 -0
  203. package/dist/server/upstream/oauth-service.js.map +1 -0
  204. package/dist/server/upstream/stable-json.d.ts +3 -0
  205. package/dist/server/upstream/stable-json.d.ts.map +1 -0
  206. package/dist/server/upstream/stable-json.js +17 -0
  207. package/dist/server/upstream/stable-json.js.map +1 -0
  208. package/package.json +69 -0
  209. package/skills/toolhome/SKILL.md +238 -0
  210. package/skills/toolhome/references/cli-reference.md +242 -0
  211. package/skills/toolhome/references/deployment.md +113 -0
  212. package/skills/toolhome/references/market-guide.md +128 -0
  213. package/skills/toolhome/references/oauth-guide.md +96 -0
  214. package/skills/toolhome/references/troubleshooting.md +133 -0
@@ -0,0 +1,169 @@
1
+ import { z } from 'zod';
2
+ import { slugSchema } from '../domain/models.js';
3
+ /**
4
+ * CLI plane record schemas (Form A of docs/cli-hosting-research.md).
5
+ *
6
+ * A CLI is a first-class entity: a command or container image plus a declarative
7
+ * allow-list, optional probe for status checks, and an optional Env Credential
8
+ * whose variables are injected into every execution.
9
+ */
10
+ /** One argv rule: token patterns, where `*` matches a single argv token. */
11
+ export const cliAllowRuleSchema = z.array(z.string().min(1)).min(1);
12
+ export const cliAllowListSchema = z.object({
13
+ allow: z.array(cliAllowRuleSchema).default([]),
14
+ deny: z.array(cliAllowRuleSchema).default([]),
15
+ });
16
+ export const cliProbeSchema = z.object({
17
+ command: z.string().min(1).max(1024),
18
+ args: z.array(z.string()).default([]),
19
+ });
20
+ const cliCredentialBindingsValueSchema = z.record(z.string().min(1), z.string().min(1));
21
+ export const cliCredentialBindingsSchema = cliCredentialBindingsValueSchema.default({});
22
+ const cliAuthStrategyValueSchema = z.enum([
23
+ 'none',
24
+ 'azure-service-principal',
25
+ 'tailscale-auth-key',
26
+ ]);
27
+ export const cliAuthStrategySchema = cliAuthStrategyValueSchema.default('none');
28
+ const namedVolumeSourceSchema = z
29
+ .string()
30
+ .min(1)
31
+ .max(128)
32
+ .regex(/^[A-Za-z0-9][A-Za-z0-9_.-]*$/, 'Only Docker named volumes are supported');
33
+ const containerVolumeSchema = z.object({
34
+ source: namedVolumeSourceSchema,
35
+ target: z
36
+ .string()
37
+ .min(1)
38
+ .max(512)
39
+ .refine((value) => value.startsWith('/') && !/[\0\r\n:]/.test(value), 'Container volume targets must be absolute paths without control characters or colons'),
40
+ readOnly: z.boolean().default(false),
41
+ });
42
+ export const cliRuntimeConfigSchema = z
43
+ .object({
44
+ executionMode: z.enum(['host', 'docker']),
45
+ authStrategy: cliAuthStrategySchema,
46
+ containerVolumes: z.array(containerVolumeSchema).max(16),
47
+ })
48
+ .superRefine((value, context) => {
49
+ if (value.executionMode === 'host' && value.authStrategy !== 'none') {
50
+ context.addIssue({
51
+ code: 'custom',
52
+ path: ['authStrategy'],
53
+ message: 'Authentication bootstrap requires Docker execution mode',
54
+ });
55
+ }
56
+ if (value.executionMode === 'host' && value.containerVolumes.length > 0) {
57
+ context.addIssue({
58
+ code: 'custom',
59
+ path: ['containerVolumes'],
60
+ message: 'Container volumes require Docker execution mode',
61
+ });
62
+ }
63
+ const targets = new Set();
64
+ for (const [index, volume] of value.containerVolumes.entries()) {
65
+ if (targets.has(volume.target)) {
66
+ context.addIssue({
67
+ code: 'custom',
68
+ path: ['containerVolumes', index, 'target'],
69
+ message: 'Container volume targets must be unique',
70
+ });
71
+ }
72
+ targets.add(volume.target);
73
+ }
74
+ });
75
+ export const createCliInputSchema = z
76
+ .object({
77
+ slug: slugSchema,
78
+ name: z.string().min(1).max(120),
79
+ command: z.string().min(1).max(1024),
80
+ executionMode: z.enum(['host', 'docker']).default('host'),
81
+ entrypoint: z.string().min(1).max(256).nullable().default(null),
82
+ authStrategy: cliAuthStrategySchema,
83
+ containerVolumes: z.array(containerVolumeSchema).default([]),
84
+ platform: z.string().min(1).max(120).nullable().default(null),
85
+ allowList: cliAllowListSchema.default({ allow: [], deny: [] }),
86
+ interactive: z.boolean().default(false),
87
+ credentialId: z.string().nullable().default(null),
88
+ credentialBindings: cliCredentialBindingsSchema,
89
+ probe: cliProbeSchema.nullable().default(null),
90
+ enabled: z.boolean().default(true),
91
+ timeoutMs: z.number().int().min(100).max(3_600_000).default(60_000),
92
+ maxOutputBytes: z
93
+ .number()
94
+ .int()
95
+ .min(1024)
96
+ .max(64 * 1024 * 1024)
97
+ .default(64 * 1024),
98
+ })
99
+ .superRefine((value, context) => {
100
+ const result = cliRuntimeConfigSchema.safeParse(value);
101
+ if (!result.success) {
102
+ for (const issue of result.error.issues) {
103
+ context.addIssue({
104
+ code: issue.code === 'custom' ? 'custom' : 'custom',
105
+ path: issue.path,
106
+ message: issue.message,
107
+ });
108
+ }
109
+ }
110
+ });
111
+ export const updateCliInputSchema = z.object({
112
+ name: z.string().min(1).max(120).optional(),
113
+ command: z.string().min(1).max(1024).optional(),
114
+ executionMode: z.enum(['host', 'docker']).optional(),
115
+ entrypoint: z.string().min(1).max(256).nullable().optional(),
116
+ authStrategy: cliAuthStrategyValueSchema.optional(),
117
+ containerVolumes: z.array(containerVolumeSchema).optional(),
118
+ platform: z.string().min(1).max(120).nullable().optional(),
119
+ allowList: cliAllowListSchema.optional(),
120
+ interactive: z.boolean().optional(),
121
+ credentialId: z.string().nullable().optional(),
122
+ credentialBindings: cliCredentialBindingsValueSchema.optional(),
123
+ probe: cliProbeSchema.nullable().optional(),
124
+ enabled: z.boolean().optional(),
125
+ timeoutMs: z.number().int().min(100).max(3_600_000).optional(),
126
+ maxOutputBytes: z
127
+ .number()
128
+ .int()
129
+ .min(1024)
130
+ .max(64 * 1024 * 1024)
131
+ .optional(),
132
+ });
133
+ export function assertCliRuntimeConfig(value) {
134
+ cliRuntimeConfigSchema.parse(value);
135
+ }
136
+ export const cliRecordSchema = z.object({
137
+ id: z.uuid(),
138
+ slug: slugSchema,
139
+ name: z.string(),
140
+ command: z.string(),
141
+ executionMode: z.enum(['host', 'docker']),
142
+ entrypoint: z.string().min(1).max(256).nullable(),
143
+ authStrategy: cliAuthStrategySchema,
144
+ containerVolumes: z.array(containerVolumeSchema),
145
+ platform: z.string().min(1).max(120).nullable(),
146
+ allowList: cliAllowListSchema,
147
+ interactive: z.boolean(),
148
+ credentialId: z.string().nullable(),
149
+ credentialBindings: cliCredentialBindingsSchema,
150
+ probe: cliProbeSchema.nullable(),
151
+ enabled: z.boolean(),
152
+ timeoutMs: z.number(),
153
+ maxOutputBytes: z.number(),
154
+ createdAt: z.iso.datetime(),
155
+ updatedAt: z.iso.datetime(),
156
+ });
157
+ /** Per-exec request body. `argv` is an array only — never a shell string. */
158
+ export const cliExecInputSchema = z.object({
159
+ argv: z.array(z.string()).min(1),
160
+ stdin: z.string().nullable().optional(),
161
+ timeoutMs: z.number().int().min(100).max(3_600_000).optional(),
162
+ maxOutputBytes: z
163
+ .number()
164
+ .int()
165
+ .min(1024)
166
+ .max(64 * 1024 * 1024)
167
+ .optional(),
168
+ });
169
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../../../src/cli-plane/models.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { Logger } from '../observability/logger.js';
2
+ import type { AuthService } from '../security/auth-service.js';
3
+ import type { CliService } from './cli-service.js';
4
+ interface HonoLike {
5
+ get(path: string, handler: (context: HonoContext) => Response | Promise<Response>): void;
6
+ post(path: string, handler: (context: HonoContext) => Response | Promise<Response>): void;
7
+ }
8
+ interface HonoContext {
9
+ req: {
10
+ raw: Request;
11
+ path: string;
12
+ param(name: string): string;
13
+ json(): Promise<unknown>;
14
+ };
15
+ }
16
+ /**
17
+ * Mount the CLI data-plane routes (docs/cli-hosting-research.md §2.2/§2.6):
18
+ *
19
+ * POST /cli/{slug}/exec NDJSON stream of stdout/stderr/exit frames
20
+ * GET /cli/{slug}/status { installed, version, loggedIn, lastCheckedAt }
21
+ *
22
+ * Both require an admin Control Key. All validation and the allow-list verdict
23
+ * happen before the response stream starts, so 400/403/404 errors are returned
24
+ * as JSON without spawning anything.
25
+ */
26
+ export declare function mountCliExecRoutes(app: HonoLike, options: {
27
+ service: CliService;
28
+ auth: AuthService;
29
+ logger: Logger;
30
+ }): void;
31
+ export {};
32
+ //# sourceMappingURL=routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/cli-plane/routes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnD,UAAU,QAAQ;IAChB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;IACzF,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;CAC3F;AAED,UAAU,WAAW;IACnB,GAAG,EAAE;QACH,GAAG,EAAE,OAAO,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;QAC5B,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;KAC1B,CAAC;CACH;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,QAAQ,EACb,OAAO,EAAE;IAAE,OAAO,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAClE,IAAI,CA0EN"}
@@ -0,0 +1,94 @@
1
+ import { AppError } from '../domain/errors.js';
2
+ import { errorResponse } from '../control/control-api.js';
3
+ import { cliNdjsonContentType, encodeFrame } from './frames.js';
4
+ /**
5
+ * Mount the CLI data-plane routes (docs/cli-hosting-research.md §2.2/§2.6):
6
+ *
7
+ * POST /cli/{slug}/exec NDJSON stream of stdout/stderr/exit frames
8
+ * GET /cli/{slug}/status { installed, version, loggedIn, lastCheckedAt }
9
+ *
10
+ * Both require an admin Control Key. All validation and the allow-list verdict
11
+ * happen before the response stream starts, so 400/403/404 errors are returned
12
+ * as JSON without spawning anything.
13
+ */
14
+ export function mountCliExecRoutes(app, options) {
15
+ const requireAdmin = (context) => {
16
+ const principal = options.auth.authenticateBearer('control', context.req.raw);
17
+ if (principal.scope !== 'admin') {
18
+ throw new AppError('forbidden', 'This operation requires an admin control key', 403);
19
+ }
20
+ };
21
+ app.post('/cli/:slug/exec', async (context) => {
22
+ try {
23
+ requireAdmin(context);
24
+ let body;
25
+ try {
26
+ body = await context.req.json();
27
+ }
28
+ catch {
29
+ throw new AppError('validation_error', 'Request body must be JSON', 400);
30
+ }
31
+ const prepared = options.service.prepareExec(context.req.param('slug'), body);
32
+ const abort = new AbortController();
33
+ const stream = new ReadableStream({
34
+ start(controller) {
35
+ void (async () => {
36
+ const emit = (frame) => {
37
+ try {
38
+ controller.enqueue(new TextEncoder().encode(encodeFrame(frame)));
39
+ }
40
+ catch {
41
+ // stream already closed by the client
42
+ }
43
+ };
44
+ try {
45
+ await options.service.runExec(prepared.record, prepared.input, emit, abort.signal);
46
+ }
47
+ catch (error) {
48
+ emit({
49
+ type: 'stderr',
50
+ data: error instanceof Error ? error.message : String(error),
51
+ });
52
+ emit({ type: 'exit', code: null, durationMs: 0, result: 'error' });
53
+ }
54
+ finally {
55
+ try {
56
+ controller.close();
57
+ }
58
+ catch {
59
+ // already closed
60
+ }
61
+ }
62
+ })();
63
+ },
64
+ cancel() {
65
+ abort.abort();
66
+ },
67
+ });
68
+ return new Response(stream, {
69
+ status: 200,
70
+ headers: {
71
+ 'content-type': cliNdjsonContentType,
72
+ 'cache-control': 'no-store',
73
+ },
74
+ });
75
+ }
76
+ catch (error) {
77
+ return errorResponse(error, options.logger);
78
+ }
79
+ });
80
+ app.get('/cli/:slug/status', async (context) => {
81
+ try {
82
+ requireAdmin(context);
83
+ const status = await options.service.status(context.req.param('slug'));
84
+ return new Response(JSON.stringify(status), {
85
+ status: 200,
86
+ headers: { 'content-type': 'application/json', 'cache-control': 'no-store' },
87
+ });
88
+ }
89
+ catch (error) {
90
+ return errorResponse(error, options.logger);
91
+ }
92
+ });
93
+ }
94
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/cli-plane/routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import type { CliExecFrame } from './frames.js';
2
+ export interface ExecRequest {
3
+ /** Host: binary path/name. Docker: container image reference. */
4
+ command: string;
5
+ /** argv passed verbatim to the binary — never through a shell. */
6
+ argv: string[];
7
+ /** Full environment for the child (base env + enforcement vars + credential vars). */
8
+ env: Record<string, string>;
9
+ stdin?: string | null;
10
+ timeoutMs: number;
11
+ maxOutputBytes: number;
12
+ executionMode: 'host' | 'docker';
13
+ /** Environment variable names explicitly forwarded into the container. */
14
+ containerEnvKeys?: string[];
15
+ /** Persistent or bind-mounted state directories explicitly forwarded into the container. */
16
+ containerVolumes?: {
17
+ source: string;
18
+ target: string;
19
+ readOnly?: boolean;
20
+ }[];
21
+ /** Fixed authentication bootstrap performed inside a hosted container. */
22
+ authStrategy?: 'none' | 'azure-service-principal' | 'tailscale-auth-key';
23
+ entrypoint?: string | null;
24
+ }
25
+ export interface ExecOutcome {
26
+ code: number | null;
27
+ durationMs: number;
28
+ result: 'ok' | 'error' | 'timeout';
29
+ truncated: boolean;
30
+ }
31
+ /**
32
+ * Run a CLI process and stream its output as NDJSON frames.
33
+ *
34
+ * The process is spawned directly (no shell); stdout and stderr are forwarded
35
+ * as separate frames. A still-running child is SIGTERM'd at `timeoutMs` and
36
+ * SIGKILL'd after a grace period. Output is memory-bounded: once
37
+ * `maxOutputBytes` have been forwarded, further chunks are dropped and the
38
+ * final exit frame carries `truncated: true`.
39
+ */
40
+ export declare function execCli(request: ExecRequest, emit: (frame: CliExecFrame) => void, signal?: AbortSignal): Promise<ExecOutcome>;
41
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/cli-plane/runner.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,WAAW;IAC1B,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,sFAAsF;IACtF,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,GAAG,QAAQ,CAAC;IACjC,0EAA0E;IAC1E,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,4FAA4F;IAC5F,gBAAgB,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;IAC5E,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,GAAG,yBAAyB,GAAG,oBAAoB,CAAC;IACzE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,IAAI,GAAG,OAAO,GAAG,SAAS,CAAC;IACnC,SAAS,EAAE,OAAO,CAAC;CACpB;AAID;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CACrB,OAAO,EAAE,WAAW,EACpB,IAAI,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,EACnC,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,WAAW,CAAC,CAsJtB"}
@@ -0,0 +1,163 @@
1
+ import { spawn } from 'node:child_process';
2
+ const killGraceMs = 1_000;
3
+ /**
4
+ * Run a CLI process and stream its output as NDJSON frames.
5
+ *
6
+ * The process is spawned directly (no shell); stdout and stderr are forwarded
7
+ * as separate frames. A still-running child is SIGTERM'd at `timeoutMs` and
8
+ * SIGKILL'd after a grace period. Output is memory-bounded: once
9
+ * `maxOutputBytes` have been forwarded, further chunks are dropped and the
10
+ * final exit frame carries `truncated: true`.
11
+ */
12
+ export function execCli(request, emit, signal) {
13
+ return new Promise((resolve) => {
14
+ const isDocker = request.executionMode === 'docker';
15
+ const spawnCommand = isDocker ? 'docker' : request.command;
16
+ const containerArgv = request.authStrategy === 'azure-service-principal'
17
+ ? [
18
+ '-c',
19
+ 'az login --service-principal --username "$AZURE_CLIENT_ID" --password "$AZURE_CLIENT_SECRET" --tenant "$AZURE_TENANT_ID" --output none && exec az "$@"',
20
+ '--',
21
+ ...request.argv,
22
+ ]
23
+ : request.authStrategy === 'tailscale-auth-key'
24
+ ? [
25
+ '-c',
26
+ 'mkdir -p /var/run/tailscale && tailscaled --tun=userspace-networking --statedir=/var/lib/tailscale --socket=/var/run/tailscale/tailscaled.sock >/tmp/tailscaled.log 2>&1 & daemon=$!; attempt=0; while [ "$attempt" -lt 50 ] && [ ! -S /var/run/tailscale/tailscaled.sock ]; do attempt=$((attempt + 1)); sleep 0.1; done; tailscale --socket=/var/run/tailscale/tailscaled.sock up --auth-key="$TS_AUTHKEY" --reset >/dev/null 2>&1 && exec tailscale --socket=/var/run/tailscale/tailscaled.sock "$@"; status=$?; kill "$daemon" >/dev/null 2>&1 || true; wait "$daemon" >/dev/null 2>&1 || true; exit "$status"',
27
+ '--',
28
+ ...request.argv,
29
+ ]
30
+ : request.argv;
31
+ const spawnArgs = isDocker
32
+ ? [
33
+ 'run',
34
+ '--rm',
35
+ '-i',
36
+ ...(request.authStrategy === 'azure-service-principal' ||
37
+ request.authStrategy === 'tailscale-auth-key'
38
+ ? ['--entrypoint', '/bin/sh']
39
+ : request.entrypoint
40
+ ? ['--entrypoint', request.entrypoint]
41
+ : []),
42
+ ...(request.containerVolumes ?? []).flatMap((volume) => [
43
+ '--volume',
44
+ `${volume.source}:${volume.target}${volume.readOnly ? ':ro' : ''}`,
45
+ ]),
46
+ ...(request.authStrategy === 'tailscale-auth-key'
47
+ ? ['--env', 'TS_STATE_DIR=/var/lib/tailscale']
48
+ : []),
49
+ ...(request.containerEnvKeys ?? []).flatMap((name) => ['--env', name]),
50
+ request.command,
51
+ ...containerArgv,
52
+ ]
53
+ : request.argv;
54
+ let child;
55
+ try {
56
+ child = spawn(spawnCommand, spawnArgs, {
57
+ env: request.env,
58
+ stdio: ['pipe', 'pipe', 'pipe'],
59
+ shell: false,
60
+ });
61
+ }
62
+ catch (error) {
63
+ emit({ type: 'stderr', data: error instanceof Error ? error.message : String(error) });
64
+ emit({ type: 'exit', code: null, durationMs: 0, result: 'error' });
65
+ resolve({ code: null, durationMs: 0, result: 'error', truncated: false });
66
+ return;
67
+ }
68
+ const started = Date.now();
69
+ let timedOut = false;
70
+ let aborted = false;
71
+ let truncated = false;
72
+ let forwardedBytes = 0;
73
+ let settled = false;
74
+ let killTimer;
75
+ let escalateTimer;
76
+ const forward = (stream, chunk) => {
77
+ if (settled || timedOut || aborted)
78
+ return;
79
+ const remaining = request.maxOutputBytes - forwardedBytes;
80
+ if (remaining <= 0) {
81
+ truncated = true;
82
+ return;
83
+ }
84
+ if (chunk.length > remaining) {
85
+ truncated = true;
86
+ forwardedBytes += remaining;
87
+ emit({ type: stream, data: chunk.subarray(0, remaining).toString('utf8') });
88
+ return;
89
+ }
90
+ forwardedBytes += chunk.length;
91
+ emit({ type: stream, data: chunk.toString('utf8') });
92
+ };
93
+ child.stdout.on('data', (chunk) => forward('stdout', chunk));
94
+ child.stderr.on('data', (chunk) => forward('stderr', chunk));
95
+ if (request.stdin !== null && request.stdin !== undefined) {
96
+ child.stdin.end(request.stdin);
97
+ }
98
+ else {
99
+ child.stdin.end();
100
+ }
101
+ const terminate = () => {
102
+ try {
103
+ child.kill('SIGTERM');
104
+ }
105
+ catch {
106
+ // child already gone
107
+ }
108
+ if (escalateTimer === undefined) {
109
+ escalateTimer = setTimeout(() => {
110
+ try {
111
+ child.kill('SIGKILL');
112
+ }
113
+ catch {
114
+ // child already gone
115
+ }
116
+ }, killGraceMs);
117
+ escalateTimer.unref();
118
+ }
119
+ };
120
+ killTimer = setTimeout(() => {
121
+ timedOut = true;
122
+ terminate();
123
+ }, request.timeoutMs);
124
+ killTimer.unref();
125
+ const onAbort = () => {
126
+ aborted = true;
127
+ terminate();
128
+ };
129
+ if (signal !== undefined) {
130
+ if (signal.aborted)
131
+ onAbort();
132
+ else
133
+ signal.addEventListener('abort', onAbort, { once: true });
134
+ }
135
+ const finish = (code) => {
136
+ if (settled)
137
+ return;
138
+ settled = true;
139
+ if (killTimer !== undefined)
140
+ clearTimeout(killTimer);
141
+ if (escalateTimer !== undefined)
142
+ clearTimeout(escalateTimer);
143
+ signal?.removeEventListener('abort', onAbort);
144
+ const durationMs = Date.now() - started;
145
+ const result = aborted ? 'error' : timedOut ? 'timeout' : code === 0 ? 'ok' : 'error';
146
+ emit({
147
+ type: 'exit',
148
+ code: timedOut || aborted ? null : code,
149
+ durationMs,
150
+ result,
151
+ ...(truncated ? { truncated: true } : {}),
152
+ });
153
+ resolve({ code: timedOut || aborted ? null : code, durationMs, result, truncated });
154
+ };
155
+ child.on('error', (error) => {
156
+ if (!settled) {
157
+ emit({ type: 'stderr', data: error instanceof Error ? error.message : String(error) });
158
+ }
159
+ });
160
+ child.on('close', (code) => finish(code));
161
+ });
162
+ }
163
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../../src/cli-plane/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * CLI status probe parsing (docs/cli-hosting-research.md §2.6).
3
+ *
4
+ * The probe command's stdout is key=value on each line; `version` surfaces as
5
+ * the version string and `loggedIn`/`logged_in` as the boolean login state.
6
+ * Absent keys keep their defaults.
7
+ */
8
+ export declare function parseProbeOutput(stdout: string): {
9
+ version: string | null;
10
+ loggedIn: boolean;
11
+ };
12
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/cli-plane/status.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAgB9F"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * CLI status probe parsing (docs/cli-hosting-research.md §2.6).
3
+ *
4
+ * The probe command's stdout is key=value on each line; `version` surfaces as
5
+ * the version string and `loggedIn`/`logged_in` as the boolean login state.
6
+ * Absent keys keep their defaults.
7
+ */
8
+ export function parseProbeOutput(stdout) {
9
+ let version = null;
10
+ let loggedIn = false;
11
+ for (const line of stdout.split('\n')) {
12
+ const trimmed = line.trim();
13
+ const versionMatch = /^version=(.*)$/.exec(trimmed);
14
+ if (versionMatch?.[1] !== undefined && versionMatch[1] !== '') {
15
+ version = versionMatch[1];
16
+ }
17
+ const loginMatch = /^loggedIn=(true|false)$/i.exec(trimmed) ?? /^logged_in=(true|false)$/i.exec(trimmed);
18
+ if (loginMatch?.[1] !== undefined) {
19
+ loggedIn = loginMatch[1].toLowerCase() === 'true';
20
+ }
21
+ }
22
+ return { version, loggedIn };
23
+ }
24
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/cli-plane/status.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,IAAI,OAAO,GAAkB,IAAI,CAAC;IAClC,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,MAAM,YAAY,GAAG,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpD,IAAI,YAAY,EAAE,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,YAAY,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;YAC9D,OAAO,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC;QACD,MAAM,UAAU,GACd,0BAA0B,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,2BAA2B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxF,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;YAClC,QAAQ,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC;QACpD,CAAC;IACH,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,44 @@
1
+ import { z } from 'zod';
2
+ import type { CredentialPayload, TransportConfig } from '../domain/models.js';
3
+ export declare const harnessConfigSchema: z.ZodObject<{
4
+ mcpServers: z.ZodRecord<z.ZodString, z.ZodObject<{
5
+ command: z.ZodOptional<z.ZodString>;
6
+ args: z.ZodOptional<z.ZodArray<z.ZodString>>;
7
+ env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
8
+ url: z.ZodOptional<z.ZodString>;
9
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
10
+ }, z.core.$strip>>;
11
+ }, z.core.$strip>;
12
+ export type HarnessConfig = z.infer<typeof harnessConfigSchema>;
13
+ export interface HarnessImportedCredential {
14
+ name: string;
15
+ payload: CredentialPayload;
16
+ }
17
+ export interface HarnessImportedEntry {
18
+ name: string;
19
+ slug: string;
20
+ kind: 'remote' | 'home';
21
+ transport: TransportConfig;
22
+ credential: HarnessImportedCredential | null;
23
+ warnings: string[];
24
+ }
25
+ export interface HarnessImportPreview {
26
+ name: string;
27
+ slug: string;
28
+ kind: 'remote' | 'home';
29
+ transportSummary: string;
30
+ credential: {
31
+ name: string;
32
+ type: string;
33
+ fields: {
34
+ name: string;
35
+ masked: boolean;
36
+ }[];
37
+ } | null;
38
+ warnings: string[];
39
+ }
40
+ export declare function toSlug(name: string): string;
41
+ export declare function parseHarnessConfig(value: unknown): HarnessImportedEntry[];
42
+ /** Masked view for previews — never contains secret values. */
43
+ export declare function toPreview(entry: HarnessImportedEntry): HarnessImportPreview;
44
+ //# sourceMappingURL=harness-import.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harness-import.d.ts","sourceRoot":"","sources":["../../../src/config/harness-import.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAyB9E,eAAO,MAAM,mBAAmB;;;;;;;;iBAE9B,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAKhE,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,iBAAiB,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IACxB,SAAS,EAAE,eAAe,CAAC;IAC3B,UAAU,EAAE,yBAAyB,GAAG,IAAI,CAAC;IAC7C,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,OAAO,CAAA;SAAE,EAAE,CAAA;KAAE,GAAG,IAAI,CAAC;IAC/F,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO3C;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,oBAAoB,EAAE,CAkBzE;AAkGD,+DAA+D;AAC/D,wBAAgB,SAAS,CAAC,KAAK,EAAE,oBAAoB,GAAG,oBAAoB,CA2B3E"}