@jini-ai/platform 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/LICENSE +201 -0
  2. package/dist/asset-cache.d.ts +80 -0
  3. package/dist/asset-cache.d.ts.map +1 -0
  4. package/dist/asset-cache.js +423 -0
  5. package/dist/asset-cache.js.map +1 -0
  6. package/dist/aws-sigv4.d.ts +51 -0
  7. package/dist/aws-sigv4.d.ts.map +1 -0
  8. package/dist/aws-sigv4.js +104 -0
  9. package/dist/aws-sigv4.js.map +1 -0
  10. package/dist/blob-storage.d.ts +89 -0
  11. package/dist/blob-storage.d.ts.map +1 -0
  12. package/dist/blob-storage.js +315 -0
  13. package/dist/blob-storage.js.map +1 -0
  14. package/dist/command.d.ts +32 -0
  15. package/dist/command.d.ts.map +1 -0
  16. package/dist/command.js +101 -0
  17. package/dist/command.js.map +1 -0
  18. package/dist/download.d.ts +92 -0
  19. package/dist/download.d.ts.map +1 -0
  20. package/dist/download.js +856 -0
  21. package/dist/download.js.map +1 -0
  22. package/dist/fs.d.ts +55 -0
  23. package/dist/fs.d.ts.map +1 -0
  24. package/dist/fs.js +124 -0
  25. package/dist/fs.js.map +1 -0
  26. package/dist/home-expansion.d.ts +18 -0
  27. package/dist/home-expansion.d.ts.map +1 -0
  28. package/dist/home-expansion.js +58 -0
  29. package/dist/home-expansion.js.map +1 -0
  30. package/dist/http.d.ts +14 -0
  31. package/dist/http.d.ts.map +1 -0
  32. package/dist/http.js +39 -0
  33. package/dist/http.js.map +1 -0
  34. package/dist/index.d.ts +59 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +45 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/process.d.ts +159 -0
  39. package/dist/process.d.ts.map +1 -0
  40. package/dist/process.js +362 -0
  41. package/dist/process.js.map +1 -0
  42. package/dist/proxy-env.d.ts +50 -0
  43. package/dist/proxy-env.d.ts.map +1 -0
  44. package/dist/proxy-env.js +373 -0
  45. package/dist/proxy-env.js.map +1 -0
  46. package/dist/resource-paths.d.ts +68 -0
  47. package/dist/resource-paths.d.ts.map +1 -0
  48. package/dist/resource-paths.js +137 -0
  49. package/dist/resource-paths.js.map +1 -0
  50. package/dist/sandbox-env.d.ts +86 -0
  51. package/dist/sandbox-env.d.ts.map +1 -0
  52. package/dist/sandbox-env.js +215 -0
  53. package/dist/sandbox-env.js.map +1 -0
  54. package/dist/shell.d.ts +46 -0
  55. package/dist/shell.d.ts.map +1 -0
  56. package/dist/shell.js +78 -0
  57. package/dist/shell.js.map +1 -0
  58. package/dist/terminal.d.ts +137 -0
  59. package/dist/terminal.d.ts.map +1 -0
  60. package/dist/terminal.js +398 -0
  61. package/dist/terminal.js.map +1 -0
  62. package/dist/toolchain.d.ts +17 -0
  63. package/dist/toolchain.d.ts.map +1 -0
  64. package/dist/toolchain.js +251 -0
  65. package/dist/toolchain.js.map +1 -0
  66. package/package.json +47 -0
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Names the environment variables and on-disk naming this port reads/writes.
3
+ * A consumer supplies its own env-var names and config-directory name — see
4
+ * `source-map.md` for the values a real adapter (e.g. the OD adapter) uses.
5
+ */
6
+ export interface SandboxEnvConfig {
7
+ /** Env var gating whether sandboxing is on (truthy/falsy string). */
8
+ modeEnvVar: string;
9
+ /** Env var carrying a PATH-delimiter-separated list of allowed import roots. */
10
+ importAllowedRootsEnvVar: string;
11
+ /** Env var carrying the sandbox data directory (required when sandboxing is on). */
12
+ dataDirEnvVar: string;
13
+ /** Env var the spawned process reads back for its agent-home directory. */
14
+ agentHomeEnvVar: string;
15
+ /** Env var the spawned process reads back for its local agent-profiles config path. */
16
+ agentProfilesConfigEnvVar: string;
17
+ /** Sub-directory name (under the agent home) local agent-profile config lives in. */
18
+ agentProfilesDirName: string;
19
+ }
20
+ export interface SandboxRuntimeRoots {
21
+ agentHomeDir: string;
22
+ cacheDir: string;
23
+ configDir: string;
24
+ generatedFilesDir: string;
25
+ logsDir: string;
26
+ mcpConfigDir: string;
27
+ pluginStateDir: string;
28
+ previewStateDir: string;
29
+ skillsCacheDir: string;
30
+ tempDir: string;
31
+ toolConfigDir: string;
32
+ }
33
+ export interface SandboxRuntimeConfig {
34
+ enabled: boolean;
35
+ dataDir: string;
36
+ roots: SandboxRuntimeRoots;
37
+ }
38
+ /**
39
+ * Reads {@link SandboxEnvConfig.modeEnvVar} and interprets it as a boolean
40
+ * flag. Throws if the value is set but neither a recognized truthy nor
41
+ * falsy spelling.
42
+ */
43
+ export declare function isSandboxModeEnabled(config: SandboxEnvConfig, env?: Record<string, string | undefined>): boolean;
44
+ /**
45
+ * The configured, canonicalized set of directories an imported project root
46
+ * is allowed to live under while sandboxing is on.
47
+ */
48
+ export declare function sandboxImportAllowedRoots(config: SandboxEnvConfig, env?: Record<string, string | undefined>): string[];
49
+ /**
50
+ * Whether `projectRoot` may be used as an imported-folder project while
51
+ * sandboxing is enabled. Always `true` when sandboxing is off.
52
+ */
53
+ export declare function isSandboxImportedProjectRootAllowed(config: SandboxEnvConfig, projectRoot: string, env?: Record<string, string | undefined>): boolean;
54
+ /**
55
+ * A human-readable reason `projectRoot` is unavailable under sandboxing, or
56
+ * `null` when it's allowed (including when sandboxing is off).
57
+ */
58
+ export declare function sandboxImportedProjectRootUnavailableReason(config: SandboxEnvConfig, projectRoot: string, env?: Record<string, string | undefined>): string | null;
59
+ /**
60
+ * Derives the full sandbox directory tree from a data directory. Pure —
61
+ * does not touch the filesystem (see {@link ensureSandboxRuntimeDirs}).
62
+ */
63
+ export declare function resolveSandboxRuntimeConfig(enabled: boolean, dataDir: string): SandboxRuntimeConfig;
64
+ /**
65
+ * Resolves the sandbox runtime config from environment variables, or `null`
66
+ * when sandboxing is off. Throws when sandboxing is on but the data-dir env
67
+ * var is unset.
68
+ */
69
+ export declare function resolveSandboxRuntimeConfigFromEnv(config: SandboxEnvConfig, env: Record<string, string | undefined>, projectRoot: string): SandboxRuntimeConfig | null;
70
+ /**
71
+ * The path a spawned agent process's local agent-profiles config lives at,
72
+ * under its sandboxed agent-home directory.
73
+ */
74
+ export declare function sandboxAgentProfilesConfigPath(config: SandboxEnvConfig, runtime: SandboxRuntimeConfig): string;
75
+ /**
76
+ * Creates every directory in the sandbox tree (idempotent). No-op when
77
+ * sandboxing is disabled.
78
+ */
79
+ export declare function ensureSandboxRuntimeDirs(runtime: SandboxRuntimeConfig): void;
80
+ /**
81
+ * Overlays sandboxed HOME/XDG/TMPDIR/tool-config env vars onto `baseEnv` for
82
+ * a spawned agent process. Returns `baseEnv` unchanged when sandboxing is
83
+ * disabled.
84
+ */
85
+ export declare function applySandboxRuntimeEnv(config: SandboxEnvConfig, baseEnv: NodeJS.ProcessEnv, runtime: SandboxRuntimeConfig): NodeJS.ProcessEnv;
86
+ //# sourceMappingURL=sandbox-env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox-env.d.ts","sourceRoot":"","sources":["../src/sandbox-env.ts"],"names":[],"mappings":"AAmBA;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,qEAAqE;IACrE,UAAU,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,wBAAwB,EAAE,MAAM,CAAC;IACjC,oFAAoF;IACpF,aAAa,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,eAAe,EAAE,MAAM,CAAC;IACxB,uFAAuF;IACvF,yBAAyB,EAAE,MAAM,CAAC;IAClC,qFAAqF;IACrF,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,mBAAmB,CAAC;CAC5B;AAKD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,gBAAgB,EACxB,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACpD,OAAO,CAUT;AAkED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,gBAAgB,EACxB,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACpD,MAAM,EAAE,CAEV;AAED;;;GAGG;AACH,wBAAgB,mCAAmC,CACjD,MAAM,EAAE,gBAAgB,EACxB,WAAW,EAAE,MAAM,EACnB,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACpD,OAAO,CAIT;AAED;;;GAGG;AACH,wBAAgB,2CAA2C,CACzD,MAAM,EAAE,gBAAgB,EACxB,WAAW,EAAE,MAAM,EACnB,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACpD,MAAM,GAAG,IAAI,CAMf;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,oBAAoB,CAmBnG;AAED;;;;GAIG;AACH,wBAAgB,kCAAkC,CAChD,MAAM,EAAE,gBAAgB,EACxB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,EACvC,WAAW,EAAE,MAAM,GAClB,oBAAoB,GAAG,IAAI,CAO7B;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,gBAAgB,EACxB,OAAO,EAAE,oBAAoB,GAC5B,MAAM,CAER;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAK5E;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,gBAAgB,EACxB,OAAO,EAAE,MAAM,CAAC,UAAU,EAC1B,OAAO,EAAE,oBAAoB,GAC5B,MAAM,CAAC,UAAU,CA8BnB"}
@@ -0,0 +1,215 @@
1
+ /**
2
+ * @module sandbox-env
3
+ *
4
+ * Sandboxed agent-execution environment: an isolated directory tree (agent
5
+ * home, cache, config, temp, …) plus the environment-variable overrides that
6
+ * redirect a spawned agent process's HOME/XDG/TMPDIR into it, and a policy
7
+ * gate for whether an imported (non-managed) project root may be used while
8
+ * sandboxing is on.
9
+ *
10
+ * Generalized from an upstream flat daemon module: the origin hardcoded its
11
+ * host product's env-var names and a product-branded config sub-directory.
12
+ * Every one of those is now a field on {@link SandboxEnvConfig} so a
13
+ * consumer isn't branded — see `source-map.md` for the exact mapping.
14
+ */
15
+ import fs from 'node:fs';
16
+ import path from 'node:path';
17
+ import { resolveProjectRelativePath } from './home-expansion.js';
18
+ const TRUTHY_VALUES = new Set(['1', 'true', 'yes', 'on']);
19
+ const FALSY_VALUES = new Set(['0', 'false', 'no', 'off', '']);
20
+ /**
21
+ * Reads {@link SandboxEnvConfig.modeEnvVar} and interprets it as a boolean
22
+ * flag. Throws if the value is set but neither a recognized truthy nor
23
+ * falsy spelling.
24
+ */
25
+ export function isSandboxModeEnabled(config, env = process.env) {
26
+ const raw = env[config.modeEnvVar];
27
+ if (typeof raw !== 'string')
28
+ return false;
29
+ const value = raw.trim().toLowerCase();
30
+ if (TRUTHY_VALUES.has(value))
31
+ return true;
32
+ if (FALSY_VALUES.has(value))
33
+ return false;
34
+ throw new Error(`${config.modeEnvVar} must be one of ${Array.from(TRUTHY_VALUES).join(', ')} ` +
35
+ `or ${Array.from(FALSY_VALUES).join(', ')}`);
36
+ }
37
+ function configuredSandboxImportRoots(config, env) {
38
+ const raw = env[config.importAllowedRootsEnvVar];
39
+ if (typeof raw !== 'string' || !raw.trim())
40
+ return [];
41
+ const roots = raw
42
+ .split(path.delimiter)
43
+ .map((part) => part.trim())
44
+ .filter(Boolean);
45
+ const relativeRoot = roots.find((root) => !path.isAbsolute(path.normalize(root)));
46
+ if (relativeRoot) {
47
+ throw new Error(`${config.importAllowedRootsEnvVar} entries must be absolute paths. Got: ${relativeRoot}`);
48
+ }
49
+ return roots;
50
+ }
51
+ function canonicalizePathForContainment(value) {
52
+ const resolved = path.normalize(value);
53
+ try {
54
+ return fs.realpathSync.native(resolved);
55
+ }
56
+ catch {
57
+ return resolved;
58
+ }
59
+ }
60
+ // A containment *candidate* (e.g. a project root that hasn't been imported/
61
+ // created yet) may not fully exist on disk, so a bare realpath attempt
62
+ // throws. Unlike `canonicalizePathForContainment` above — used only for the
63
+ // *configured allowed roots*, which are expected to already exist when they
64
+ // matter — this walks up to the nearest existing ancestor, realpaths that,
65
+ // and rejoins the not-yet-existing suffix. Without this, comparing a raw
66
+ // candidate against a realpath'd allowed root misfires whenever the roots
67
+ // sit under a symlinked prefix (macOS's /tmp -> /private/tmp, /var ->
68
+ // /private/var): the candidate would keep the raw prefix while the allowed
69
+ // root was resolved through the symlink, so a legitimately-nested path
70
+ // would look like it climbs above the root.
71
+ function canonicalizeContainmentCandidate(value) {
72
+ const resolved = path.normalize(value);
73
+ let existing = resolved;
74
+ const trailingSegments = [];
75
+ for (;;) {
76
+ try {
77
+ return path.join(fs.realpathSync.native(existing), ...trailingSegments);
78
+ }
79
+ catch {
80
+ // `path.dirname(x) === x` is the fixed point for both an absolute
81
+ // filesystem root ('/') and a relative reference ('.') — walking
82
+ // further would just retry the same path forever, so bail out to the
83
+ // raw normalized value instead of looping.
84
+ const parent = path.dirname(existing);
85
+ if (parent === existing)
86
+ return resolved;
87
+ trailingSegments.unshift(path.basename(existing));
88
+ existing = parent;
89
+ }
90
+ }
91
+ }
92
+ function isPathInsideDir(root, candidate) {
93
+ const relative = path.relative(root, candidate);
94
+ return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
95
+ }
96
+ /**
97
+ * The configured, canonicalized set of directories an imported project root
98
+ * is allowed to live under while sandboxing is on.
99
+ */
100
+ export function sandboxImportAllowedRoots(config, env = process.env) {
101
+ return configuredSandboxImportRoots(config, env).map(canonicalizePathForContainment);
102
+ }
103
+ /**
104
+ * Whether `projectRoot` may be used as an imported-folder project while
105
+ * sandboxing is enabled. Always `true` when sandboxing is off.
106
+ */
107
+ export function isSandboxImportedProjectRootAllowed(config, projectRoot, env = process.env) {
108
+ if (!isSandboxModeEnabled(config, env))
109
+ return true;
110
+ const candidate = canonicalizeContainmentCandidate(projectRoot);
111
+ return sandboxImportAllowedRoots(config, env).some((root) => isPathInsideDir(root, candidate));
112
+ }
113
+ /**
114
+ * A human-readable reason `projectRoot` is unavailable under sandboxing, or
115
+ * `null` when it's allowed (including when sandboxing is off).
116
+ */
117
+ export function sandboxImportedProjectRootUnavailableReason(config, projectRoot, env = process.env) {
118
+ if (!isSandboxModeEnabled(config, env))
119
+ return null;
120
+ return isSandboxImportedProjectRootAllowed(config, projectRoot, env)
121
+ ? null
122
+ : `Imported-folder projects are not available in ${config.modeEnvVar} unless their root is ` +
123
+ `under ${config.importAllowedRootsEnvVar}.`;
124
+ }
125
+ /**
126
+ * Derives the full sandbox directory tree from a data directory. Pure —
127
+ * does not touch the filesystem (see {@link ensureSandboxRuntimeDirs}).
128
+ */
129
+ export function resolveSandboxRuntimeConfig(enabled, dataDir) {
130
+ const sandboxRoot = path.join(dataDir, 'sandbox');
131
+ return {
132
+ enabled,
133
+ dataDir,
134
+ roots: {
135
+ agentHomeDir: path.join(sandboxRoot, 'agent-home'),
136
+ cacheDir: path.join(sandboxRoot, 'cache'),
137
+ configDir: path.join(sandboxRoot, 'config'),
138
+ generatedFilesDir: path.join(dataDir, 'generated-files'),
139
+ logsDir: path.join(dataDir, 'logs'),
140
+ mcpConfigDir: dataDir,
141
+ pluginStateDir: path.join(dataDir, 'plugins'),
142
+ previewStateDir: path.join(dataDir, 'previews'),
143
+ skillsCacheDir: path.join(dataDir, 'skills'),
144
+ tempDir: path.join(sandboxRoot, 'tmp'),
145
+ toolConfigDir: path.join(sandboxRoot, 'tools'),
146
+ },
147
+ };
148
+ }
149
+ /**
150
+ * Resolves the sandbox runtime config from environment variables, or `null`
151
+ * when sandboxing is off. Throws when sandboxing is on but the data-dir env
152
+ * var is unset.
153
+ */
154
+ export function resolveSandboxRuntimeConfigFromEnv(config, env, projectRoot) {
155
+ if (!isSandboxModeEnabled(config, env))
156
+ return null;
157
+ const rawDataDir = env[config.dataDirEnvVar]?.trim();
158
+ if (!rawDataDir) {
159
+ throw new Error(`${config.dataDirEnvVar} is required when ${config.modeEnvVar} is enabled`);
160
+ }
161
+ return resolveSandboxRuntimeConfig(true, resolveProjectRelativePath(rawDataDir, projectRoot));
162
+ }
163
+ /**
164
+ * The path a spawned agent process's local agent-profiles config lives at,
165
+ * under its sandboxed agent-home directory.
166
+ */
167
+ export function sandboxAgentProfilesConfigPath(config, runtime) {
168
+ return path.join(runtime.roots.agentHomeDir, config.agentProfilesDirName, 'agents.local.json');
169
+ }
170
+ /**
171
+ * Creates every directory in the sandbox tree (idempotent). No-op when
172
+ * sandboxing is disabled.
173
+ */
174
+ export function ensureSandboxRuntimeDirs(runtime) {
175
+ if (!runtime.enabled)
176
+ return;
177
+ for (const dir of new Set(Object.values(runtime.roots))) {
178
+ fs.mkdirSync(dir, { recursive: true });
179
+ }
180
+ }
181
+ /**
182
+ * Overlays sandboxed HOME/XDG/TMPDIR/tool-config env vars onto `baseEnv` for
183
+ * a spawned agent process. Returns `baseEnv` unchanged when sandboxing is
184
+ * disabled.
185
+ */
186
+ export function applySandboxRuntimeEnv(config, baseEnv, runtime) {
187
+ if (!runtime.enabled)
188
+ return baseEnv;
189
+ const env = { ...baseEnv };
190
+ const { roots } = runtime;
191
+ const codexHome = path.join(roots.agentHomeDir, '.codex');
192
+ const claudeConfigDir = path.join(roots.configDir, 'claude');
193
+ const opencodeHome = path.join(roots.agentHomeDir, '.opencode');
194
+ const npmUserConfig = path.join(roots.toolConfigDir, 'npmrc');
195
+ env[config.modeEnvVar] = '1';
196
+ env[config.dataDirEnvVar] = runtime.dataDir;
197
+ env[config.agentHomeEnvVar] = roots.agentHomeDir;
198
+ env.HOME = roots.agentHomeDir;
199
+ env.USERPROFILE = roots.agentHomeDir;
200
+ env.XDG_CONFIG_HOME = roots.configDir;
201
+ env.XDG_CACHE_HOME = roots.cacheDir;
202
+ env.XDG_DATA_HOME = path.join(roots.configDir, 'data');
203
+ env.XDG_STATE_HOME = path.join(roots.configDir, 'state');
204
+ env.TMPDIR = roots.tempDir;
205
+ env.TEMP = roots.tempDir;
206
+ env.TMP = roots.tempDir;
207
+ env.CODEX_HOME = codexHome;
208
+ env.CLAUDE_CONFIG_DIR = claudeConfigDir;
209
+ env.OPENCODE_TEST_HOME = opencodeHome;
210
+ env[config.agentProfilesConfigEnvVar] = sandboxAgentProfilesConfigPath(config, runtime);
211
+ env.NPM_CONFIG_USERCONFIG = npmUserConfig;
212
+ env.npm_config_userconfig = npmUserConfig;
213
+ return env;
214
+ }
215
+ //# sourceMappingURL=sandbox-env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox-env.js","sourceRoot":"","sources":["../src/sandbox-env.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * @module shell
3
+ *
4
+ * Buffered command execution that re-enters the user's login shell. A daemon
5
+ * process's own `PATH` frequently lacks entries a shell profile adds (a
6
+ * version manager's shims, a package-manager-installed CLI, a Homebrew
7
+ * prefix), so a plain `execFile` against a bare command name can fail even
8
+ * though the same command works fine in the user's terminal. Routing through
9
+ * `$SHELL -c "..."` re-sources that PATH before running the command.
10
+ *
11
+ * Depends on nothing else in this package; owns no process lifecycle beyond
12
+ * the single buffered child it spawns per call.
13
+ */
14
+ import { type ExecFileOptions } from "node:child_process";
15
+ export type BufferedCommandResult = {
16
+ code: string | number | null | undefined;
17
+ error: Error | null;
18
+ ok: boolean;
19
+ stderr: string;
20
+ stdout: string;
21
+ };
22
+ /**
23
+ * Run a command directly via `execFile`, buffering stdout/stderr and never
24
+ * rejecting — failures are reported through the returned `ok`/`error` fields.
25
+ *
26
+ * @param command - The executable to run.
27
+ * @param args - Arguments to pass to the executable.
28
+ * @param opts - `child_process.execFile` options (a 120s timeout and 1MiB
29
+ * buffer apply unless overridden).
30
+ * @returns The buffered result.
31
+ */
32
+ export declare function execFileBuffered(command: string, args: readonly string[], opts?: ExecFileOptions): Promise<BufferedCommandResult>;
33
+ /**
34
+ * Run an arbitrary command re-entering the user's login shell (via
35
+ * `$SHELL -c`) so shell-profile-only `PATH` entries are visible, then buffer
36
+ * its output. Falls back to a direct `execFile` on Windows, where there is no
37
+ * equivalent login-shell PATH gap.
38
+ *
39
+ * @param command - The executable to run.
40
+ * @param args - Arguments to pass to the executable.
41
+ * @param opts - `child_process.execFile` options; `env` defaults to
42
+ * `process.env` so the re-exported `PATH` above has a base to restore from.
43
+ * @returns The buffered result.
44
+ */
45
+ export declare function execCommandViaLoginShell(command: string, args: readonly string[], opts?: ExecFileOptions): Promise<BufferedCommandResult>;
46
+ //# sourceMappingURL=shell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../src/shell.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAY,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAEpE,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACzC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,IAAI,GAAE,eAAoB,GACzB,OAAO,CAAC,qBAAqB,CAAC,CAYhC;AAqBD;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,IAAI,GAAE,eAAoB,GACzB,OAAO,CAAC,qBAAqB,CAAC,CAUhC"}
package/dist/shell.js ADDED
@@ -0,0 +1,78 @@
1
+ /**
2
+ * @module shell
3
+ *
4
+ * Buffered command execution that re-enters the user's login shell. A daemon
5
+ * process's own `PATH` frequently lacks entries a shell profile adds (a
6
+ * version manager's shims, a package-manager-installed CLI, a Homebrew
7
+ * prefix), so a plain `execFile` against a bare command name can fail even
8
+ * though the same command works fine in the user's terminal. Routing through
9
+ * `$SHELL -c "..."` re-sources that PATH before running the command.
10
+ *
11
+ * Depends on nothing else in this package; owns no process lifecycle beyond
12
+ * the single buffered child it spawns per call.
13
+ */
14
+ import { execFile } from "node:child_process";
15
+ /**
16
+ * Run a command directly via `execFile`, buffering stdout/stderr and never
17
+ * rejecting — failures are reported through the returned `ok`/`error` fields.
18
+ *
19
+ * @param command - The executable to run.
20
+ * @param args - Arguments to pass to the executable.
21
+ * @param opts - `child_process.execFile` options (a 120s timeout and 1MiB
22
+ * buffer apply unless overridden).
23
+ * @returns The buffered result.
24
+ */
25
+ export function execFileBuffered(command, args, opts = {}) {
26
+ return new Promise((resolve) => {
27
+ execFile(command, [...args], { timeout: 120_000, maxBuffer: 1024 * 1024, ...opts }, (error, stdout, stderr) => {
28
+ resolve({
29
+ code: error && "code" in error ? error.code : undefined,
30
+ error,
31
+ ok: !error,
32
+ stderr: String(stderr).trim(),
33
+ stdout: String(stdout).trim(),
34
+ });
35
+ });
36
+ });
37
+ }
38
+ /** @internal Single-quote a POSIX shell argument, escaping embedded single quotes. */
39
+ function quotePosixShellArg(value) {
40
+ const text = String(value ?? "");
41
+ return `'${text.replace(/'/g, `'\\''`)}'`;
42
+ }
43
+ /** @internal Join a command and its arguments into one quoted POSIX shell command line. */
44
+ function buildShellCommandLine(command, args) {
45
+ return [command, ...args].map(quotePosixShellArg).join(" ");
46
+ }
47
+ /** @internal Wrap a shell command line so a non-login shell still sees the current `PATH`. */
48
+ function buildLoginShellCommand(innerCommand) {
49
+ // Use a non-login shell and re-export PATH so test fakes and wrapped
50
+ // command shims remain visible; login shells often reset PATH from
51
+ // profile scripts.
52
+ return `export PATH=${quotePosixShellArg(process.env.PATH)}; ${innerCommand}`;
53
+ }
54
+ /**
55
+ * Run an arbitrary command re-entering the user's login shell (via
56
+ * `$SHELL -c`) so shell-profile-only `PATH` entries are visible, then buffer
57
+ * its output. Falls back to a direct `execFile` on Windows, where there is no
58
+ * equivalent login-shell PATH gap.
59
+ *
60
+ * @param command - The executable to run.
61
+ * @param args - Arguments to pass to the executable.
62
+ * @param opts - `child_process.execFile` options; `env` defaults to
63
+ * `process.env` so the re-exported `PATH` above has a base to restore from.
64
+ * @returns The buffered result.
65
+ */
66
+ export function execCommandViaLoginShell(command, args, opts = {}) {
67
+ if (process.platform === "win32")
68
+ return execFileBuffered(command, args, opts);
69
+ // `/bin/sh` is POSIX-guaranteed to exist; unlike a specific shell (zsh,
70
+ // bash), it is never absent on a POSIX host, so it is the only safe
71
+ // default for a product-neutral engine that can't assume its host's shell.
72
+ const shell = process.env.SHELL?.trim() || "/bin/sh";
73
+ return execFileBuffered(shell, ["-c", buildLoginShellCommand(buildShellCommandLine(command, args))], {
74
+ env: process.env,
75
+ ...opts,
76
+ });
77
+ }
78
+ //# sourceMappingURL=shell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell.js","sourceRoot":"","sources":["../src/shell.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,QAAQ,EAAwB,MAAM,oBAAoB,CAAC;AAUpE;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAe,EACf,IAAuB,EACvB,OAAwB,EAAE;IAE1B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,QAAQ,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,GAAG,IAAI,EAAE,GAAG,IAAI,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;YAC5G,OAAO,CAAC;gBACN,IAAI,EAAE,KAAK,IAAI,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;gBACvD,KAAK;gBACL,EAAE,EAAE,CAAC,KAAK;gBACV,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE;gBAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE;aAC9B,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,sFAAsF;AACtF,SAAS,kBAAkB,CAAC,KAAgC;IAC1D,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IACjC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AAC5C,CAAC;AAED,2FAA2F;AAC3F,SAAS,qBAAqB,CAAC,OAAe,EAAE,IAAuB;IACrE,OAAO,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC9D,CAAC;AAED,8FAA8F;AAC9F,SAAS,sBAAsB,CAAC,YAAoB;IAClD,qEAAqE;IACrE,mEAAmE;IACnE,mBAAmB;IACnB,OAAO,eAAe,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,YAAY,EAAE,CAAC;AAChF,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,wBAAwB,CACtC,OAAe,EACf,IAAuB,EACvB,OAAwB,EAAE;IAE1B,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO;QAAE,OAAO,gBAAgB,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC/E,wEAAwE;IACxE,oEAAoE;IACpE,2EAA2E;IAC3E,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;IACrD,OAAO,gBAAgB,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,sBAAsB,CAAC,qBAAqB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE;QACnG,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,GAAG,IAAI;KACR,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,137 @@
1
+ /** A single running PTY child process, however the caller's backend spawns it. */
2
+ export interface PtyProcess {
3
+ onData(cb: (chunk: string) => void): void;
4
+ onExit(cb: (event: {
5
+ exitCode: number;
6
+ signal?: number;
7
+ }) => void): void;
8
+ write(input: string): void;
9
+ resize(cols: number, rows: number): void;
10
+ kill(signal?: string): void;
11
+ }
12
+ export interface PtySpawnOptions {
13
+ name: string;
14
+ cols: number;
15
+ rows: number;
16
+ cwd: string;
17
+ env: Record<string, string>;
18
+ }
19
+ /** Spawns a PTY. The caller supplies this — e.g. a thin wrapper around `node-pty`'s `spawn`. */
20
+ export type PtySpawn = (shell: string, args: string[], options: PtySpawnOptions) => PtyProcess;
21
+ /**
22
+ * Resolves the candidate paths to node-pty's `spawn-helper` binary. On
23
+ * macOS/Linux, `pty.fork` shells out to this helper via `posix_spawn`;
24
+ * node-pty looks for the native artifacts under `build/Release` first and a
25
+ * platform-tagged `prebuilds/<platform>-<arch>` dir second. Returns both so
26
+ * {@link ensureSpawnHelperExecutable} covers whichever one a given install
27
+ * produced. Empty on win32 (ConPTY has no helper) or when node-pty can't be
28
+ * resolved at all (not installed, or a workspace that doesn't use it).
29
+ *
30
+ * @param options.platform - Defaults to `process.platform`; injectable for tests.
31
+ * @param options.resolve - Defaults to a `require.resolve`-shaped resolver for
32
+ * `'node-pty'`; injectable so this stays testable without the native module.
33
+ */
34
+ export declare function spawnHelperCandidatePaths(options?: {
35
+ platform?: NodeJS.Platform;
36
+ resolve?: (specifier: string) => string;
37
+ }): string[];
38
+ /**
39
+ * Restores the executable bit on node-pty's `spawn-helper`. pnpm unpacks
40
+ * node-pty's prebuilt binaries with mode 0644 — and node-pty's own
41
+ * post-install hook only chmods `build/Release`, which a prebuild-based
42
+ * install never creates. Re-adding +x before the first fork makes the
43
+ * terminal self-heal across reinstalls without depending on an install hook.
44
+ * Best-effort and idempotent: a missing file or a read-only filesystem is
45
+ * swallowed, and the subsequent spawn surfaces the real error instead.
46
+ *
47
+ * @param candidatePaths - Defaults to {@link spawnHelperCandidatePaths}'s result.
48
+ */
49
+ export declare function ensureSpawnHelperExecutable(candidatePaths?: string[]): void;
50
+ /**
51
+ * Resolves the shell binary for a new PTY. Honors an explicit request
52
+ * override, then the user's environment (`SHELL` on posix, `ComSpec` on
53
+ * win32), and finally a per-platform default.
54
+ */
55
+ export declare function resolveShell(requested?: string | null, options?: {
56
+ platform?: NodeJS.Platform;
57
+ env?: NodeJS.ProcessEnv;
58
+ }): string;
59
+ export type TerminalEventData = {
60
+ data: string;
61
+ } | {
62
+ code: number | null;
63
+ signal: string | null;
64
+ };
65
+ export interface TerminalEventRecord {
66
+ id: number;
67
+ event: 'data' | 'exit';
68
+ data: TerminalEventData;
69
+ timestamp: number;
70
+ byteLength: number;
71
+ }
72
+ /** A minimal push sink a transport adapts its live connection to (e.g. SSE). */
73
+ export interface TerminalSseSink {
74
+ send(event: string, data: TerminalEventData, id: number): void;
75
+ end(): void;
76
+ }
77
+ export interface TerminalSession {
78
+ readonly id: string;
79
+ readonly projectId: string | null;
80
+ readonly cwd: string;
81
+ readonly shell: string;
82
+ readonly cols: number;
83
+ readonly rows: number;
84
+ readonly status: 'running' | 'exited';
85
+ readonly createdAt: number;
86
+ readonly updatedAt: number;
87
+ readonly exitCode: number | null;
88
+ readonly signal: string | null;
89
+ }
90
+ export interface CreateTerminalOptions {
91
+ projectId?: string | null;
92
+ cwd: string;
93
+ cols?: number;
94
+ rows?: number;
95
+ shell?: string | null;
96
+ }
97
+ export interface CreateTerminalServiceOptions {
98
+ /** Lazily loads the PTY spawner. Called at most once, on the first `create()`. */
99
+ loadSpawnPty: () => Promise<PtySpawn>;
100
+ /** Count backstop for the per-session output ring-buffer; `maxBufferBytes` is the real ceiling. */
101
+ maxEvents?: number;
102
+ /** Byte ceiling for retained reattach scrollback per running session (evicted oldest-first). */
103
+ maxBufferBytes?: number;
104
+ /** Trailing scrollback kept once a shell exits, so an unreaped session doesn't pin memory. */
105
+ exitTailBytes?: number;
106
+ /** Coalesces PTY output for roughly one animation frame before fanning out one `data` event. */
107
+ flushIntervalMs?: number;
108
+ /** Flushes immediately once buffered output crosses this size, bypassing the frame timer. */
109
+ flushThresholdBytes?: number;
110
+ /** Drops an exited session from the registry after this idle window. */
111
+ ttlMs?: number;
112
+ /** Grace window given to children to exit during {@link TerminalService.shutdownActive}. */
113
+ shutdownGraceMs?: number;
114
+ }
115
+ export interface TerminalService {
116
+ create(options: CreateTerminalOptions): Promise<TerminalSession>;
117
+ get(id: string): TerminalSession | null;
118
+ list(filter?: {
119
+ projectId?: string | null;
120
+ }): TerminalSession[];
121
+ write(id: string, input: string): boolean;
122
+ resize(id: string, cols: number, rows: number): boolean;
123
+ kill(id: string, signal?: string): boolean;
124
+ /** Replays scrollback after `lastEventId`, then attaches `sink` for live output if still running. */
125
+ attach(id: string, lastEventId: number, sink: TerminalSseSink): 'attached' | 'ended' | 'not-found';
126
+ detach(id: string, sink: TerminalSseSink): void;
127
+ shutdownActive(options?: {
128
+ graceMs?: number;
129
+ }): Promise<void>;
130
+ isTerminal(status: string): boolean;
131
+ }
132
+ /**
133
+ * Builds an in-memory terminal session manager. See the module docblock for
134
+ * the design rationale; see {@link CreateTerminalServiceOptions} for tuning.
135
+ */
136
+ export declare function createTerminalService(options: CreateTerminalServiceOptions): TerminalService;
137
+ //# sourceMappingURL=terminal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../src/terminal.ts"],"names":[],"mappings":"AA2BA,kFAAkF;AAClF,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1C,MAAM,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GAAG,IAAI,CAAC;IACzE,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B;AAED,gGAAgG;AAChG,MAAM,MAAM,QAAQ,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,eAAe,KAAK,UAAU,CAAC;AAE/F;;;;;;;;;;;;GAYG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,GAAE;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;CACpC,GAAG,MAAM,EAAE,CAgBhB;AAUD;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CAAC,cAAc,GAAE,MAAM,EAAgC,GAAG,IAAI,CAWxG;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,EACzB,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;CAAO,GACpE,MAAM,CASR;AAYD,MAAM,MAAM,iBAAiB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAElG,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,IAAI,EAAE,iBAAiB,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,gFAAgF;AAChF,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/D,GAAG,IAAI,IAAI,CAAC;CACb;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAuCD,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,4BAA4B;IAC3C,kFAAkF;IAClF,YAAY,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC;IACtC,mGAAmG;IACnG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gGAAgG;IAChG,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8FAA8F;IAC9F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gGAAgG;IAChG,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6FAA6F;IAC7F,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4FAA4F;IAC5F,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACjE,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAAC;IACxC,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,eAAe,EAAE,CAAC;IAChE,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1C,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACxD,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3C,qGAAqG;IACrG,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,GAAG,UAAU,GAAG,OAAO,GAAG,WAAW,CAAC;IACnG,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,GAAG,IAAI,CAAC;IAChD,cAAc,CAAC,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;CACrC;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,GAAG,eAAe,CA2Q5F"}