@jini-ai/http-kit 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.
- package/LICENSE +201 -0
- package/README.md +107 -0
- package/dist/active-context.d.ts +99 -0
- package/dist/active-context.d.ts.map +1 -0
- package/dist/active-context.js +77 -0
- package/dist/active-context.js.map +1 -0
- package/dist/adapter.d.ts +36 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +92 -0
- package/dist/adapter.js.map +1 -0
- package/dist/agents.d.ts +55 -0
- package/dist/agents.d.ts.map +1 -0
- package/dist/agents.js +23 -0
- package/dist/agents.js.map +1 -0
- package/dist/api-security-middleware.d.ts +146 -0
- package/dist/api-security-middleware.d.ts.map +1 -0
- package/dist/api-security-middleware.js +276 -0
- package/dist/api-security-middleware.js.map +1 -0
- package/dist/attachments.d.ts +317 -0
- package/dist/attachments.d.ts.map +1 -0
- package/dist/attachments.js +664 -0
- package/dist/attachments.js.map +1 -0
- package/dist/cancel-owned-runs.d.ts +44 -0
- package/dist/cancel-owned-runs.d.ts.map +1 -0
- package/dist/cancel-owned-runs.js +35 -0
- package/dist/cancel-owned-runs.js.map +1 -0
- package/dist/compat.d.ts +22 -0
- package/dist/compat.d.ts.map +1 -0
- package/dist/compat.js +17 -0
- package/dist/compat.js.map +1 -0
- package/dist/component-catalog.d.ts +74 -0
- package/dist/component-catalog.d.ts.map +1 -0
- package/dist/component-catalog.js +74 -0
- package/dist/component-catalog.js.map +1 -0
- package/dist/connectors.d.ts +165 -0
- package/dist/connectors.d.ts.map +1 -0
- package/dist/connectors.js +474 -0
- package/dist/connectors.js.map +1 -0
- package/dist/daemon-status.d.ts +72 -0
- package/dist/daemon-status.d.ts.map +1 -0
- package/dist/daemon-status.js +60 -0
- package/dist/daemon-status.js.map +1 -0
- package/dist/db-ops.d.ts +116 -0
- package/dist/db-ops.d.ts.map +1 -0
- package/dist/db-ops.js +191 -0
- package/dist/db-ops.js.map +1 -0
- package/dist/delegated-tools.d.ts +46 -0
- package/dist/delegated-tools.d.ts.map +1 -0
- package/dist/delegated-tools.js +155 -0
- package/dist/delegated-tools.js.map +1 -0
- package/dist/express/run-stream.d.ts +15 -0
- package/dist/express/run-stream.d.ts.map +1 -0
- package/dist/express/run-stream.js +11 -0
- package/dist/express/run-stream.js.map +1 -0
- package/dist/express-index.d.ts +32 -0
- package/dist/express-index.d.ts.map +1 -0
- package/dist/express-index.js +14 -0
- package/dist/express-index.js.map +1 -0
- package/dist/fastify/adapter.d.ts +31 -0
- package/dist/fastify/adapter.d.ts.map +1 -0
- package/dist/fastify/adapter.js +64 -0
- package/dist/fastify/adapter.js.map +1 -0
- package/dist/fastify/agents.d.ts +13 -0
- package/dist/fastify/agents.d.ts.map +1 -0
- package/dist/fastify/agents.js +7 -0
- package/dist/fastify/agents.js.map +1 -0
- package/dist/fastify/api-security-middleware.d.ts +64 -0
- package/dist/fastify/api-security-middleware.d.ts.map +1 -0
- package/dist/fastify/api-security-middleware.js +139 -0
- package/dist/fastify/api-security-middleware.js.map +1 -0
- package/dist/fastify/compat.d.ts +22 -0
- package/dist/fastify/compat.d.ts.map +1 -0
- package/dist/fastify/compat.js +16 -0
- package/dist/fastify/compat.js.map +1 -0
- package/dist/fastify/daemon-status.d.ts +22 -0
- package/dist/fastify/daemon-status.d.ts.map +1 -0
- package/dist/fastify/daemon-status.js +9 -0
- package/dist/fastify/daemon-status.js.map +1 -0
- package/dist/fastify/host-tools.d.ts +13 -0
- package/dist/fastify/host-tools.d.ts.map +1 -0
- package/dist/fastify/host-tools.js +8 -0
- package/dist/fastify/host-tools.js.map +1 -0
- package/dist/fastify/index.d.ts +36 -0
- package/dist/fastify/index.d.ts.map +1 -0
- package/dist/fastify/index.js +18 -0
- package/dist/fastify/index.js.map +1 -0
- package/dist/fastify/local-daemon-request.d.ts +43 -0
- package/dist/fastify/local-daemon-request.d.ts.map +1 -0
- package/dist/fastify/local-daemon-request.js +155 -0
- package/dist/fastify/local-daemon-request.js.map +1 -0
- package/dist/fastify/origin.d.ts +21 -0
- package/dist/fastify/origin.d.ts.map +1 -0
- package/dist/fastify/origin.js +14 -0
- package/dist/fastify/origin.js.map +1 -0
- package/dist/fastify/request.d.ts +20 -0
- package/dist/fastify/request.d.ts.map +1 -0
- package/dist/fastify/request.js +25 -0
- package/dist/fastify/request.js.map +1 -0
- package/dist/fastify/response.d.ts +20 -0
- package/dist/fastify/response.d.ts.map +1 -0
- package/dist/fastify/response.js +41 -0
- package/dist/fastify/response.js.map +1 -0
- package/dist/fastify/route-registration-guard.d.ts +70 -0
- package/dist/fastify/route-registration-guard.d.ts.map +1 -0
- package/dist/fastify/route-registration-guard.js +69 -0
- package/dist/fastify/route-registration-guard.js.map +1 -0
- package/dist/fastify/run-stream.d.ts +18 -0
- package/dist/fastify/run-stream.d.ts.map +1 -0
- package/dist/fastify/run-stream.js +10 -0
- package/dist/fastify/run-stream.js.map +1 -0
- package/dist/fastify/runs.d.ts +17 -0
- package/dist/fastify/runs.d.ts.map +1 -0
- package/dist/fastify/runs.js +33 -0
- package/dist/fastify/runs.js.map +1 -0
- package/dist/frontend-control.d.ts +131 -0
- package/dist/frontend-control.d.ts.map +1 -0
- package/dist/frontend-control.js +77 -0
- package/dist/frontend-control.js.map +1 -0
- package/dist/frontend-sessions.d.ts +100 -0
- package/dist/frontend-sessions.d.ts.map +1 -0
- package/dist/frontend-sessions.js +180 -0
- package/dist/frontend-sessions.js.map +1 -0
- package/dist/health.d.ts +91 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +53 -0
- package/dist/health.js.map +1 -0
- package/dist/host-tools.d.ts +174 -0
- package/dist/host-tools.d.ts.map +1 -0
- package/dist/host-tools.js +338 -0
- package/dist/host-tools.js.map +1 -0
- package/dist/index.d.ts +86 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/local-daemon-request.d.ts +44 -0
- package/dist/local-daemon-request.d.ts.map +1 -0
- package/dist/local-daemon-request.js +145 -0
- package/dist/local-daemon-request.js.map +1 -0
- package/dist/media.d.ts +131 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.js +352 -0
- package/dist/media.js.map +1 -0
- package/dist/memory.d.ts +230 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +331 -0
- package/dist/memory.js.map +1 -0
- package/dist/model-proxy.d.ts +45 -0
- package/dist/model-proxy.d.ts.map +1 -0
- package/dist/model-proxy.js +619 -0
- package/dist/model-proxy.js.map +1 -0
- package/dist/origin-validation.d.ts +64 -0
- package/dist/origin-validation.d.ts.map +1 -0
- package/dist/origin-validation.js +226 -0
- package/dist/origin-validation.js.map +1 -0
- package/dist/origin.d.ts +32 -0
- package/dist/origin.d.ts.map +1 -0
- package/dist/origin.js +14 -0
- package/dist/origin.js.map +1 -0
- package/dist/pack-http.d.ts +30 -0
- package/dist/pack-http.d.ts.map +1 -0
- package/dist/pack-http.js +12 -0
- package/dist/pack-http.js.map +1 -0
- package/dist/raw-sse.d.ts +44 -0
- package/dist/raw-sse.d.ts.map +1 -0
- package/dist/raw-sse.js +93 -0
- package/dist/raw-sse.js.map +1 -0
- package/dist/remote-run-events.d.ts +66 -0
- package/dist/remote-run-events.d.ts.map +1 -0
- package/dist/remote-run-events.js +230 -0
- package/dist/remote-run-events.js.map +1 -0
- package/dist/request.d.ts +19 -0
- package/dist/request.d.ts.map +1 -0
- package/dist/request.js +25 -0
- package/dist/request.js.map +1 -0
- package/dist/research.d.ts +42 -0
- package/dist/research.d.ts.map +1 -0
- package/dist/research.js +316 -0
- package/dist/research.js.map +1 -0
- package/dist/response.d.ts +14 -0
- package/dist/response.d.ts.map +1 -0
- package/dist/response.js +45 -0
- package/dist/response.js.map +1 -0
- package/dist/route-manifest.d.ts +31 -0
- package/dist/route-manifest.d.ts.map +1 -0
- package/dist/route-manifest.js +103 -0
- package/dist/route-manifest.js.map +1 -0
- package/dist/route-registration-guard.d.ts +65 -0
- package/dist/route-registration-guard.d.ts.map +1 -0
- package/dist/route-registration-guard.js +71 -0
- package/dist/route-registration-guard.js.map +1 -0
- package/dist/routines.d.ts +114 -0
- package/dist/routines.d.ts.map +1 -0
- package/dist/routines.js +320 -0
- package/dist/routines.js.map +1 -0
- package/dist/run-stream.d.ts +60 -0
- package/dist/run-stream.d.ts.map +1 -0
- package/dist/run-stream.js +108 -0
- package/dist/run-stream.js.map +1 -0
- package/dist/runs.d.ts +79 -0
- package/dist/runs.d.ts.map +1 -0
- package/dist/runs.js +232 -0
- package/dist/runs.js.map +1 -0
- package/dist/sse.d.ts +139 -0
- package/dist/sse.d.ts.map +1 -0
- package/dist/sse.js +157 -0
- package/dist/sse.js.map +1 -0
- package/dist/terminals.d.ts +125 -0
- package/dist/terminals.d.ts.map +1 -0
- package/dist/terminals.js +349 -0
- package/dist/terminals.js.map +1 -0
- package/dist/tool-catalog.d.ts +68 -0
- package/dist/tool-catalog.d.ts.map +1 -0
- package/dist/tool-catalog.js +68 -0
- package/dist/tool-catalog.js.map +1 -0
- package/dist/types.d.ts +58 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/workspace-root.d.ts +69 -0
- package/dist/workspace-root.d.ts.map +1 -0
- package/dist/workspace-root.js +63 -0
- package/dist/workspace-root.js.map +1 -0
- package/dist/xai.d.ts +86 -0
- package/dist/xai.d.ts.map +1 -0
- package/dist/xai.js +668 -0
- package/dist/xai.js.map +1 -0
- package/package.json +58 -0
package/dist/health.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { createApiError } from '@jini-ai/protocol';
|
|
2
|
+
import { defineJsonRoute, mountJsonRoute } from './adapter.js';
|
|
3
|
+
import { err, ok } from './types.js';
|
|
4
|
+
async function defaultCheckReadiness() {
|
|
5
|
+
return { ok: true, checks: {} };
|
|
6
|
+
}
|
|
7
|
+
function livenessRoute(path) {
|
|
8
|
+
return defineJsonRoute({
|
|
9
|
+
method: 'get',
|
|
10
|
+
path,
|
|
11
|
+
parse: () => ok(undefined),
|
|
12
|
+
handle: async (_input, deps) => ok({ ok: true, version: await deps.getVersion() }),
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
function readinessRoute(path) {
|
|
16
|
+
return defineJsonRoute({
|
|
17
|
+
method: 'get',
|
|
18
|
+
path,
|
|
19
|
+
parse: () => ok(undefined),
|
|
20
|
+
handle: async (_input, deps) => {
|
|
21
|
+
const checkReadiness = deps.checkReadiness ?? defaultCheckReadiness;
|
|
22
|
+
const [result, version] = await Promise.all([checkReadiness(), deps.getVersion()]);
|
|
23
|
+
if (!result.ok) {
|
|
24
|
+
return err(createApiError('SERVICE_UNAVAILABLE', 'service not ready', { details: { checks: result.checks } }));
|
|
25
|
+
}
|
|
26
|
+
return ok({ ok: true, ready: true, version, checks: result.checks });
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
function versionRoute(path) {
|
|
31
|
+
return defineJsonRoute({
|
|
32
|
+
method: 'get',
|
|
33
|
+
path,
|
|
34
|
+
parse: () => ok(undefined),
|
|
35
|
+
handle: async (_input, deps) => ok({ version: await deps.getVersion() }),
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
export const healthRoute = livenessRoute('/health');
|
|
39
|
+
export const apiHealthRoute = livenessRoute('/api/health');
|
|
40
|
+
export const readyRoute = readinessRoute('/ready');
|
|
41
|
+
export const apiReadyRoute = readinessRoute('/api/ready');
|
|
42
|
+
export const versionInfoRoute = versionRoute('/version');
|
|
43
|
+
export const apiVersionInfoRoute = versionRoute('/api/version');
|
|
44
|
+
/** Mounts all six health/readiness/version routes on `app`. Call this before installing `express.json()`/the bearer-auth/origin-guard middleware — see module doc. */
|
|
45
|
+
export function registerHealthRoutes(app, deps, adapter) {
|
|
46
|
+
mountJsonRoute(app, healthRoute, deps, adapter);
|
|
47
|
+
mountJsonRoute(app, apiHealthRoute, deps, adapter);
|
|
48
|
+
mountJsonRoute(app, readyRoute, deps, adapter);
|
|
49
|
+
mountJsonRoute(app, apiReadyRoute, deps, adapter);
|
|
50
|
+
mountJsonRoute(app, versionInfoRoute, deps, adapter);
|
|
51
|
+
mountJsonRoute(app, apiVersionInfoRoute, deps, adapter);
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module host-tools
|
|
3
|
+
*
|
|
4
|
+
* Generic "open a working directory in a local host tool" surface, ported
|
|
5
|
+
* from the routes-classification table's `host-tools.ts` MIXED row (see
|
|
6
|
+
* `source-map.md`): the editor catalogue, `$PATH`/mac-bundle probing, and
|
|
7
|
+
* guarded detached-spawn machinery have zero OD dependency and are ported
|
|
8
|
+
* here in full. `GET /api/editors` (which uses solely this machinery) was
|
|
9
|
+
* mounted first; `POST /api/resources/:resourceRef/open-in` (OD's `POST
|
|
10
|
+
* /api/projects/:id/open-in`) is now ported too, now that a generic
|
|
11
|
+
* workspace-root port exists (`workspace-root.ts`) to stand in for OD's
|
|
12
|
+
* `projectStore.getProject`/`projectFiles.resolveProjectDir` — see that
|
|
13
|
+
* route's own doc below for the exact mapping.
|
|
14
|
+
*
|
|
15
|
+
* The probing functions take an injectable `HostToolProbeEnv` (filesystem
|
|
16
|
+
* `access`, `env`, `platform`) rather than reading `process.env`/`fs`
|
|
17
|
+
* directly, so every platform/found/missing branch is exercisable from a
|
|
18
|
+
* single-OS test runner without touching the real filesystem.
|
|
19
|
+
*/
|
|
20
|
+
import { spawn as nodeSpawn } from 'node:child_process';
|
|
21
|
+
import type { Express } from 'express';
|
|
22
|
+
import { type AdapterContext } from './adapter.js';
|
|
23
|
+
import { type WorkspaceRootResolver } from './workspace-root.js';
|
|
24
|
+
export type RealPlatform = 'darwin' | 'win32' | 'linux';
|
|
25
|
+
export type Platform = RealPlatform | 'unknown';
|
|
26
|
+
export interface CatalogueEntry {
|
|
27
|
+
readonly id: string;
|
|
28
|
+
readonly label: string;
|
|
29
|
+
readonly icon: string;
|
|
30
|
+
/** CLI shim name to probe on `$PATH`. Mutually exclusive in practice with `macOpenBundle`, though both may be set as a fallback pair. */
|
|
31
|
+
readonly command?: string;
|
|
32
|
+
readonly commandArgs?: (workingDir: string) => string[];
|
|
33
|
+
/** macOS-only fallback: when the CLI shim is missing, look for an app bundle by name and launch it via `open -a "<name>"`. */
|
|
34
|
+
readonly macOpenBundle?: string | readonly string[];
|
|
35
|
+
readonly macOpenArgs?: (bundleName: string, workingDir: string) => string[];
|
|
36
|
+
readonly platforms?: readonly RealPlatform[];
|
|
37
|
+
readonly excludedPlatforms?: readonly RealPlatform[];
|
|
38
|
+
}
|
|
39
|
+
/** The cross-platform-staple + macOS-bundle editor/tool catalogue, unchanged from the origin. */
|
|
40
|
+
export declare const CATALOGUE: readonly CatalogueEntry[];
|
|
41
|
+
/** Maps Node's `process.platform` to this module's tri-state `Platform`; anything else (aix, freebsd, sunos, ...) is `'unknown'`. */
|
|
42
|
+
export declare function currentPlatform(nodePlatform?: NodeJS.Platform): Platform;
|
|
43
|
+
export declare function applicableForPlatform(entry: CatalogueEntry, platform: Platform): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Everything the probing functions below need from the outside world, gathered into one
|
|
46
|
+
* injectable value. Production code gets {@link defaultProbeEnv}; tests inject a fake `access`
|
|
47
|
+
* (so "found"/"missing" is a table, not a real filesystem) and any `platform`/`env` they want to
|
|
48
|
+
* exercise, independent of the OS actually running the test.
|
|
49
|
+
*/
|
|
50
|
+
export interface HostToolProbeEnv {
|
|
51
|
+
readonly access: (path: string, mode: number) => Promise<void>;
|
|
52
|
+
readonly env: Readonly<Record<string, string | undefined>>;
|
|
53
|
+
readonly platform: Platform;
|
|
54
|
+
}
|
|
55
|
+
export declare function defaultProbeEnv(): HostToolProbeEnv;
|
|
56
|
+
/**
|
|
57
|
+
* `$PATH` directories to probe, plus the common macOS/Linux locations a login shell would have
|
|
58
|
+
* that a GUI-launched daemon's thin inherited `PATH` often lacks (no `/usr/local/bin`, no
|
|
59
|
+
* `/opt/homebrew/bin`) — without these, CLI shims installed via an editor's "Install command"
|
|
60
|
+
* action are invisible to a daemon launched by double-clicking an app bundle.
|
|
61
|
+
*/
|
|
62
|
+
export declare function pathDirs(probeEnv: HostToolProbeEnv): string[];
|
|
63
|
+
export declare function probeCommandOnPath(command: string, probeEnv: HostToolProbeEnv): Promise<string | null>;
|
|
64
|
+
export declare function probeMacBundle(name: string | readonly string[], probeEnv: HostToolProbeEnv): Promise<{
|
|
65
|
+
name: string;
|
|
66
|
+
path: string;
|
|
67
|
+
} | null>;
|
|
68
|
+
/**
|
|
69
|
+
* A discriminated union rather than one shape with optional fields: `resolvedPath`/`launch` are
|
|
70
|
+
* only ever set together (both "found" branches below set the pair; the "not found" branch sets
|
|
71
|
+
* neither), so the type says that directly instead of leaving `resolvedPath` reachable-but-absent
|
|
72
|
+
* when `available` is `false`.
|
|
73
|
+
*/
|
|
74
|
+
type ResolvedEntry = {
|
|
75
|
+
readonly available: true;
|
|
76
|
+
readonly resolvedPath: string;
|
|
77
|
+
readonly launch: {
|
|
78
|
+
readonly command: string;
|
|
79
|
+
readonly argsForDir: (workingDir: string) => string[];
|
|
80
|
+
};
|
|
81
|
+
} | {
|
|
82
|
+
readonly available: false;
|
|
83
|
+
};
|
|
84
|
+
export declare function resolveEntry(entry: CatalogueEntry, probeEnv?: HostToolProbeEnv): Promise<ResolvedEntry>;
|
|
85
|
+
export interface HostToolLaunchPlan {
|
|
86
|
+
readonly available: boolean;
|
|
87
|
+
readonly resolvedPath?: string;
|
|
88
|
+
readonly command?: string;
|
|
89
|
+
readonly args?: string[];
|
|
90
|
+
}
|
|
91
|
+
/** Resolves the concrete `{command, args}` a caller would spawn to open `workingDir` in `editorId`, or `available: false` if that tool isn't installed/known. */
|
|
92
|
+
export declare function resolveHostToolLaunchPlan(editorId: string, workingDir: string, probeEnv?: HostToolProbeEnv): Promise<HostToolLaunchPlan>;
|
|
93
|
+
export type LaunchHostToolResult = {
|
|
94
|
+
readonly ok: true;
|
|
95
|
+
} | {
|
|
96
|
+
readonly ok: false;
|
|
97
|
+
readonly error: string;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Spawns a detached host-tool launch and waits for the OS to confirm it actually started. Node
|
|
101
|
+
* emits `'spawn'` once the child is running and `'error'` when the launch is refused (missing
|
|
102
|
+
* binary, quarantine, EACCES) — `'error'` arrives on a later tick, so this must be awaited before
|
|
103
|
+
* a caller replies, otherwise a launch the OS rejected would be reported as success (origin's
|
|
104
|
+
* #3871).
|
|
105
|
+
*
|
|
106
|
+
* Deliberately never passes `shell: true`: on Windows that would route the launch through
|
|
107
|
+
* `cmd.exe`, which shell-interprets args — and one of them is a caller-supplied directory path,
|
|
108
|
+
* so a path containing `&`/`|`/`^`/`>` etc. would inject commands. `command` is already resolved
|
|
109
|
+
* to an absolute path (including `.exe`/`.cmd`), so it's routed through `createCommandInvocation`
|
|
110
|
+
* (`@jini-ai/platform`), which runs a `.cmd`/`.bat` via `cmd.exe` with
|
|
111
|
+
* `CommandLineToArgvW`-safe verbatim args and everything else directly — no shell, no
|
|
112
|
+
* metacharacter interpretation.
|
|
113
|
+
*/
|
|
114
|
+
export declare function launchHostTool(command: string, args: string[], spawnImpl?: typeof nodeSpawn): Promise<LaunchHostToolResult>;
|
|
115
|
+
export interface HostEditor {
|
|
116
|
+
readonly id: string;
|
|
117
|
+
readonly label: string;
|
|
118
|
+
readonly icon: string;
|
|
119
|
+
readonly available: boolean;
|
|
120
|
+
readonly resolvedPath?: string;
|
|
121
|
+
readonly platforms?: readonly RealPlatform[];
|
|
122
|
+
}
|
|
123
|
+
export interface HostEditorsResponse {
|
|
124
|
+
readonly editors: readonly HostEditor[];
|
|
125
|
+
readonly platform: Platform;
|
|
126
|
+
}
|
|
127
|
+
/** Probes every catalogue entry applicable to the current platform and reports which are actually installed. */
|
|
128
|
+
export declare function listAvailableEditors(probeEnv?: HostToolProbeEnv): Promise<HostEditorsResponse>;
|
|
129
|
+
/** `GET /api/editors` — lists the host-tool catalogue applicable to this platform with live availability. */
|
|
130
|
+
export declare const hostEditorsRoute: import("./types.js").JsonRouteSpec<void, HostEditorsResponse, Record<string, never>>;
|
|
131
|
+
export interface OpenResourceInEditorRequest {
|
|
132
|
+
readonly resourceRef: string;
|
|
133
|
+
readonly editorId: string;
|
|
134
|
+
readonly detail?: string;
|
|
135
|
+
}
|
|
136
|
+
export interface OpenResourceInEditorResponse {
|
|
137
|
+
readonly ok: true;
|
|
138
|
+
readonly editorId: string;
|
|
139
|
+
readonly path: string;
|
|
140
|
+
}
|
|
141
|
+
/** Everything `POST /api/resources/:resourceRef/open-in` needs from the host. */
|
|
142
|
+
export interface HostToolsOpenInDeps {
|
|
143
|
+
/** Resolves a resource reference to a filesystem working directory. Defaults to {@link denyAllWorkspaceRoots} — a host that never wires a real resolver gets a 404 on every call, never a guessed path (see `workspace-root.ts`). */
|
|
144
|
+
readonly resolveRoot?: WorkspaceRootResolver;
|
|
145
|
+
readonly probeEnv?: HostToolProbeEnv;
|
|
146
|
+
readonly spawnImpl?: typeof nodeSpawn;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* `POST /api/resources/:resourceRef/open-in` — launches `editorId` (from
|
|
150
|
+
* {@link CATALOGUE}) rooted at the working directory `deps.resolveRoot`
|
|
151
|
+
* resolves for `resourceRef`. Ported from OD's `POST
|
|
152
|
+
* /api/projects/:id/open-in`: `projectId` generalizes to the opaque
|
|
153
|
+
* `resourceRef` this package already uses (`active-context.ts`,
|
|
154
|
+
* `cancel-owned-runs.ts`), and `getProject`/`resolveProjectDir` generalize
|
|
155
|
+
* to the injected {@link WorkspaceRootResolver}. `PROJECT_NOT_FOUND` (an
|
|
156
|
+
* OD-product-only code with no `@jini-ai/protocol` equivalent — see
|
|
157
|
+
* `response.ts`'s file-map note) becomes a generic `NOT_FOUND` when the
|
|
158
|
+
* resolver denies. `EDITOR_NOT_AVAILABLE` (OD's 409 for "installed catalogue
|
|
159
|
+
* entry, but not found on this machine") becomes `CONFLICT`, which already
|
|
160
|
+
* maps to 409 in this package's `ERROR_STATUS_BY_CODE`.
|
|
161
|
+
*
|
|
162
|
+
* The launch-failure message is returned to the caller verbatim (unlike
|
|
163
|
+
* `runs.ts`'s SEC-005 redaction of internal agent-run errors): this is a
|
|
164
|
+
* same-origin, explicitly-consented, single local action the caller just
|
|
165
|
+
* asked for (open the tool it named, at the directory it's authorized to
|
|
166
|
+
* open) — the underlying spawn error (e.g. a quarantined/missing binary) is
|
|
167
|
+
* operationally useful to the caller and does not cross a trust boundary
|
|
168
|
+
* the way an internal agent-run exception can.
|
|
169
|
+
*/
|
|
170
|
+
export declare const openResourceInEditorRoute: import("./types.js").JsonRouteSpec<OpenResourceInEditorRequest, OpenResourceInEditorResponse, HostToolsOpenInDeps>;
|
|
171
|
+
/** Mounts `GET /api/editors` and `POST /api/resources/:resourceRef/open-in` on `app`. A pack's `http(app, services)` calls this directly. */
|
|
172
|
+
export declare function registerHostToolsRoutes(app: Express, adapter: AdapterContext, openInDeps?: HostToolsOpenInDeps): void;
|
|
173
|
+
export {};
|
|
174
|
+
//# sourceMappingURL=host-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-tools.d.ts","sourceRoot":"","sources":["../src/host-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module host-tools
|
|
3
|
+
*
|
|
4
|
+
* Generic "open a working directory in a local host tool" surface, ported
|
|
5
|
+
* from the routes-classification table's `host-tools.ts` MIXED row (see
|
|
6
|
+
* `source-map.md`): the editor catalogue, `$PATH`/mac-bundle probing, and
|
|
7
|
+
* guarded detached-spawn machinery have zero OD dependency and are ported
|
|
8
|
+
* here in full. `GET /api/editors` (which uses solely this machinery) was
|
|
9
|
+
* mounted first; `POST /api/resources/:resourceRef/open-in` (OD's `POST
|
|
10
|
+
* /api/projects/:id/open-in`) is now ported too, now that a generic
|
|
11
|
+
* workspace-root port exists (`workspace-root.ts`) to stand in for OD's
|
|
12
|
+
* `projectStore.getProject`/`projectFiles.resolveProjectDir` — see that
|
|
13
|
+
* route's own doc below for the exact mapping.
|
|
14
|
+
*
|
|
15
|
+
* The probing functions take an injectable `HostToolProbeEnv` (filesystem
|
|
16
|
+
* `access`, `env`, `platform`) rather than reading `process.env`/`fs`
|
|
17
|
+
* directly, so every platform/found/missing branch is exercisable from a
|
|
18
|
+
* single-OS test runner without touching the real filesystem.
|
|
19
|
+
*/
|
|
20
|
+
import { spawn as nodeSpawn } from 'node:child_process';
|
|
21
|
+
import { access as fsAccess, constants as fsConstants } from 'node:fs/promises';
|
|
22
|
+
import { createCommandInvocation } from '@jini-ai/platform';
|
|
23
|
+
import { createApiError } from '@jini-ai/protocol';
|
|
24
|
+
import { defineJsonRoute, mountJsonRoute } from './adapter.js';
|
|
25
|
+
import { validationError } from './request.js';
|
|
26
|
+
import { err, ok } from './types.js';
|
|
27
|
+
import { denyAllWorkspaceRoots, resolveWorkspaceRoot, WorkspaceRootDeniedError } from './workspace-root.js';
|
|
28
|
+
const MAC_OPEN_COMMAND = '/usr/bin/open';
|
|
29
|
+
/** The cross-platform-staple + macOS-bundle editor/tool catalogue, unchanged from the origin. */
|
|
30
|
+
export const CATALOGUE = [
|
|
31
|
+
{ id: 'cursor', label: 'Cursor', icon: 'sparkles', command: 'cursor', macOpenBundle: 'Cursor' },
|
|
32
|
+
{ id: 'vscode', label: 'VS Code', icon: 'file-code', command: 'code', macOpenBundle: 'Visual Studio Code' },
|
|
33
|
+
{ id: 'windsurf', label: 'Windsurf', icon: 'sparkles', command: 'windsurf', macOpenBundle: 'Windsurf' },
|
|
34
|
+
{ id: 'zed', label: 'Zed', icon: 'edit', command: 'zed', macOpenBundle: 'Zed' },
|
|
35
|
+
{ id: 'qoder', label: 'Qoder', icon: 'sparkles', command: 'qoder', macOpenBundle: ['Qoder', 'QoderWork'] },
|
|
36
|
+
{ id: 'antigravity', label: 'Antigravity', icon: 'orbit', command: 'antigravity', macOpenBundle: ['Antigravity', 'Google Antigravity'] },
|
|
37
|
+
{ id: 'webstorm', label: 'WebStorm', icon: 'edit', command: 'webstorm', macOpenBundle: 'WebStorm' },
|
|
38
|
+
{ id: 'idea', label: 'IntelliJ IDEA', icon: 'edit', command: 'idea', macOpenBundle: 'IntelliJ IDEA' },
|
|
39
|
+
{ id: 'xcode', label: 'Xcode', icon: 'file-code', macOpenBundle: ['Xcode', 'Xcode-beta', 'Xcode Beta'], platforms: ['darwin'] },
|
|
40
|
+
{ id: 'finder', label: 'Finder', icon: 'folder', command: MAC_OPEN_COMMAND, commandArgs: (workingDir) => ['-R', workingDir], platforms: ['darwin'] },
|
|
41
|
+
{ id: 'explorer', label: 'Explorer', icon: 'folder', command: 'explorer', platforms: ['win32'] },
|
|
42
|
+
{ id: 'file-manager', label: 'File Manager', icon: 'folder', command: 'xdg-open', platforms: ['linux'] },
|
|
43
|
+
{ id: 'terminal', label: 'Terminal', icon: 'sliders', macOpenBundle: 'Terminal', platforms: ['darwin'] },
|
|
44
|
+
// darwin-only: Warp cold-starts ignore the cwd argument on win32/linux, so the
|
|
45
|
+
// "open in Warp" UX is broken on those platforms (origin's #4544).
|
|
46
|
+
{ id: 'warp', label: 'Warp', icon: 'sliders', macOpenBundle: 'Warp', platforms: ['darwin'] },
|
|
47
|
+
];
|
|
48
|
+
/** Maps Node's `process.platform` to this module's tri-state `Platform`; anything else (aix, freebsd, sunos, ...) is `'unknown'`. */
|
|
49
|
+
export function currentPlatform(nodePlatform = process.platform) {
|
|
50
|
+
switch (nodePlatform) {
|
|
51
|
+
case 'darwin':
|
|
52
|
+
return 'darwin';
|
|
53
|
+
case 'win32':
|
|
54
|
+
return 'win32';
|
|
55
|
+
case 'linux':
|
|
56
|
+
return 'linux';
|
|
57
|
+
default:
|
|
58
|
+
return 'unknown';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export function applicableForPlatform(entry, platform) {
|
|
62
|
+
if (platform === 'unknown')
|
|
63
|
+
return false;
|
|
64
|
+
if (entry.platforms && !entry.platforms.includes(platform))
|
|
65
|
+
return false;
|
|
66
|
+
if (entry.excludedPlatforms && entry.excludedPlatforms.includes(platform))
|
|
67
|
+
return false;
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
export function defaultProbeEnv() {
|
|
71
|
+
return { access: fsAccess, env: process.env, platform: currentPlatform() };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* `$PATH` directories to probe, plus the common macOS/Linux locations a login shell would have
|
|
75
|
+
* that a GUI-launched daemon's thin inherited `PATH` often lacks (no `/usr/local/bin`, no
|
|
76
|
+
* `/opt/homebrew/bin`) — without these, CLI shims installed via an editor's "Install command"
|
|
77
|
+
* action are invisible to a daemon launched by double-clicking an app bundle.
|
|
78
|
+
*/
|
|
79
|
+
export function pathDirs(probeEnv) {
|
|
80
|
+
const raw = probeEnv.env.PATH ?? '';
|
|
81
|
+
const sep = probeEnv.platform === 'win32' ? ';' : ':';
|
|
82
|
+
const home = probeEnv.env.HOME ?? '';
|
|
83
|
+
const extras = probeEnv.platform === 'darwin'
|
|
84
|
+
? ['/usr/local/bin', '/opt/homebrew/bin', '/usr/bin', '/bin', '/usr/sbin', '/sbin', `${home}/.local/bin`]
|
|
85
|
+
: probeEnv.platform === 'linux'
|
|
86
|
+
? ['/usr/local/bin', '/usr/bin', '/bin', `${home}/.local/bin`]
|
|
87
|
+
: [];
|
|
88
|
+
return [...raw.split(sep), ...extras].filter((dir) => dir.length > 0);
|
|
89
|
+
}
|
|
90
|
+
export async function probeCommandOnPath(command, probeEnv) {
|
|
91
|
+
if (command.includes('/')) {
|
|
92
|
+
try {
|
|
93
|
+
await probeEnv.access(command, fsConstants.X_OK);
|
|
94
|
+
return command;
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const dirs = pathDirs(probeEnv);
|
|
101
|
+
const suffixes = probeEnv.platform === 'win32' ? ['.exe', '.cmd', '.bat', ''] : [''];
|
|
102
|
+
for (const dir of dirs) {
|
|
103
|
+
for (const suffix of suffixes) {
|
|
104
|
+
const candidate = `${dir}/${command}${suffix}`;
|
|
105
|
+
try {
|
|
106
|
+
await probeEnv.access(candidate, fsConstants.X_OK);
|
|
107
|
+
return candidate;
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// not here
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
async function resolveMacOpenCommand(probeEnv) {
|
|
117
|
+
try {
|
|
118
|
+
await probeEnv.access(MAC_OPEN_COMMAND, fsConstants.X_OK);
|
|
119
|
+
return MAC_OPEN_COMMAND;
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return (await probeCommandOnPath('open', probeEnv)) ?? MAC_OPEN_COMMAND;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
export async function probeMacBundle(name, probeEnv) {
|
|
126
|
+
if (probeEnv.platform !== 'darwin')
|
|
127
|
+
return null;
|
|
128
|
+
const names = Array.isArray(name) ? name : [name];
|
|
129
|
+
const home = probeEnv.env.HOME ?? '';
|
|
130
|
+
const candidates = [
|
|
131
|
+
(bundleName) => `/Applications/${bundleName}.app`,
|
|
132
|
+
(bundleName) => `${home}/Applications/${bundleName}.app`,
|
|
133
|
+
(bundleName) => `/System/Applications/${bundleName}.app`,
|
|
134
|
+
(bundleName) => `/System/Applications/Utilities/${bundleName}.app`,
|
|
135
|
+
(bundleName) => `/System/Library/CoreServices/${bundleName}.app`,
|
|
136
|
+
];
|
|
137
|
+
for (const bundleName of names) {
|
|
138
|
+
for (const candidate of candidates) {
|
|
139
|
+
const path = candidate(bundleName);
|
|
140
|
+
try {
|
|
141
|
+
await probeEnv.access(path, fsConstants.R_OK);
|
|
142
|
+
return { name: bundleName, path };
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// not here
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
export async function resolveEntry(entry, probeEnv = defaultProbeEnv()) {
|
|
152
|
+
if (entry.command) {
|
|
153
|
+
const resolved = await probeCommandOnPath(entry.command, probeEnv);
|
|
154
|
+
if (resolved) {
|
|
155
|
+
return {
|
|
156
|
+
available: true,
|
|
157
|
+
resolvedPath: resolved,
|
|
158
|
+
launch: { command: resolved, argsForDir: entry.commandArgs ?? ((workingDir) => [workingDir]) },
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (entry.macOpenBundle && probeEnv.platform === 'darwin') {
|
|
163
|
+
const bundle = await probeMacBundle(entry.macOpenBundle, probeEnv);
|
|
164
|
+
if (bundle) {
|
|
165
|
+
return {
|
|
166
|
+
available: true,
|
|
167
|
+
resolvedPath: bundle.path,
|
|
168
|
+
launch: {
|
|
169
|
+
command: await resolveMacOpenCommand(probeEnv),
|
|
170
|
+
argsForDir: entry.macOpenArgs
|
|
171
|
+
? (workingDir) => entry.macOpenArgs(bundle.name, workingDir)
|
|
172
|
+
: (workingDir) => ['-a', bundle.name, workingDir],
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return { available: false };
|
|
178
|
+
}
|
|
179
|
+
/** Resolves the concrete `{command, args}` a caller would spawn to open `workingDir` in `editorId`, or `available: false` if that tool isn't installed/known. */
|
|
180
|
+
export async function resolveHostToolLaunchPlan(editorId, workingDir, probeEnv = defaultProbeEnv()) {
|
|
181
|
+
const entry = CATALOGUE.find((c) => c.id === editorId);
|
|
182
|
+
if (!entry)
|
|
183
|
+
return { available: false };
|
|
184
|
+
const probe = await resolveEntry(entry, probeEnv);
|
|
185
|
+
if (!probe.available)
|
|
186
|
+
return { available: false };
|
|
187
|
+
return {
|
|
188
|
+
available: true,
|
|
189
|
+
resolvedPath: probe.resolvedPath,
|
|
190
|
+
command: probe.launch.command,
|
|
191
|
+
args: probe.launch.argsForDir(workingDir),
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Spawns a detached host-tool launch and waits for the OS to confirm it actually started. Node
|
|
196
|
+
* emits `'spawn'` once the child is running and `'error'` when the launch is refused (missing
|
|
197
|
+
* binary, quarantine, EACCES) — `'error'` arrives on a later tick, so this must be awaited before
|
|
198
|
+
* a caller replies, otherwise a launch the OS rejected would be reported as success (origin's
|
|
199
|
+
* #3871).
|
|
200
|
+
*
|
|
201
|
+
* Deliberately never passes `shell: true`: on Windows that would route the launch through
|
|
202
|
+
* `cmd.exe`, which shell-interprets args — and one of them is a caller-supplied directory path,
|
|
203
|
+
* so a path containing `&`/`|`/`^`/`>` etc. would inject commands. `command` is already resolved
|
|
204
|
+
* to an absolute path (including `.exe`/`.cmd`), so it's routed through `createCommandInvocation`
|
|
205
|
+
* (`@jini-ai/platform`), which runs a `.cmd`/`.bat` via `cmd.exe` with
|
|
206
|
+
* `CommandLineToArgvW`-safe verbatim args and everything else directly — no shell, no
|
|
207
|
+
* metacharacter interpretation.
|
|
208
|
+
*/
|
|
209
|
+
export function launchHostTool(command, args, spawnImpl = nodeSpawn) {
|
|
210
|
+
return new Promise((resolve) => {
|
|
211
|
+
const invocation = createCommandInvocation({ command, args });
|
|
212
|
+
const child = spawnImpl(invocation.command, invocation.args, {
|
|
213
|
+
detached: true,
|
|
214
|
+
stdio: 'ignore',
|
|
215
|
+
windowsHide: process.platform === 'win32',
|
|
216
|
+
windowsVerbatimArguments: invocation.windowsVerbatimArguments,
|
|
217
|
+
});
|
|
218
|
+
let settled = false;
|
|
219
|
+
child.once('spawn', () => {
|
|
220
|
+
if (settled)
|
|
221
|
+
return;
|
|
222
|
+
settled = true;
|
|
223
|
+
child.unref();
|
|
224
|
+
resolve({ ok: true });
|
|
225
|
+
});
|
|
226
|
+
child.once('error', (spawnError) => {
|
|
227
|
+
if (settled)
|
|
228
|
+
return;
|
|
229
|
+
settled = true;
|
|
230
|
+
resolve({ ok: false, error: spawnError instanceof Error ? spawnError.message : String(spawnError) });
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
/** Probes every catalogue entry applicable to the current platform and reports which are actually installed. */
|
|
235
|
+
export async function listAvailableEditors(probeEnv = defaultProbeEnv()) {
|
|
236
|
+
const filtered = CATALOGUE.filter((entry) => applicableForPlatform(entry, probeEnv.platform));
|
|
237
|
+
const editors = await Promise.all(filtered.map(async (entry) => {
|
|
238
|
+
const probe = await resolveEntry(entry, probeEnv);
|
|
239
|
+
return {
|
|
240
|
+
id: entry.id,
|
|
241
|
+
label: entry.label,
|
|
242
|
+
icon: entry.icon,
|
|
243
|
+
available: probe.available,
|
|
244
|
+
...(probe.available ? { resolvedPath: probe.resolvedPath } : {}),
|
|
245
|
+
...(entry.platforms ? { platforms: entry.platforms } : {}),
|
|
246
|
+
};
|
|
247
|
+
}));
|
|
248
|
+
return { editors, platform: probeEnv.platform };
|
|
249
|
+
}
|
|
250
|
+
/** `GET /api/editors` — lists the host-tool catalogue applicable to this platform with live availability. */
|
|
251
|
+
export const hostEditorsRoute = defineJsonRoute({
|
|
252
|
+
method: 'get',
|
|
253
|
+
path: '/api/editors',
|
|
254
|
+
parse: () => ok(undefined),
|
|
255
|
+
handle: async () => ok(await listAvailableEditors()),
|
|
256
|
+
});
|
|
257
|
+
function isRecord(value) {
|
|
258
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
259
|
+
}
|
|
260
|
+
function parseOpenResourceInEditor(input) {
|
|
261
|
+
const resourceRef = input.params.resourceRef;
|
|
262
|
+
if (typeof resourceRef !== 'string' || resourceRef.length === 0) {
|
|
263
|
+
return err(validationError('resourceRef must be a non-empty path parameter'));
|
|
264
|
+
}
|
|
265
|
+
if (!isRecord(input.body))
|
|
266
|
+
return err(validationError('body must be a JSON object'));
|
|
267
|
+
const editorId = input.body.editorId;
|
|
268
|
+
if (typeof editorId !== 'string' || editorId.length === 0) {
|
|
269
|
+
return err(validationError('editorId is required', [{ path: 'editorId', message: 'required non-empty string' }]));
|
|
270
|
+
}
|
|
271
|
+
const detail = input.body.detail;
|
|
272
|
+
if (detail !== undefined && (typeof detail !== 'string' || detail.length === 0)) {
|
|
273
|
+
return err(validationError('detail must be a non-empty string when provided'));
|
|
274
|
+
}
|
|
275
|
+
return ok({ resourceRef, editorId, ...(detail === undefined ? {} : { detail }) });
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* `POST /api/resources/:resourceRef/open-in` — launches `editorId` (from
|
|
279
|
+
* {@link CATALOGUE}) rooted at the working directory `deps.resolveRoot`
|
|
280
|
+
* resolves for `resourceRef`. Ported from OD's `POST
|
|
281
|
+
* /api/projects/:id/open-in`: `projectId` generalizes to the opaque
|
|
282
|
+
* `resourceRef` this package already uses (`active-context.ts`,
|
|
283
|
+
* `cancel-owned-runs.ts`), and `getProject`/`resolveProjectDir` generalize
|
|
284
|
+
* to the injected {@link WorkspaceRootResolver}. `PROJECT_NOT_FOUND` (an
|
|
285
|
+
* OD-product-only code with no `@jini-ai/protocol` equivalent — see
|
|
286
|
+
* `response.ts`'s file-map note) becomes a generic `NOT_FOUND` when the
|
|
287
|
+
* resolver denies. `EDITOR_NOT_AVAILABLE` (OD's 409 for "installed catalogue
|
|
288
|
+
* entry, but not found on this machine") becomes `CONFLICT`, which already
|
|
289
|
+
* maps to 409 in this package's `ERROR_STATUS_BY_CODE`.
|
|
290
|
+
*
|
|
291
|
+
* The launch-failure message is returned to the caller verbatim (unlike
|
|
292
|
+
* `runs.ts`'s SEC-005 redaction of internal agent-run errors): this is a
|
|
293
|
+
* same-origin, explicitly-consented, single local action the caller just
|
|
294
|
+
* asked for (open the tool it named, at the directory it's authorized to
|
|
295
|
+
* open) — the underlying spawn error (e.g. a quarantined/missing binary) is
|
|
296
|
+
* operationally useful to the caller and does not cross a trust boundary
|
|
297
|
+
* the way an internal agent-run exception can.
|
|
298
|
+
*/
|
|
299
|
+
export const openResourceInEditorRoute = defineJsonRoute({
|
|
300
|
+
method: 'post',
|
|
301
|
+
path: '/api/resources/:resourceRef/open-in',
|
|
302
|
+
requireSameOrigin: true,
|
|
303
|
+
parse: parseOpenResourceInEditor,
|
|
304
|
+
handle: async (input, deps) => {
|
|
305
|
+
const entry = CATALOGUE.find((c) => c.id === input.editorId);
|
|
306
|
+
if (!entry)
|
|
307
|
+
return err(createApiError('BAD_REQUEST', `unknown editor: ${input.editorId}`));
|
|
308
|
+
const probeEnv = deps.probeEnv ?? defaultProbeEnv();
|
|
309
|
+
if (!applicableForPlatform(entry, probeEnv.platform)) {
|
|
310
|
+
return err(createApiError('BAD_REQUEST', `${entry.label} is not available on ${probeEnv.platform}`));
|
|
311
|
+
}
|
|
312
|
+
let resolvedDir;
|
|
313
|
+
try {
|
|
314
|
+
resolvedDir = await resolveWorkspaceRoot({ resourceRef: input.resourceRef, ...(input.detail === undefined ? {} : { detail: input.detail }) }, { resolver: deps.resolveRoot ?? denyAllWorkspaceRoots });
|
|
315
|
+
}
|
|
316
|
+
catch (error) {
|
|
317
|
+
if (error instanceof WorkspaceRootDeniedError) {
|
|
318
|
+
return err(createApiError('NOT_FOUND', `resource "${input.resourceRef}" was not found`));
|
|
319
|
+
}
|
|
320
|
+
throw error;
|
|
321
|
+
}
|
|
322
|
+
const launchPlan = await resolveHostToolLaunchPlan(input.editorId, resolvedDir, probeEnv);
|
|
323
|
+
if (!launchPlan.available || !launchPlan.command || !launchPlan.args) {
|
|
324
|
+
return err(createApiError('CONFLICT', `${entry.label} is not installed`));
|
|
325
|
+
}
|
|
326
|
+
const launch = await launchHostTool(launchPlan.command, launchPlan.args, deps.spawnImpl ?? nodeSpawn);
|
|
327
|
+
if (!launch.ok) {
|
|
328
|
+
return err(createApiError('INTERNAL_ERROR', `failed to launch ${entry.label}: ${launch.error}`));
|
|
329
|
+
}
|
|
330
|
+
return ok({ ok: true, editorId: input.editorId, path: resolvedDir });
|
|
331
|
+
},
|
|
332
|
+
});
|
|
333
|
+
/** Mounts `GET /api/editors` and `POST /api/resources/:resourceRef/open-in` on `app`. A pack's `http(app, services)` calls this directly. */
|
|
334
|
+
export function registerHostToolsRoutes(app, adapter, openInDeps = {}) {
|
|
335
|
+
mountJsonRoute(app, hostEditorsRoute, {}, adapter);
|
|
336
|
+
mountJsonRoute(app, openResourceInEditorRoute, openInDeps, adapter);
|
|
337
|
+
}
|
|
338
|
+
//# sourceMappingURL=host-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-tools.js","sourceRoot":"","sources":["../src/host-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,MAAM,IAAI,QAAQ,EAAE,SAAS,IAAI,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,cAAc,EAAuB,MAAM,cAAc,CAAC;AACpF,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,GAAG,EAAE,EAAE,EAAuC,MAAM,YAAY,CAAC;AAC1E,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,wBAAwB,EAA8B,MAAM,qBAAqB,CAAC;AAmBxI,MAAM,gBAAgB,GAAG,eAAe,CAAC;AAEzC,iGAAiG;AACjG,MAAM,CAAC,MAAM,SAAS,GAA8B;IAClD,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE;IAC/F,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,oBAAoB,EAAE;IAC3G,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE;IACvG,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE;IAC/E,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE;IAC1G,EAAE,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC,aAAa,EAAE,oBAAoB,CAAC,EAAE;IACxI,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE;IACnG,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,eAAe,EAAE;IACrG,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,aAAa,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,YAAY,CAAC,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE;IAC/H,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE;IACpJ,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,OAAO,CAAC,EAAE;IAChG,EAAE,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,OAAO,CAAC,EAAE;IACxG,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE;IACxG,+EAA+E;IAC/E,mEAAmE;IACnE,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE;CAC7F,CAAC;AAEF,qIAAqI;AACrI,MAAM,UAAU,eAAe,CAAC,eAAgC,OAAO,CAAC,QAAQ;IAC9E,QAAQ,YAAY,EAAE,CAAC;QACrB,KAAK,QAAQ;YACX,OAAO,QAAQ,CAAC;QAClB,KAAK,OAAO;YACV,OAAO,OAAO,CAAC;QACjB,KAAK,OAAO;YACV,OAAO,OAAO,CAAC;QACjB;YACE,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAqB,EAAE,QAAkB;IAC7E,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACzC,IAAI,KAAK,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IACzE,IAAI,KAAK,CAAC,iBAAiB,IAAI,KAAK,CAAC,iBAAiB,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IACxF,OAAO,IAAI,CAAC;AACd,CAAC;AAcD,MAAM,UAAU,eAAe;IAC7B,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,QAAQ,EAAE,eAAe,EAAE,EAAE,CAAC;AAC7E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,QAA0B;IACjD,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;IACpC,MAAM,GAAG,GAAG,QAAQ,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IACtD,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;IACrC,MAAM,MAAM,GACV,QAAQ,CAAC,QAAQ,KAAK,QAAQ;QAC5B,CAAC,CAAC,CAAC,gBAAgB,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,IAAI,aAAa,CAAC;QACzG,CAAC,CAAC,QAAQ,CAAC,QAAQ,KAAK,OAAO;YAC7B,CAAC,CAAC,CAAC,gBAAgB,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,IAAI,aAAa,CAAC;YAC9D,CAAC,CAAC,EAAE,CAAC;IACX,OAAO,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,OAAe,EAAE,QAA0B;IAClF,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,IAAI,CAAC;YACH,MAAM,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;YACjD,OAAO,OAAO,CAAC;QACjB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAChC,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACrF,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC9B,MAAM,SAAS,GAAG,GAAG,GAAG,IAAI,OAAO,GAAG,MAAM,EAAE,CAAC;YAC/C,IAAI,CAAC;gBACH,MAAM,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;gBACnD,OAAO,SAAS,CAAC;YACnB,CAAC;YAAC,MAAM,CAAC;gBACP,WAAW;YACb,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,KAAK,UAAU,qBAAqB,CAAC,QAA0B;IAC7D,IAAI,CAAC;QACH,MAAM,QAAQ,CAAC,MAAM,CAAC,gBAAgB,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;QAC1D,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,MAAM,kBAAkB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,IAAI,gBAAgB,CAAC;IAC1E,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAAgC,EAChC,QAA0B;IAE1B,IAAI,QAAQ,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAChD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;IACrC,MAAM,UAAU,GAAG;QACjB,CAAC,UAAkB,EAAE,EAAE,CAAC,iBAAiB,UAAU,MAAM;QACzD,CAAC,UAAkB,EAAE,EAAE,CAAC,GAAG,IAAI,iBAAiB,UAAU,MAAM;QAChE,CAAC,UAAkB,EAAE,EAAE,CAAC,wBAAwB,UAAU,MAAM;QAChE,CAAC,UAAkB,EAAE,EAAE,CAAC,kCAAkC,UAAU,MAAM;QAC1E,CAAC,UAAkB,EAAE,EAAE,CAAC,gCAAgC,UAAU,MAAM;KACzE,CAAC;IACF,KAAK,MAAM,UAAU,IAAI,KAAK,EAAE,CAAC;QAC/B,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;YACnC,IAAI,CAAC;gBACH,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;gBAC9C,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;YACpC,CAAC;YAAC,MAAM,CAAC;gBACP,WAAW;YACb,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAYD,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,KAAqB,EAAE,WAA6B,eAAe,EAAE;IACtG,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QACnE,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO;gBACL,SAAS,EAAE,IAAI;gBACf,YAAY,EAAE,QAAQ;gBACtB,MAAM,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,CAAC,WAAW,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,EAAE;aAC/F,CAAC;QACJ,CAAC;IACH,CAAC;IACD,IAAI,KAAK,CAAC,aAAa,IAAI,QAAQ,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1D,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,KAAK,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;QACnE,IAAI,MAAM,EAAE,CAAC;YACX,OAAO;gBACL,SAAS,EAAE,IAAI;gBACf,YAAY,EAAE,MAAM,CAAC,IAAI;gBACzB,MAAM,EAAE;oBACN,OAAO,EAAE,MAAM,qBAAqB,CAAC,QAAQ,CAAC;oBAC9C,UAAU,EAAE,KAAK,CAAC,WAAW;wBAC3B,CAAC,CAAC,CAAC,UAAkB,EAAE,EAAE,CAAC,KAAK,CAAC,WAAY,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC;wBACrE,CAAC,CAAC,CAAC,UAAkB,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC;iBAC5D;aACF,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AAC9B,CAAC;AASD,iKAAiK;AACjK,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,QAAgB,EAChB,UAAkB,EAClB,WAA6B,eAAe,EAAE;IAE9C,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC;IACvD,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IACxC,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAClD,IAAI,CAAC,KAAK,CAAC,SAAS;QAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAClD,OAAO;QACL,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO;QAC7B,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC;KAC1C,CAAC;AACJ,CAAC;AAID;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,cAAc,CAC5B,OAAe,EACf,IAAc,EACd,YAA8B,SAAS;IAEvC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,UAAU,GAAG,uBAAuB,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,MAAM,KAAK,GAAG,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,IAAI,EAAE;YAC3D,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,QAAQ;YACf,WAAW,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO;YACzC,wBAAwB,EAAE,UAAU,CAAC,wBAAwB;SAC9D,CAAC,CAAC;QACH,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE;YACvB,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,KAAK,CAAC,KAAK,EAAE,CAAC;YACd,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE,EAAE;YACjC,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,YAAY,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACvG,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAgBD,gHAAgH;AAChH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,WAA6B,eAAe,EAAE;IACvF,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,qBAAqB,CAAC,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC9F,MAAM,OAAO,GAAiB,MAAM,OAAO,CAAC,GAAG,CAC7C,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QAC3B,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAClD,OAAO;YACL,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAChE,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC3D,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;IACF,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,CAAC;AAClD,CAAC;AAED,6GAA6G;AAC7G,MAAM,CAAC,MAAM,gBAAgB,GAAG,eAAe,CAAmD;IAChG,MAAM,EAAE,KAAK;IACb,IAAI,EAAE,cAAc;IACpB,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC;IAC1B,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC,MAAM,oBAAoB,EAAE,CAAC;CACrD,CAAC,CAAC;AAsBH,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,yBAAyB,CAAC,KAAwB;IACzD,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC;IAC7C,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChE,OAAO,GAAG,CAAC,eAAe,CAAC,gDAAgD,CAAC,CAAC,CAAC;IAChF,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC,eAAe,CAAC,4BAA4B,CAAC,CAAC,CAAC;IACrF,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;IACrC,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1D,OAAO,GAAG,CAAC,eAAe,CAAC,sBAAsB,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,2BAA2B,EAAE,CAAC,CAAC,CAAC,CAAC;IACpH,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;IACjC,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;QAChF,OAAO,GAAG,CAAC,eAAe,CAAC,iDAAiD,CAAC,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,EAAE,CAAC,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;AACpF,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,eAAe,CAItD;IACA,MAAM,EAAE,MAAM;IACd,IAAI,EAAE,qCAAqC;IAC3C,iBAAiB,EAAE,IAAI;IACvB,KAAK,EAAE,yBAAyB;IAChC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAC5B,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC7D,IAAI,CAAC,KAAK;YAAE,OAAO,GAAG,CAAC,cAAc,CAAC,aAAa,EAAE,mBAAmB,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QAC3F,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,eAAe,EAAE,CAAC;QACpD,IAAI,CAAC,qBAAqB,CAAC,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACrD,OAAO,GAAG,CAAC,cAAc,CAAC,aAAa,EAAE,GAAG,KAAK,CAAC,KAAK,wBAAwB,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QACvG,CAAC;QAED,IAAI,WAAmB,CAAC;QACxB,IAAI,CAAC;YACH,WAAW,GAAG,MAAM,oBAAoB,CACtC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EACnG,EAAE,QAAQ,EAAE,IAAI,CAAC,WAAW,IAAI,qBAAqB,EAAE,CACxD,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,wBAAwB,EAAE,CAAC;gBAC9C,OAAO,GAAG,CAAC,cAAc,CAAC,WAAW,EAAE,aAAa,KAAK,CAAC,WAAW,iBAAiB,CAAC,CAAC,CAAC;YAC3F,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;QAED,MAAM,UAAU,GAAG,MAAM,yBAAyB,CAAC,KAAK,CAAC,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;QAC1F,IAAI,CAAC,UAAU,CAAC,SAAS,IAAI,CAAC,UAAU,CAAC,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;YACrE,OAAO,GAAG,CAAC,cAAc,CAAC,UAAU,EAAE,GAAG,KAAK,CAAC,KAAK,mBAAmB,CAAC,CAAC,CAAC;QAC5E,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,CAAC;QACtG,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,OAAO,GAAG,CAAC,cAAc,CAAC,gBAAgB,EAAE,oBAAoB,KAAK,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACnG,CAAC;QACD,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;IACvE,CAAC;CACF,CAAC,CAAC;AAEH,6IAA6I;AAC7I,MAAM,UAAU,uBAAuB,CACrC,GAAY,EACZ,OAAuB,EACvB,aAAkC,EAAE;IAEpC,cAAc,CAAC,GAAG,EAAE,gBAAgB,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;IACnD,cAAc,CAAC,GAAG,EAAE,yBAAyB,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;AACtE,CAAC"}
|