very-happy-cli 0.2.141 → 0.2.143
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/dist/{AcpBackend-CnWSwaHk.cjs → AcpBackend-B8oehrfU.cjs} +2 -2
- package/dist/{AcpBackend-CWmjboOm.mjs → AcpBackend-LEgn9vol.mjs} +2 -2
- package/dist/{AcpSessionManager-Dxt78rPO.cjs → AcpSessionManager-BomdfyhZ.cjs} +1 -1
- package/dist/{AcpSessionManager-CtXoi6PN.mjs → AcpSessionManager-Yfbs5bi2.mjs} +1 -1
- package/dist/{agentGuidance-Do7cQka3.mjs → agentGuidance-BU4hxm8M.mjs} +1 -1
- package/dist/{agentGuidance-B9ENxSaS.cjs → agentGuidance-CJSl54ua.cjs} +1 -1
- package/dist/codex/happyMcpStdioBridge.cjs +2 -2
- package/dist/codex/happyMcpStdioBridge.mjs +2 -2
- package/dist/{config-Dn7nAHcA.cjs → config-CfqWoHmO.cjs} +5 -4
- package/dist/{config-DY57frJF.mjs → config-euZ_K5Lo.mjs} +5 -4
- package/dist/{index-BSVgut_Y.cjs → index-BREtikhm.cjs} +5 -4
- package/dist/{index-3STVDtNO.cjs → index-Bj68y6ee.cjs} +12 -40
- package/dist/{index-ChWePQEd.cjs → index-C510dSUn.cjs} +188 -132
- package/dist/{index-C55sW8E9.mjs → index-DoiG88oX.mjs} +169 -114
- package/dist/{index-DhfgAB8K.mjs → index-PM_SsRpw.mjs} +5 -4
- package/dist/{index-Dz6FgNFg.mjs → index-ZOMC8Gzn.mjs} +11 -39
- package/dist/index.cjs +7 -6
- package/dist/index.mjs +7 -6
- package/dist/installPiTools-BKnXjrVu.cjs +82 -0
- package/dist/installPiTools-C-Lxv4Bt.mjs +77 -0
- package/dist/{installTerminalHooks-zmtIrf3E.mjs → installTerminalHooks-BGVQqbgq.mjs} +8 -7
- package/dist/{installTerminalHooks--jkP17uE.cjs → installTerminalHooks-C_jraM1j.cjs} +9 -8
- package/dist/lib.cjs +3 -2
- package/dist/lib.d.cts +6 -1
- package/dist/lib.d.mts +6 -1
- package/dist/lib.mjs +3 -2
- package/dist/{limits-DbLWXlJm.cjs → limits-B3oVgqBJ.cjs} +29 -10
- package/dist/{limits-DT5Yk_UH.mjs → limits-uABU-yq3.mjs} +29 -11
- package/dist/{mcp-Bzy-X9kI.mjs → mcp-CfbTQXyh.mjs} +28 -14
- package/dist/{mcp-kE0n1dBF.cjs → mcp-G-3lL_KH.cjs} +29 -15
- package/dist/piExtension.d.mts +17 -0
- package/dist/piExtension.mjs +84 -0
- package/dist/piRuntime-BE6iYQwU.mjs +37 -0
- package/dist/piRuntime-CWE-1W-y.cjs +39 -0
- package/dist/piTerminal-Dyc_9pGP.cjs +132 -0
- package/dist/piTerminal-rqKn1_Zy.mjs +129 -0
- package/dist/projectPath-CSpqWdxp.mjs +10 -0
- package/dist/projectPath-ChLhdOyt.cjs +13 -0
- package/dist/{runGemini-BmdhYEzM.mjs → runGemini-BMlXIaTL.mjs} +8 -7
- package/dist/{runGemini-CxUz95A1.cjs → runGemini-C6qMFzcn.cjs} +9 -8
- package/dist/{runOpenClaw-RLIFJx61.cjs → runOpenClaw-C2_aCP7v.cjs} +6 -5
- package/dist/{runOpenClaw-CYpO3Vv8.mjs → runOpenClaw-CoO5Vp3S.mjs} +6 -5
- package/dist/{send-DT04hV8o.mjs → send-CBrJylJc.mjs} +5 -4
- package/dist/{send-BGcCrMUT.cjs → send-DGVwmB-p.cjs} +5 -4
- package/dist/{sessions-DDWTq2AG.mjs → sessions-DbLubh2N.mjs} +7 -6
- package/dist/{sessions-Jt9lrcrG.cjs → sessions-DyQXMN-8.cjs} +7 -6
- package/dist/{spawn-CdZgvthE.cjs → spawn-DIyFOn3W.cjs} +5 -4
- package/dist/{spawn-Ca0A70dX.mjs → spawn-wkkxEGdF.mjs} +5 -4
- package/dist/{teams-CzK1zg0m.mjs → teams-BTyVFK3P.mjs} +5 -4
- package/dist/{teams-DfVwVZ4x.cjs → teams-QOkGFjkJ.cjs} +5 -4
- package/dist/terminalToolContext-CFeGeaNm.mjs +7 -0
- package/dist/terminalToolContext-DoV9Gs7K.cjs +9 -0
- package/dist/{todo-4WhOom8k.mjs → todo-DoLkqdBe.mjs} +4 -3
- package/dist/{todo-D9nFaYpQ.cjs → todo-Du6pjwx_.cjs} +4 -3
- package/dist/{types-Bk3W89Z3.cjs → types-6__wqmmP.cjs} +80 -17
- package/dist/{types-CLosaeZT.mjs → types-BG4gFjLL.mjs} +79 -15
- package/package.json +11 -7
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { r as registerTeamsTools } from './agentGuidance-
|
|
1
|
+
import { r as registerTeamsTools, P as PREVIEW_TOOL_NAME, a as PREVIEW_TOOL_TITLE, b as PREVIEW_TOOL_DESCRIPTION } from './agentGuidance-BU4hxm8M.mjs';
|
|
2
2
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
4
|
import { z } from 'zod';
|
|
5
|
-
import {
|
|
6
|
-
import { l as logger, C as CLIPBOARD_TOOL_NAME, a as CLIPBOARD_TOOL_TITLE, b as CLIPBOARD_TOOL_DESCRIPTION, e as CLIPBOARD_MAX_BYTES } from './limits-
|
|
7
|
-
import { h as registerAssistantSessionTools } from './index-
|
|
5
|
+
import { p as pushClipboardViaDaemon, f as pushFilePreviewViaDaemon, g as setTerminalTitleViaDaemon } from './types-BG4gFjLL.mjs';
|
|
6
|
+
import { l as logger, C as CLIPBOARD_TOOL_NAME, a as CLIPBOARD_TOOL_TITLE, b as CLIPBOARD_TOOL_DESCRIPTION, e as CLIPBOARD_MAX_BYTES } from './limits-uABU-yq3.mjs';
|
|
7
|
+
import { h as checkPreviewPath, j as registerAssistantSessionTools } from './index-DoiG88oX.mjs';
|
|
8
8
|
import 'node:fs/promises';
|
|
9
9
|
import 'node:os';
|
|
10
10
|
import 'node:crypto';
|
|
@@ -14,6 +14,7 @@ import 'socket.io-client';
|
|
|
14
14
|
import 'node:child_process';
|
|
15
15
|
import 'node:fs';
|
|
16
16
|
import 'node:path';
|
|
17
|
+
import { r as resolveMcpTerminalId } from './terminalToolContext-CFeGeaNm.mjs';
|
|
17
18
|
import 'node:events';
|
|
18
19
|
import '@paralleldrive/cuid2';
|
|
19
20
|
import 'child_process';
|
|
@@ -22,6 +23,7 @@ import 'fs/promises';
|
|
|
22
23
|
import 'crypto';
|
|
23
24
|
import 'path';
|
|
24
25
|
import 'cross-spawn';
|
|
26
|
+
import './projectPath-CSpqWdxp.mjs';
|
|
25
27
|
import 'url';
|
|
26
28
|
import 'os';
|
|
27
29
|
import 'node-pty';
|
|
@@ -48,11 +50,6 @@ import 'node:url';
|
|
|
48
50
|
import 'node:readline/promises';
|
|
49
51
|
|
|
50
52
|
const TERMINAL_TITLE_TOOL_NAME = "change_title";
|
|
51
|
-
function resolveMcpTerminalId(env) {
|
|
52
|
-
if (env.HAPPY_MCP_URL) return null;
|
|
53
|
-
const id = env.VH_TERMINAL_ID;
|
|
54
|
-
return id && /^[a-zA-Z0-9_-]{1,64}$/.test(id) ? id : null;
|
|
55
|
-
}
|
|
56
53
|
function resolveMcpToolSurface(env) {
|
|
57
54
|
if (env.HAPPY_SESSION_VARIANT !== "assistant") return "clipboard";
|
|
58
55
|
if (env.HAPPY_MANAGED === "1") return "clipboard";
|
|
@@ -68,13 +65,13 @@ function registerMcpTools(server, surface, terminalId = null) {
|
|
|
68
65
|
}
|
|
69
66
|
}, async (args) => {
|
|
70
67
|
logger.debug(`[MCP] copy_to_clipboard called (${args.text.length} chars)`);
|
|
71
|
-
const result = await pushClipboardViaDaemon(args.text);
|
|
68
|
+
const result = await pushClipboardViaDaemon(args.text, terminalId ?? void 0);
|
|
72
69
|
if (result.delivered) {
|
|
73
70
|
const note = result.truncated ? ` (truncated to ${CLIPBOARD_MAX_BYTES / 1024}KB \u2014 original was ${result.totalBytes} bytes)` : "";
|
|
74
71
|
return {
|
|
75
72
|
content: [{
|
|
76
73
|
type: "text",
|
|
77
|
-
text: `
|
|
74
|
+
text: `Queued a clipboard request for the user's open Very Happy device(s)${note}. This does not confirm that a browser wrote the clipboard; the user may need to tap a confirmation button.`
|
|
78
75
|
}],
|
|
79
76
|
isError: false
|
|
80
77
|
};
|
|
@@ -88,6 +85,22 @@ function registerMcpTools(server, surface, terminalId = null) {
|
|
|
88
85
|
};
|
|
89
86
|
});
|
|
90
87
|
if (terminalId) {
|
|
88
|
+
server.registerTool(PREVIEW_TOOL_NAME, {
|
|
89
|
+
description: PREVIEW_TOOL_DESCRIPTION,
|
|
90
|
+
title: PREVIEW_TOOL_TITLE,
|
|
91
|
+
inputSchema: {
|
|
92
|
+
path: z.string().min(1).describe("Absolute path or path relative to the current working directory"),
|
|
93
|
+
mode: z.enum(["file", "diff"]).optional().describe("'file' (default) previews the file; 'diff' is reserved and currently falls back to 'file'")
|
|
94
|
+
}
|
|
95
|
+
}, async (args) => {
|
|
96
|
+
const verdict = checkPreviewPath(args.path);
|
|
97
|
+
if (verdict.deniedReason) return { content: [{ type: "text", text: verdict.deniedReason }], isError: true };
|
|
98
|
+
const result = await pushFilePreviewViaDaemon(terminalId, verdict.resolved, args.mode ?? "file");
|
|
99
|
+
return {
|
|
100
|
+
content: [{ type: "text", text: result.delivered ? `Queued a preview request for ${verdict.resolved}. This does not confirm that a browser opened it.` : `Failed to request preview: ${result.error || "unknown error"}` }],
|
|
101
|
+
isError: !result.delivered
|
|
102
|
+
};
|
|
103
|
+
});
|
|
91
104
|
server.registerTool(TERMINAL_TITLE_TOOL_NAME, {
|
|
92
105
|
description: "Change the title of the very-happy web terminal this agent is running in",
|
|
93
106
|
title: "Change Terminal Title",
|
|
@@ -116,15 +129,16 @@ function registerMcpTools(server, surface, terminalId = null) {
|
|
|
116
129
|
registerAssistantSessionTools(server);
|
|
117
130
|
}
|
|
118
131
|
}
|
|
119
|
-
async function handleMcpCommand() {
|
|
132
|
+
async function handleMcpCommand(terminalToolsOnly = false) {
|
|
120
133
|
const server = new McpServer({
|
|
121
134
|
name: "very-happy",
|
|
122
135
|
version: "1.0.0"
|
|
123
136
|
});
|
|
124
|
-
const surface = resolveMcpToolSurface(process.env);
|
|
137
|
+
const surface = terminalToolsOnly ? "clipboard" : resolveMcpToolSurface(process.env);
|
|
125
138
|
const terminalId = resolveMcpTerminalId(process.env);
|
|
139
|
+
if (terminalToolsOnly && !terminalId) throw new Error("Very Happy terminal context is required");
|
|
126
140
|
registerMcpTools(server, surface, terminalId);
|
|
127
|
-
if (process.env.HAPPY_MANAGED !== "1" && !process.env.HAPPY_MCP_URL) registerTeamsTools(server, process.env.HAPPY_SESSION_ID);
|
|
141
|
+
if (!terminalToolsOnly && process.env.HAPPY_MANAGED !== "1" && !process.env.HAPPY_MCP_URL) registerTeamsTools(server, process.env.HAPPY_SESSION_ID);
|
|
128
142
|
const transport = new StdioServerTransport();
|
|
129
143
|
await server.connect(transport);
|
|
130
144
|
logger.debug(`[MCP] very-happy stdio MCP server started (surface=${surface}, terminal=${terminalId ?? "none"})`);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var agentGuidance = require('./agentGuidance-
|
|
3
|
+
var agentGuidance = require('./agentGuidance-CJSl54ua.cjs');
|
|
4
4
|
var mcp_js = require('@modelcontextprotocol/sdk/server/mcp.js');
|
|
5
5
|
var stdio_js = require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
6
6
|
var z = require('zod');
|
|
7
|
-
var api = require('./types-
|
|
8
|
-
var persistence = require('./limits-
|
|
9
|
-
var index = require('./index-
|
|
7
|
+
var api = require('./types-6__wqmmP.cjs');
|
|
8
|
+
var persistence = require('./limits-B3oVgqBJ.cjs');
|
|
9
|
+
var index = require('./index-C510dSUn.cjs');
|
|
10
10
|
require('node:fs/promises');
|
|
11
11
|
require('node:os');
|
|
12
12
|
require('node:crypto');
|
|
@@ -16,6 +16,7 @@ require('socket.io-client');
|
|
|
16
16
|
require('node:child_process');
|
|
17
17
|
require('node:fs');
|
|
18
18
|
require('node:path');
|
|
19
|
+
var terminalToolContext = require('./terminalToolContext-DoV9Gs7K.cjs');
|
|
19
20
|
require('node:events');
|
|
20
21
|
require('@paralleldrive/cuid2');
|
|
21
22
|
require('child_process');
|
|
@@ -24,6 +25,7 @@ require('fs/promises');
|
|
|
24
25
|
require('crypto');
|
|
25
26
|
require('path');
|
|
26
27
|
require('cross-spawn');
|
|
28
|
+
require('./projectPath-ChLhdOyt.cjs');
|
|
27
29
|
require('url');
|
|
28
30
|
require('os');
|
|
29
31
|
require('node-pty');
|
|
@@ -50,11 +52,6 @@ require('node:url');
|
|
|
50
52
|
require('node:readline/promises');
|
|
51
53
|
|
|
52
54
|
const TERMINAL_TITLE_TOOL_NAME = "change_title";
|
|
53
|
-
function resolveMcpTerminalId(env) {
|
|
54
|
-
if (env.HAPPY_MCP_URL) return null;
|
|
55
|
-
const id = env.VH_TERMINAL_ID;
|
|
56
|
-
return id && /^[a-zA-Z0-9_-]{1,64}$/.test(id) ? id : null;
|
|
57
|
-
}
|
|
58
55
|
function resolveMcpToolSurface(env) {
|
|
59
56
|
if (env.HAPPY_SESSION_VARIANT !== "assistant") return "clipboard";
|
|
60
57
|
if (env.HAPPY_MANAGED === "1") return "clipboard";
|
|
@@ -70,13 +67,13 @@ function registerMcpTools(server, surface, terminalId = null) {
|
|
|
70
67
|
}
|
|
71
68
|
}, async (args) => {
|
|
72
69
|
persistence.logger.debug(`[MCP] copy_to_clipboard called (${args.text.length} chars)`);
|
|
73
|
-
const result = await api.pushClipboardViaDaemon(args.text);
|
|
70
|
+
const result = await api.pushClipboardViaDaemon(args.text, terminalId ?? void 0);
|
|
74
71
|
if (result.delivered) {
|
|
75
72
|
const note = result.truncated ? ` (truncated to ${persistence.CLIPBOARD_MAX_BYTES / 1024}KB \u2014 original was ${result.totalBytes} bytes)` : "";
|
|
76
73
|
return {
|
|
77
74
|
content: [{
|
|
78
75
|
type: "text",
|
|
79
|
-
text: `
|
|
76
|
+
text: `Queued a clipboard request for the user's open Very Happy device(s)${note}. This does not confirm that a browser wrote the clipboard; the user may need to tap a confirmation button.`
|
|
80
77
|
}],
|
|
81
78
|
isError: false
|
|
82
79
|
};
|
|
@@ -90,6 +87,22 @@ function registerMcpTools(server, surface, terminalId = null) {
|
|
|
90
87
|
};
|
|
91
88
|
});
|
|
92
89
|
if (terminalId) {
|
|
90
|
+
server.registerTool(agentGuidance.PREVIEW_TOOL_NAME, {
|
|
91
|
+
description: agentGuidance.PREVIEW_TOOL_DESCRIPTION,
|
|
92
|
+
title: agentGuidance.PREVIEW_TOOL_TITLE,
|
|
93
|
+
inputSchema: {
|
|
94
|
+
path: z.z.string().min(1).describe("Absolute path or path relative to the current working directory"),
|
|
95
|
+
mode: z.z.enum(["file", "diff"]).optional().describe("'file' (default) previews the file; 'diff' is reserved and currently falls back to 'file'")
|
|
96
|
+
}
|
|
97
|
+
}, async (args) => {
|
|
98
|
+
const verdict = index.checkPreviewPath(args.path);
|
|
99
|
+
if (verdict.deniedReason) return { content: [{ type: "text", text: verdict.deniedReason }], isError: true };
|
|
100
|
+
const result = await api.pushFilePreviewViaDaemon(terminalId, verdict.resolved, args.mode ?? "file");
|
|
101
|
+
return {
|
|
102
|
+
content: [{ type: "text", text: result.delivered ? `Queued a preview request for ${verdict.resolved}. This does not confirm that a browser opened it.` : `Failed to request preview: ${result.error || "unknown error"}` }],
|
|
103
|
+
isError: !result.delivered
|
|
104
|
+
};
|
|
105
|
+
});
|
|
93
106
|
server.registerTool(TERMINAL_TITLE_TOOL_NAME, {
|
|
94
107
|
description: "Change the title of the very-happy web terminal this agent is running in",
|
|
95
108
|
title: "Change Terminal Title",
|
|
@@ -118,15 +131,16 @@ function registerMcpTools(server, surface, terminalId = null) {
|
|
|
118
131
|
index.registerAssistantSessionTools(server);
|
|
119
132
|
}
|
|
120
133
|
}
|
|
121
|
-
async function handleMcpCommand() {
|
|
134
|
+
async function handleMcpCommand(terminalToolsOnly = false) {
|
|
122
135
|
const server = new mcp_js.McpServer({
|
|
123
136
|
name: "very-happy",
|
|
124
137
|
version: "1.0.0"
|
|
125
138
|
});
|
|
126
|
-
const surface = resolveMcpToolSurface(process.env);
|
|
127
|
-
const terminalId = resolveMcpTerminalId(process.env);
|
|
139
|
+
const surface = terminalToolsOnly ? "clipboard" : resolveMcpToolSurface(process.env);
|
|
140
|
+
const terminalId = terminalToolContext.resolveMcpTerminalId(process.env);
|
|
141
|
+
if (terminalToolsOnly && !terminalId) throw new Error("Very Happy terminal context is required");
|
|
128
142
|
registerMcpTools(server, surface, terminalId);
|
|
129
|
-
if (process.env.HAPPY_MANAGED !== "1" && !process.env.HAPPY_MCP_URL) agentGuidance.registerTeamsTools(server, process.env.HAPPY_SESSION_ID);
|
|
143
|
+
if (!terminalToolsOnly && process.env.HAPPY_MANAGED !== "1" && !process.env.HAPPY_MCP_URL) agentGuidance.registerTeamsTools(server, process.env.HAPPY_SESSION_ID);
|
|
130
144
|
const transport = new stdio_js.StdioServerTransport();
|
|
131
145
|
await server.connect(transport);
|
|
132
146
|
persistence.logger.debug(`[MCP] very-happy stdio MCP server started (surface=${surface}, terminal=${terminalId ?? "none"})`);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
type PiContext = {
|
|
2
|
+
cwd: string;
|
|
3
|
+
};
|
|
4
|
+
type PiApi = {
|
|
5
|
+
on(event: 'session_start' | 'session_shutdown', handler: (event: unknown, ctx: PiContext) => Promise<void>): void;
|
|
6
|
+
registerTool(tool: {
|
|
7
|
+
name: string;
|
|
8
|
+
label: string;
|
|
9
|
+
description: string;
|
|
10
|
+
parameters: unknown;
|
|
11
|
+
execute(id: string, args: Record<string, unknown>, signal?: AbortSignal): Promise<unknown>;
|
|
12
|
+
}): void;
|
|
13
|
+
};
|
|
14
|
+
/** Auto-discovered native Pi extension. Managed launchers own their own bridge. */
|
|
15
|
+
declare function piTerminalExtension(pi: PiApi): void;
|
|
16
|
+
|
|
17
|
+
export { piTerminalExtension as default };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
import { p as projectPath } from './projectPath-CSpqWdxp.mjs';
|
|
5
|
+
import { r as resolveMcpTerminalId } from './terminalToolContext-CFeGeaNm.mjs';
|
|
6
|
+
import 'path';
|
|
7
|
+
import 'url';
|
|
8
|
+
|
|
9
|
+
function piTerminalExtension(pi) {
|
|
10
|
+
if (process.env.HAPPY_MCP_URL || process.env.HAPPY_TERMINAL_MCP_URL || !resolveMcpTerminalId(process.env)) return;
|
|
11
|
+
let client;
|
|
12
|
+
let connecting;
|
|
13
|
+
let stopped = false;
|
|
14
|
+
let cwd = process.cwd();
|
|
15
|
+
function connect() {
|
|
16
|
+
if (stopped) return Promise.reject(new Error("Very Happy terminal tools have shut down"));
|
|
17
|
+
if (connecting) return connecting;
|
|
18
|
+
if (client) return Promise.resolve(client);
|
|
19
|
+
const current = new Client({ name: "very-happy-pi-terminal", version: "1" });
|
|
20
|
+
client = current;
|
|
21
|
+
current.onclose = () => {
|
|
22
|
+
if (client === current) client = void 0;
|
|
23
|
+
};
|
|
24
|
+
const env = Object.fromEntries(Object.entries(process.env).filter((entry) => entry[1] !== void 0));
|
|
25
|
+
if (env.VH_HAPPY_HOME_DIR) env.HAPPY_HOME_DIR = env.VH_HAPPY_HOME_DIR;
|
|
26
|
+
const transport = new StdioClientTransport({
|
|
27
|
+
// Pi may itself be a Bun/SEA executable. Use the CLI's Node runtime
|
|
28
|
+
// from PATH, just like the installed very-happy shebang.
|
|
29
|
+
command: "node",
|
|
30
|
+
args: ["--no-warnings", "--no-deprecation", resolve(projectPath(), "dist/index.mjs"), "mcp", "--terminal-tools"],
|
|
31
|
+
env,
|
|
32
|
+
cwd,
|
|
33
|
+
stderr: "pipe"
|
|
34
|
+
});
|
|
35
|
+
transport.stderr?.on("data", () => {
|
|
36
|
+
});
|
|
37
|
+
connecting = current.connect(transport, { timeout: 1e4 }).then(async () => {
|
|
38
|
+
if (stopped) {
|
|
39
|
+
await current.close();
|
|
40
|
+
throw new Error("Very Happy terminal tools have shut down");
|
|
41
|
+
}
|
|
42
|
+
return current;
|
|
43
|
+
}).catch(async (error) => {
|
|
44
|
+
if (client === current) client = void 0;
|
|
45
|
+
await current.close();
|
|
46
|
+
throw error;
|
|
47
|
+
}).finally(() => {
|
|
48
|
+
connecting = void 0;
|
|
49
|
+
});
|
|
50
|
+
return connecting;
|
|
51
|
+
}
|
|
52
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
53
|
+
cwd = ctx.cwd;
|
|
54
|
+
const current = await connect();
|
|
55
|
+
const available = await current.listTools({}, { timeout: 1e4 });
|
|
56
|
+
if (stopped) return;
|
|
57
|
+
for (const tool of available.tools) {
|
|
58
|
+
pi.registerTool({
|
|
59
|
+
name: tool.name,
|
|
60
|
+
label: tool.title || tool.name,
|
|
61
|
+
description: tool.description || tool.name,
|
|
62
|
+
parameters: tool.inputSchema,
|
|
63
|
+
async execute(_id, args, signal) {
|
|
64
|
+
const active = await connect();
|
|
65
|
+
const result = await active.callTool({ name: tool.name, arguments: args }, void 0, { signal, timeout: 3e4 });
|
|
66
|
+
if (result.isError) {
|
|
67
|
+
const content = Array.isArray(result.content) ? result.content : [];
|
|
68
|
+
throw new Error(content.filter((block) => block.type === "text").map((block) => block.text).join("\n") || "Very Happy tool failed");
|
|
69
|
+
}
|
|
70
|
+
return { content: result.content, details: { isError: !!result.isError } };
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
pi.on("session_shutdown", async () => {
|
|
76
|
+
stopped = true;
|
|
77
|
+
await connecting?.catch(() => {
|
|
78
|
+
});
|
|
79
|
+
await client?.close();
|
|
80
|
+
client = void 0;
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export { piTerminalExtension as default };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { mkdir, chmod, writeFile, rename } from 'node:fs/promises';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { c as configuration } from './limits-uABU-yq3.mjs';
|
|
5
|
+
import { P as PI_TEAMS_EXTENSION } from './index-DoiG88oX.mjs';
|
|
6
|
+
|
|
7
|
+
async function publish(path, content, mode) {
|
|
8
|
+
const temporary = `${path}.${randomUUID()}.new`;
|
|
9
|
+
await writeFile(temporary, content, { mode, flag: "wx" });
|
|
10
|
+
await rename(temporary, path);
|
|
11
|
+
}
|
|
12
|
+
async function preparePiTeamsRuntime() {
|
|
13
|
+
const directory = join(configuration.happyHomeDir, "teams", "pi-runtime");
|
|
14
|
+
await mkdir(directory, { recursive: true, mode: 448 });
|
|
15
|
+
const extension = join(directory, "very-happy-teams.mjs");
|
|
16
|
+
await publish(extension, PI_TEAMS_EXTENSION, 384);
|
|
17
|
+
const launcher = join(directory, "pi-teams.mjs");
|
|
18
|
+
const script = `#!${process.execPath}
|
|
19
|
+
import { spawn } from 'node:child_process';
|
|
20
|
+
const child = spawn(process.env.VH_TEAM_PI_COMMAND || 'pi', ['--extension', ${JSON.stringify(extension)}, ...process.argv.slice(2)], {stdio:'inherit',env:process.env,shell:process.platform==='win32'});
|
|
21
|
+
child.on('error',()=>{process.stderr.write('Very Happy could not launch pi\\n');process.exitCode=1});
|
|
22
|
+
child.on('exit',(code)=>{process.exitCode=code ?? 1});
|
|
23
|
+
for(const signal of ['SIGINT','SIGTERM'])process.on(signal,()=>child.kill(signal));
|
|
24
|
+
`;
|
|
25
|
+
await publish(launcher, script, 448);
|
|
26
|
+
await chmod(launcher, 448);
|
|
27
|
+
let command = launcher;
|
|
28
|
+
if (process.platform === "win32") {
|
|
29
|
+
command = join(directory, "pi-teams.cmd");
|
|
30
|
+
await publish(command, `@echo off\r
|
|
31
|
+
"${process.execPath}" "${launcher}" %*\r
|
|
32
|
+
`, 448);
|
|
33
|
+
}
|
|
34
|
+
return { PI_ACP_PI_COMMAND: command, VH_TEAM_PI_COMMAND: (process.env.PI_ACP_PI_COMMAND === command ? process.env.VH_TEAM_PI_COMMAND : process.env.PI_ACP_PI_COMMAND) || "pi" };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { preparePiTeamsRuntime as p };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var promises = require('node:fs/promises');
|
|
4
|
+
var node_crypto = require('node:crypto');
|
|
5
|
+
var path = require('node:path');
|
|
6
|
+
var persistence = require('./limits-B3oVgqBJ.cjs');
|
|
7
|
+
var index = require('./index-C510dSUn.cjs');
|
|
8
|
+
|
|
9
|
+
async function publish(path, content, mode) {
|
|
10
|
+
const temporary = `${path}.${node_crypto.randomUUID()}.new`;
|
|
11
|
+
await promises.writeFile(temporary, content, { mode, flag: "wx" });
|
|
12
|
+
await promises.rename(temporary, path);
|
|
13
|
+
}
|
|
14
|
+
async function preparePiTeamsRuntime() {
|
|
15
|
+
const directory = path.join(persistence.configuration.happyHomeDir, "teams", "pi-runtime");
|
|
16
|
+
await promises.mkdir(directory, { recursive: true, mode: 448 });
|
|
17
|
+
const extension = path.join(directory, "very-happy-teams.mjs");
|
|
18
|
+
await publish(extension, index.PI_TEAMS_EXTENSION, 384);
|
|
19
|
+
const launcher = path.join(directory, "pi-teams.mjs");
|
|
20
|
+
const script = `#!${process.execPath}
|
|
21
|
+
import { spawn } from 'node:child_process';
|
|
22
|
+
const child = spawn(process.env.VH_TEAM_PI_COMMAND || 'pi', ['--extension', ${JSON.stringify(extension)}, ...process.argv.slice(2)], {stdio:'inherit',env:process.env,shell:process.platform==='win32'});
|
|
23
|
+
child.on('error',()=>{process.stderr.write('Very Happy could not launch pi\\n');process.exitCode=1});
|
|
24
|
+
child.on('exit',(code)=>{process.exitCode=code ?? 1});
|
|
25
|
+
for(const signal of ['SIGINT','SIGTERM'])process.on(signal,()=>child.kill(signal));
|
|
26
|
+
`;
|
|
27
|
+
await publish(launcher, script, 448);
|
|
28
|
+
await promises.chmod(launcher, 448);
|
|
29
|
+
let command = launcher;
|
|
30
|
+
if (process.platform === "win32") {
|
|
31
|
+
command = path.join(directory, "pi-teams.cmd");
|
|
32
|
+
await publish(command, `@echo off\r
|
|
33
|
+
"${process.execPath}" "${launcher}" %*\r
|
|
34
|
+
`, 448);
|
|
35
|
+
}
|
|
36
|
+
return { PI_ACP_PI_COMMAND: command, VH_TEAM_PI_COMMAND: (process.env.PI_ACP_PI_COMMAND === command ? process.env.VH_TEAM_PI_COMMAND : process.env.PI_ACP_PI_COMMAND) || "pi" };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
exports.preparePiTeamsRuntime = preparePiTeamsRuntime;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var node_child_process = require('node:child_process');
|
|
4
|
+
var node_crypto = require('node:crypto');
|
|
5
|
+
var node_http = require('node:http');
|
|
6
|
+
var mcp_js = require('@modelcontextprotocol/sdk/server/mcp.js');
|
|
7
|
+
var streamableHttp_js = require('@modelcontextprotocol/sdk/server/streamableHttp.js');
|
|
8
|
+
var piRuntime = require('./piRuntime-CWE-1W-y.cjs');
|
|
9
|
+
var mcp = require('./mcp-G-3lL_KH.cjs');
|
|
10
|
+
require('./agentGuidance-CJSl54ua.cjs');
|
|
11
|
+
require('node:fs/promises');
|
|
12
|
+
require('node:os');
|
|
13
|
+
require('zod');
|
|
14
|
+
require('./limits-B3oVgqBJ.cjs');
|
|
15
|
+
require('axios');
|
|
16
|
+
require('tweetnacl');
|
|
17
|
+
require('socket.io-client');
|
|
18
|
+
require('./types-6__wqmmP.cjs');
|
|
19
|
+
require('node:fs');
|
|
20
|
+
require('node:path');
|
|
21
|
+
var terminalToolContext = require('./terminalToolContext-DoV9Gs7K.cjs');
|
|
22
|
+
require('./index-C510dSUn.cjs');
|
|
23
|
+
require('chalk');
|
|
24
|
+
require('cross-spawn');
|
|
25
|
+
require('node:readline');
|
|
26
|
+
require('./projectPath-ChLhdOyt.cjs');
|
|
27
|
+
require('path');
|
|
28
|
+
require('url');
|
|
29
|
+
require('fs/promises');
|
|
30
|
+
require('ink');
|
|
31
|
+
require('react');
|
|
32
|
+
require('@anthropic-ai/claude-agent-sdk');
|
|
33
|
+
require('node:events');
|
|
34
|
+
require('os');
|
|
35
|
+
require('child_process');
|
|
36
|
+
require('@paralleldrive/cuid2');
|
|
37
|
+
require('fs');
|
|
38
|
+
require('@anthropic-ai/sandbox-runtime');
|
|
39
|
+
require('expo-server-sdk');
|
|
40
|
+
require('crypto');
|
|
41
|
+
require('ps-list');
|
|
42
|
+
require('tmp');
|
|
43
|
+
require('open');
|
|
44
|
+
require('fastify');
|
|
45
|
+
require('fastify-type-provider-zod');
|
|
46
|
+
require('node:module');
|
|
47
|
+
require('node:util');
|
|
48
|
+
require('http');
|
|
49
|
+
require('util');
|
|
50
|
+
require('inquirer');
|
|
51
|
+
require('node:url');
|
|
52
|
+
require('node:readline/promises');
|
|
53
|
+
require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
54
|
+
require('node-pty');
|
|
55
|
+
|
|
56
|
+
async function startPiTerminalTools(terminalId) {
|
|
57
|
+
const path = `/terminal-tools/${node_crypto.randomUUID()}`;
|
|
58
|
+
const server = node_http.createServer(async (req, res) => {
|
|
59
|
+
if (req.url !== path || req.headers.origin || req.method !== "POST") {
|
|
60
|
+
res.writeHead(403).end();
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const mcp$1 = new mcp_js.McpServer({ name: "Very Happy Terminal Tools", version: "1.0.0" });
|
|
64
|
+
mcp.registerMcpTools(mcp$1, "clipboard", terminalId);
|
|
65
|
+
const transport = new streamableHttp_js.StreamableHTTPServerTransport({ sessionIdGenerator: void 0 });
|
|
66
|
+
res.on("close", () => {
|
|
67
|
+
void transport.close();
|
|
68
|
+
void mcp$1.close();
|
|
69
|
+
});
|
|
70
|
+
try {
|
|
71
|
+
await mcp$1.connect(transport);
|
|
72
|
+
await transport.handleRequest(req, res);
|
|
73
|
+
} catch {
|
|
74
|
+
if (!res.headersSent) res.writeHead(500).end();
|
|
75
|
+
void mcp$1.close();
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
await new Promise((resolve, reject) => {
|
|
79
|
+
server.once("error", reject);
|
|
80
|
+
server.listen(0, "127.0.0.1", () => {
|
|
81
|
+
server.off("error", reject);
|
|
82
|
+
resolve();
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
return {
|
|
86
|
+
url: `http://127.0.0.1:${server.address().port}${path}`,
|
|
87
|
+
stop: () => new Promise((resolve, reject) => {
|
|
88
|
+
server.close((error) => error ? reject(error) : resolve());
|
|
89
|
+
server.closeAllConnections();
|
|
90
|
+
})
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
async function runPiTerminal(args) {
|
|
94
|
+
const terminalId = terminalToolContext.resolveMcpTerminalId({ VH_TERMINAL_ID: process.env.VH_TERMINAL_ID });
|
|
95
|
+
if (!terminalId) throw new Error("Run `very-happy pi --terminal` inside a Very Happy terminal (VH_TERMINAL_ID is required).");
|
|
96
|
+
const runtime = await piRuntime.preparePiTeamsRuntime();
|
|
97
|
+
const bridge = process.env.HAPPY_MCP_URL ? null : await startPiTerminalTools(terminalId);
|
|
98
|
+
try {
|
|
99
|
+
return await new Promise((resolve, reject) => {
|
|
100
|
+
const child = node_child_process.spawn(runtime.PI_ACP_PI_COMMAND, args, {
|
|
101
|
+
stdio: "inherit",
|
|
102
|
+
env: { ...process.env, ...runtime, ...bridge ? { HAPPY_TERMINAL_MCP_URL: bridge.url } : {} },
|
|
103
|
+
shell: process.platform === "win32"
|
|
104
|
+
});
|
|
105
|
+
const interrupt = () => {
|
|
106
|
+
child.kill("SIGINT");
|
|
107
|
+
};
|
|
108
|
+
const terminate = () => {
|
|
109
|
+
child.kill("SIGTERM");
|
|
110
|
+
};
|
|
111
|
+
const cleanup = () => {
|
|
112
|
+
process.off("SIGINT", interrupt);
|
|
113
|
+
process.off("SIGTERM", terminate);
|
|
114
|
+
};
|
|
115
|
+
process.on("SIGINT", interrupt);
|
|
116
|
+
process.on("SIGTERM", terminate);
|
|
117
|
+
child.once("error", (error) => {
|
|
118
|
+
cleanup();
|
|
119
|
+
reject(new Error(`Could not launch native pi: ${error.message}`));
|
|
120
|
+
});
|
|
121
|
+
child.once("exit", (code, signal) => {
|
|
122
|
+
cleanup();
|
|
123
|
+
resolve(code ?? (signal === "SIGINT" ? 130 : signal === "SIGTERM" ? 143 : 1));
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
} finally {
|
|
127
|
+
await bridge?.stop();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
exports.runPiTerminal = runPiTerminal;
|
|
132
|
+
exports.startPiTerminalTools = startPiTerminalTools;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { createServer } from 'node:http';
|
|
4
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
5
|
+
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
6
|
+
import { p as preparePiTeamsRuntime } from './piRuntime-BE6iYQwU.mjs';
|
|
7
|
+
import { registerMcpTools } from './mcp-CfbTQXyh.mjs';
|
|
8
|
+
import './agentGuidance-BU4hxm8M.mjs';
|
|
9
|
+
import 'node:fs/promises';
|
|
10
|
+
import 'node:os';
|
|
11
|
+
import 'zod';
|
|
12
|
+
import './limits-uABU-yq3.mjs';
|
|
13
|
+
import 'axios';
|
|
14
|
+
import 'tweetnacl';
|
|
15
|
+
import 'socket.io-client';
|
|
16
|
+
import './types-BG4gFjLL.mjs';
|
|
17
|
+
import 'node:fs';
|
|
18
|
+
import 'node:path';
|
|
19
|
+
import { r as resolveMcpTerminalId } from './terminalToolContext-CFeGeaNm.mjs';
|
|
20
|
+
import './index-DoiG88oX.mjs';
|
|
21
|
+
import 'chalk';
|
|
22
|
+
import 'cross-spawn';
|
|
23
|
+
import 'node:readline';
|
|
24
|
+
import './projectPath-CSpqWdxp.mjs';
|
|
25
|
+
import 'path';
|
|
26
|
+
import 'url';
|
|
27
|
+
import 'fs/promises';
|
|
28
|
+
import 'ink';
|
|
29
|
+
import 'react';
|
|
30
|
+
import '@anthropic-ai/claude-agent-sdk';
|
|
31
|
+
import 'node:events';
|
|
32
|
+
import 'os';
|
|
33
|
+
import 'child_process';
|
|
34
|
+
import '@paralleldrive/cuid2';
|
|
35
|
+
import 'fs';
|
|
36
|
+
import '@anthropic-ai/sandbox-runtime';
|
|
37
|
+
import 'expo-server-sdk';
|
|
38
|
+
import 'crypto';
|
|
39
|
+
import 'ps-list';
|
|
40
|
+
import 'tmp';
|
|
41
|
+
import 'open';
|
|
42
|
+
import 'fastify';
|
|
43
|
+
import 'fastify-type-provider-zod';
|
|
44
|
+
import 'node:module';
|
|
45
|
+
import 'node:util';
|
|
46
|
+
import 'http';
|
|
47
|
+
import 'util';
|
|
48
|
+
import 'inquirer';
|
|
49
|
+
import 'node:url';
|
|
50
|
+
import 'node:readline/promises';
|
|
51
|
+
import '@modelcontextprotocol/sdk/server/stdio.js';
|
|
52
|
+
import 'node-pty';
|
|
53
|
+
|
|
54
|
+
async function startPiTerminalTools(terminalId) {
|
|
55
|
+
const path = `/terminal-tools/${randomUUID()}`;
|
|
56
|
+
const server = createServer(async (req, res) => {
|
|
57
|
+
if (req.url !== path || req.headers.origin || req.method !== "POST") {
|
|
58
|
+
res.writeHead(403).end();
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const mcp = new McpServer({ name: "Very Happy Terminal Tools", version: "1.0.0" });
|
|
62
|
+
registerMcpTools(mcp, "clipboard", terminalId);
|
|
63
|
+
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: void 0 });
|
|
64
|
+
res.on("close", () => {
|
|
65
|
+
void transport.close();
|
|
66
|
+
void mcp.close();
|
|
67
|
+
});
|
|
68
|
+
try {
|
|
69
|
+
await mcp.connect(transport);
|
|
70
|
+
await transport.handleRequest(req, res);
|
|
71
|
+
} catch {
|
|
72
|
+
if (!res.headersSent) res.writeHead(500).end();
|
|
73
|
+
void mcp.close();
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
await new Promise((resolve, reject) => {
|
|
77
|
+
server.once("error", reject);
|
|
78
|
+
server.listen(0, "127.0.0.1", () => {
|
|
79
|
+
server.off("error", reject);
|
|
80
|
+
resolve();
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
return {
|
|
84
|
+
url: `http://127.0.0.1:${server.address().port}${path}`,
|
|
85
|
+
stop: () => new Promise((resolve, reject) => {
|
|
86
|
+
server.close((error) => error ? reject(error) : resolve());
|
|
87
|
+
server.closeAllConnections();
|
|
88
|
+
})
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
async function runPiTerminal(args) {
|
|
92
|
+
const terminalId = resolveMcpTerminalId({ VH_TERMINAL_ID: process.env.VH_TERMINAL_ID });
|
|
93
|
+
if (!terminalId) throw new Error("Run `very-happy pi --terminal` inside a Very Happy terminal (VH_TERMINAL_ID is required).");
|
|
94
|
+
const runtime = await preparePiTeamsRuntime();
|
|
95
|
+
const bridge = process.env.HAPPY_MCP_URL ? null : await startPiTerminalTools(terminalId);
|
|
96
|
+
try {
|
|
97
|
+
return await new Promise((resolve, reject) => {
|
|
98
|
+
const child = spawn(runtime.PI_ACP_PI_COMMAND, args, {
|
|
99
|
+
stdio: "inherit",
|
|
100
|
+
env: { ...process.env, ...runtime, ...bridge ? { HAPPY_TERMINAL_MCP_URL: bridge.url } : {} },
|
|
101
|
+
shell: process.platform === "win32"
|
|
102
|
+
});
|
|
103
|
+
const interrupt = () => {
|
|
104
|
+
child.kill("SIGINT");
|
|
105
|
+
};
|
|
106
|
+
const terminate = () => {
|
|
107
|
+
child.kill("SIGTERM");
|
|
108
|
+
};
|
|
109
|
+
const cleanup = () => {
|
|
110
|
+
process.off("SIGINT", interrupt);
|
|
111
|
+
process.off("SIGTERM", terminate);
|
|
112
|
+
};
|
|
113
|
+
process.on("SIGINT", interrupt);
|
|
114
|
+
process.on("SIGTERM", terminate);
|
|
115
|
+
child.once("error", (error) => {
|
|
116
|
+
cleanup();
|
|
117
|
+
reject(new Error(`Could not launch native pi: ${error.message}`));
|
|
118
|
+
});
|
|
119
|
+
child.once("exit", (code, signal) => {
|
|
120
|
+
cleanup();
|
|
121
|
+
resolve(code ?? (signal === "SIGINT" ? 130 : signal === "SIGTERM" ? 143 : 1));
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
} finally {
|
|
125
|
+
await bridge?.stop();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export { runPiTerminal, startPiTerminalTools };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { dirname, resolve } from 'path';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
|
|
4
|
+
const __dirname$1 = dirname(fileURLToPath(import.meta.url));
|
|
5
|
+
function projectPath() {
|
|
6
|
+
const path = resolve(__dirname$1, "..");
|
|
7
|
+
return path;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export { projectPath as p };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var path = require('path');
|
|
4
|
+
var url = require('url');
|
|
5
|
+
|
|
6
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
7
|
+
const __dirname$1 = path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('projectPath-ChLhdOyt.cjs', document.baseURI).href))));
|
|
8
|
+
function projectPath() {
|
|
9
|
+
const path$1 = path.resolve(__dirname$1, "..");
|
|
10
|
+
return path$1;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
exports.projectPath = projectPath;
|