@thurstonsand/ghosttykit 0.0.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 (42) hide show
  1. package/README.md +174 -0
  2. package/dist/src/client.d.ts +59 -0
  3. package/dist/src/client.d.ts.map +1 -0
  4. package/dist/src/client.js +271 -0
  5. package/dist/src/client.js.map +1 -0
  6. package/dist/src/codes.d.ts +14 -0
  7. package/dist/src/codes.d.ts.map +1 -0
  8. package/dist/src/codes.js +13 -0
  9. package/dist/src/codes.js.map +1 -0
  10. package/dist/src/errors.d.ts +41 -0
  11. package/dist/src/errors.d.ts.map +1 -0
  12. package/dist/src/errors.js +89 -0
  13. package/dist/src/errors.js.map +1 -0
  14. package/dist/src/index.d.ts +9 -0
  15. package/dist/src/index.d.ts.map +1 -0
  16. package/dist/src/index.js +6 -0
  17. package/dist/src/index.js.map +1 -0
  18. package/dist/src/paste-internal.d.ts +5 -0
  19. package/dist/src/paste-internal.d.ts.map +1 -0
  20. package/dist/src/paste-internal.js +259 -0
  21. package/dist/src/paste-internal.js.map +1 -0
  22. package/dist/src/paste.d.ts +42 -0
  23. package/dist/src/paste.d.ts.map +1 -0
  24. package/dist/src/paste.js +17 -0
  25. package/dist/src/paste.js.map +1 -0
  26. package/dist/src/protocol.d.ts +106 -0
  27. package/dist/src/protocol.d.ts.map +1 -0
  28. package/dist/src/protocol.js +132 -0
  29. package/dist/src/protocol.js.map +1 -0
  30. package/dist/src/socket.d.ts +7 -0
  31. package/dist/src/socket.d.ts.map +1 -0
  32. package/dist/src/socket.js +39 -0
  33. package/dist/src/socket.js.map +1 -0
  34. package/dist/test/client.test.d.ts +2 -0
  35. package/dist/test/client.test.d.ts.map +1 -0
  36. package/dist/test/client.test.js +174 -0
  37. package/dist/test/client.test.js.map +1 -0
  38. package/dist/test/protocol.test.d.ts +2 -0
  39. package/dist/test/protocol.test.d.ts.map +1 -0
  40. package/dist/test/protocol.test.js +25 -0
  41. package/dist/test/protocol.test.js.map +1 -0
  42. package/package.json +46 -0
@@ -0,0 +1,132 @@
1
+ import { protocolCodes } from "./codes.js";
2
+ export const protocolVersion = 1;
3
+ const replyModes = new WeakMap();
4
+ export function replyModeOf(request) {
5
+ return replyModes.get(request) ?? "frame";
6
+ }
7
+ export function encodeRequest(request) {
8
+ return `${JSON.stringify(request)}\n`;
9
+ }
10
+ export function doctorRequest() {
11
+ return envelope("doctor");
12
+ }
13
+ export function terminalIdRequest(options = {}) {
14
+ return compact({
15
+ ...envelope("terminal-id"),
16
+ tty: options.tty,
17
+ focused: optionalTrue(options.focused),
18
+ refresh: optionalTrue(options.refresh),
19
+ });
20
+ }
21
+ export function tabTerminalCountRequest(options = {}) {
22
+ return compact({
23
+ ...envelope("tab-terminal-count"),
24
+ tty: options.tty,
25
+ focused: optionalTrue(options.focused),
26
+ });
27
+ }
28
+ export function clearCacheRequest(options = {}) {
29
+ return withReplyMode(compact({
30
+ ...envelope("clear-cache"),
31
+ tty: options.tty,
32
+ ack: optionalTrue(options.ack),
33
+ }), ackReplyMode(options.ack));
34
+ }
35
+ export function keyTableActivateRequest(options) {
36
+ return withReplyMode(compact({
37
+ ...envelope("key-table-activate"),
38
+ tty: options.tty,
39
+ focused: optionalTrue(options.focused),
40
+ table: options.table,
41
+ ack: optionalTrue(options.ack),
42
+ }), ackReplyMode(options.ack));
43
+ }
44
+ export function keyTableDeactivateRequest(options = {}) {
45
+ return withReplyMode(compact({
46
+ ...envelope("key-table-deactivate"),
47
+ tty: options.tty,
48
+ focused: optionalTrue(options.focused),
49
+ ack: optionalTrue(options.ack),
50
+ }), ackReplyMode(options.ack));
51
+ }
52
+ export function focusRequest(options) {
53
+ return withReplyMode(compact({
54
+ ...envelope("focus"),
55
+ tty: options.tty,
56
+ focused: optionalTrue(options.focused),
57
+ direction: options.direction,
58
+ ack: optionalTrue(options.ack),
59
+ }), ackReplyMode(options.ack));
60
+ }
61
+ export function splitRequest(options) {
62
+ return withReplyMode(compact({
63
+ ...envelope("split"),
64
+ tty: options.tty,
65
+ focused: optionalTrue(options.focused),
66
+ direction: options.direction,
67
+ cwd: options.cwd,
68
+ commandText: options.commandText,
69
+ focus: options.focus,
70
+ ack: optionalTrue(options.ack),
71
+ }), ackReplyMode(options.ack));
72
+ }
73
+ export function resizeRequest(options) {
74
+ return withReplyMode(compact({
75
+ ...envelope("resize"),
76
+ tty: options.tty,
77
+ focused: optionalTrue(options.focused),
78
+ direction: options.direction,
79
+ amount: options.amount,
80
+ ack: optionalTrue(options.ack),
81
+ }), ackReplyMode(options.ack));
82
+ }
83
+ export function zoomRequest(options = {}) {
84
+ return withReplyMode(compact({
85
+ ...envelope("zoom"),
86
+ tty: options.tty,
87
+ focused: optionalTrue(options.focused),
88
+ ack: optionalTrue(options.ack),
89
+ }), ackReplyMode(options.ack));
90
+ }
91
+ export function pasteRequest(options = {}) {
92
+ return withReplyMode(compact({
93
+ ...envelope("paste"),
94
+ tty: options.tty,
95
+ }), "stream");
96
+ }
97
+ export function bridgeCreateRequest(options = {}) {
98
+ return compact({
99
+ ...envelope("bridge-create"),
100
+ tty: options.tty,
101
+ focused: optionalTrue(options.focused),
102
+ });
103
+ }
104
+ export function bridgeLeaseRequest(token) {
105
+ return withReplyMode({
106
+ ...envelope("bridge-lease"),
107
+ token,
108
+ }, "hold");
109
+ }
110
+ export { protocolCodes };
111
+ function envelope(command) {
112
+ return { version: protocolVersion, command };
113
+ }
114
+ function ackReplyMode(ack) {
115
+ return ack ? "frame" : "none";
116
+ }
117
+ function optionalTrue(value) {
118
+ return value ? true : undefined;
119
+ }
120
+ function compact(value) {
121
+ for (const key of Object.keys(value)) {
122
+ if (value[key] === undefined) {
123
+ delete value[key];
124
+ }
125
+ }
126
+ return value;
127
+ }
128
+ function withReplyMode(request, mode) {
129
+ replyModes.set(request, mode);
130
+ return request;
131
+ }
132
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import net from "node:net";
2
+ export declare function defaultSocketPath(): string;
3
+ export declare function socketPath(options?: {
4
+ socketPath?: string;
5
+ }): string;
6
+ export declare function dial(socketPathValue: string): Promise<net.Socket>;
7
+ //# sourceMappingURL=socket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../../src/socket.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;AAK3B,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,wBAAgB,UAAU,CAAC,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,MAAM,CAExE;AAED,wBAAgB,IAAI,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAmCjE"}
@@ -0,0 +1,39 @@
1
+ import net from "node:net";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { TransportError } from "./errors.js";
5
+ export function defaultSocketPath() {
6
+ return path.join(os.homedir(), ".local/run/ghosttykit/ghosttykitd.sock");
7
+ }
8
+ export function socketPath(options = {}) {
9
+ return options.socketPath || process.env.GTY_SOCK || defaultSocketPath();
10
+ }
11
+ export function dial(socketPathValue) {
12
+ if (!socketPathValue.trim()) {
13
+ return Promise.reject(new TransportError("socket path is empty"));
14
+ }
15
+ return new Promise((resolve, reject) => {
16
+ const socket = net.createConnection({ path: socketPathValue });
17
+ let settled = false;
18
+ function settle(handler, value) {
19
+ if (settled) {
20
+ return;
21
+ }
22
+ settled = true;
23
+ socket.off("connect", onConnect);
24
+ socket.off("error", onError);
25
+ handler(value);
26
+ }
27
+ function onConnect() {
28
+ settle(resolve, socket);
29
+ }
30
+ function onError(error) {
31
+ settle(reject, new TransportError(`connect ${socketPathValue}: ${error.message}`, {
32
+ cause: error,
33
+ }));
34
+ }
35
+ socket.once("connect", onConnect);
36
+ socket.once("error", onError);
37
+ });
38
+ }
39
+ //# sourceMappingURL=socket.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"socket.js","sourceRoot":"","sources":["../../src/socket.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;AAC3B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,UAAU,iBAAiB;IAC/B,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,wCAAwC,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,UAAmC,EAAE;IAC9D,OAAO,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,iBAAiB,EAAE,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,eAAuB;IAC1C,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,EAAE,CAAC;QAC5B,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,cAAc,CAAC,sBAAsB,CAAC,CAAC,CAAC;IACpE,CAAC;IAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAG,GAAG,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC;QAC/D,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,SAAS,MAAM,CAAI,OAA2B,EAAE,KAAQ;YACtD,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO;YACT,CAAC;YACD,OAAO,GAAG,IAAI,CAAC;YACf,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;YACjC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC7B,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC;QAED,SAAS,SAAS;YAChB,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1B,CAAC;QAED,SAAS,OAAO,CAAC,KAAY;YAC3B,MAAM,CACJ,MAAM,EACN,IAAI,cAAc,CAAC,WAAW,eAAe,KAAK,KAAK,CAAC,OAAO,EAAE,EAAE;gBACjE,KAAK,EAAE,KAAK;aACb,CAAC,CACH,CAAC;QACJ,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=client.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.test.d.ts","sourceRoot":"","sources":["../../test/client.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,174 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdtemp, readdir, readFile, rm } from "node:fs/promises";
3
+ import net from "node:net";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+ import test from "node:test";
7
+ import { GhosttyKitClient } from "../src/client.js";
8
+ import { InvalidReplyModeError, PasteEmptyError } from "../src/errors.js";
9
+ import { Paste } from "../src/paste.js";
10
+ import { doctorRequest, focusRequest, pasteRequest, } from "../src/protocol.js";
11
+ import { socketPath } from "../src/socket.js";
12
+ test("call rejects stream requests", async () => {
13
+ const client = new GhosttyKitClient({ socketPath: "unused.sock" });
14
+ await assert.rejects(client.call(pasteRequest()), InvalidReplyModeError);
15
+ });
16
+ test("stream rejects frame requests", async () => {
17
+ const client = new GhosttyKitClient({ socketPath: "unused.sock" });
18
+ await assert.rejects(client.stream(doctorRequest()), InvalidReplyModeError);
19
+ });
20
+ test("call maps protocol errors", async () => {
21
+ await withServer(async (socket) => {
22
+ await readRequest(socket);
23
+ socket.end('{"version":1,"code":"paste_empty","error":"clipboard empty"}\n');
24
+ }, async (socketPathValue) => {
25
+ const client = new GhosttyKitClient({ socketPath: socketPathValue });
26
+ await assert.rejects(client.call(doctorRequest()), PasteEmptyError);
27
+ });
28
+ });
29
+ test("stream preserves body bytes buffered with header", async () => {
30
+ await withServer(async (socket) => {
31
+ await readRequest(socket);
32
+ socket.end('{"version":1,"code":"ok","kind":"text","bytes":11}\nhello world');
33
+ }, async (socketPathValue) => {
34
+ const client = new GhosttyKitClient({ socketPath: socketPathValue });
35
+ const stream = await client.stream(pasteRequest());
36
+ const chunks = [];
37
+ for await (const chunk of stream.body) {
38
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
39
+ }
40
+ assert.equal(stream.header.kind, "text");
41
+ assert.equal(stream.header.bytes, 11);
42
+ assert.equal(Buffer.concat(chunks).toString("utf8"), "hello world");
43
+ });
44
+ });
45
+ test("paste returns consumable text paste", async () => {
46
+ await withServer(async (socket) => {
47
+ await readRequest(socket);
48
+ socket.end('{"version":1,"code":"ok","kind":"text","bytes":11}\nhello world');
49
+ }, async (socketPathValue) => {
50
+ const client = new GhosttyKitClient({ socketPath: socketPathValue });
51
+ const paste = await client.paste();
52
+ assert.equal(paste.kind, "text");
53
+ assert.equal(paste.byteLength, 11);
54
+ assert.equal(paste.state, "pending");
55
+ assert.equal(await paste.text(), "hello world");
56
+ assert.equal(paste.state, "consumed");
57
+ await assert.rejects(paste.raw(), /already been consumed/);
58
+ });
59
+ });
60
+ test("paste saves streamed files and exposes metadata", async () => {
61
+ await withServer(async (socket) => {
62
+ await readRequest(socket);
63
+ socket.end('{"version":1,"code":"ok","kind":"files","bytes":11,"files":[{"fileName":"../hello world.txt","mediaType":"text/plain","bytes":5,"source":"one"},{"mediaType":"image/png","bytes":6,"source":"two"}]}\nhelloworld!');
64
+ }, async (socketPathValue) => {
65
+ const outputDir = await mkdtemp(path.join(os.tmpdir(), "ghosttykit-paste-save-"));
66
+ try {
67
+ const client = new GhosttyKitClient({ socketPath: socketPathValue });
68
+ const paste = await client.paste();
69
+ const files = await Paste.match(paste, {
70
+ text: () => assert.fail("expected files paste"),
71
+ files: (paste) => paste.save(outputDir),
72
+ });
73
+ assert.equal(files.length, 2);
74
+ assert.equal(files[0]?.byteLength, 5);
75
+ assert.equal(files[0]?.mediaType, "text/plain");
76
+ assert.match(path.basename(files[0]?.path ?? ""), /^hello world-[0-9a-f-]+\.txt$/);
77
+ assert.match(path.basename(files[1]?.path ?? ""), /^pasted-file-[0-9a-f-]+\.png$/);
78
+ assert.equal(await readFile(files[0]?.path ?? "", "utf8"), "hello");
79
+ assert.equal(await readFile(files[1]?.path ?? "", "utf8"), "world!");
80
+ assert.equal((await readdir(outputDir)).length, 2);
81
+ }
82
+ finally {
83
+ await rm(outputDir, { recursive: true, force: true });
84
+ }
85
+ });
86
+ });
87
+ test("text paste can save to a generated text file", async () => {
88
+ await withServer(async (socket) => {
89
+ await readRequest(socket);
90
+ socket.end('{"version":1,"code":"ok","kind":"text","bytes":11}\nhello world');
91
+ }, async (socketPathValue) => {
92
+ const outputDir = await mkdtemp(path.join(os.tmpdir(), "ghosttykit-text-save-"));
93
+ try {
94
+ const client = new GhosttyKitClient({ socketPath: socketPathValue });
95
+ const paste = await client.paste();
96
+ const files = await Paste.match(paste, {
97
+ text: (paste) => paste.save(outputDir),
98
+ files: () => assert.fail("expected text paste"),
99
+ });
100
+ assert.equal(files.length, 1);
101
+ assert.equal(files[0]?.byteLength, 11);
102
+ assert.equal(files[0]?.mediaType, "text/plain");
103
+ assert.match(path.basename(files[0]?.path ?? ""), /^pasted-text-[0-9a-f-]+\.txt$/);
104
+ assert.equal(await readFile(files[0]?.path ?? "", "utf8"), "hello world");
105
+ }
106
+ finally {
107
+ await rm(outputDir, { recursive: true, force: true });
108
+ }
109
+ });
110
+ });
111
+ test("notify waits for daemon close without reply bytes", async () => {
112
+ await withServer(async (socket) => {
113
+ await readRequest(socket);
114
+ socket.end();
115
+ }, async (socketPathValue) => {
116
+ const client = new GhosttyKitClient({ socketPath: socketPathValue });
117
+ await client.notify(focusRequest({ direction: "left" }));
118
+ });
119
+ });
120
+ test("socketPath prefers explicit path, then GTY_SOCK", () => {
121
+ const previous = process.env.GTY_SOCK;
122
+ process.env.GTY_SOCK = "/tmp/gty.sock";
123
+ try {
124
+ assert.equal(socketPath({ socketPath: "/tmp/explicit.sock" }), "/tmp/explicit.sock");
125
+ assert.equal(socketPath(), "/tmp/gty.sock");
126
+ }
127
+ finally {
128
+ if (previous === undefined) {
129
+ delete process.env.GTY_SOCK;
130
+ }
131
+ else {
132
+ process.env.GTY_SOCK = previous;
133
+ }
134
+ }
135
+ });
136
+ async function withServer(handle, run) {
137
+ const directory = await mkdtemp(path.join(os.tmpdir(), "ghosttykit-ts-"));
138
+ const socketPathValue = path.join(directory, "daemon.sock");
139
+ const server = net.createServer((socket) => {
140
+ void handle(socket).catch((error) => socket.destroy(error));
141
+ });
142
+ try {
143
+ await new Promise((resolve, reject) => {
144
+ server.once("error", reject);
145
+ server.listen(socketPathValue, resolve);
146
+ });
147
+ await run(socketPathValue);
148
+ }
149
+ finally {
150
+ await new Promise((resolve, reject) => {
151
+ server.close((error) => (error ? reject(error) : resolve()));
152
+ });
153
+ await rm(directory, { recursive: true, force: true });
154
+ }
155
+ }
156
+ function readRequest(socket) {
157
+ return new Promise((resolve, reject) => {
158
+ let data = "";
159
+ socket.on("data", (chunk) => {
160
+ data += chunk.toString("utf8");
161
+ if (!data.includes("\n")) {
162
+ return;
163
+ }
164
+ try {
165
+ resolve(JSON.parse(data.split("\n", 1)[0] ?? ""));
166
+ }
167
+ catch (error) {
168
+ reject(error);
169
+ }
170
+ });
171
+ socket.once("error", reject);
172
+ });
173
+ }
174
+ //# sourceMappingURL=client.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.test.js","sourceRoot":"","sources":["../../test/client.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=protocol.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.test.d.ts","sourceRoot":"","sources":["../../test/protocol.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,25 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import { encodeRequest, focusRequest, pasteRequest, replyModeOf, terminalIdRequest, } from "../src/protocol.js";
4
+ test("encodes request envelopes without reply metadata", () => {
5
+ const request = focusRequest({
6
+ tty: "/dev/ttys001",
7
+ direction: "left",
8
+ ack: true,
9
+ });
10
+ const encoded = encodeRequest(request);
11
+ const decoded = JSON.parse(encoded);
12
+ assert.equal(decoded.version, 1);
13
+ assert.equal(decoded.command, "focus");
14
+ assert.equal(decoded.tty, "/dev/ttys001");
15
+ assert.equal(decoded.direction, "left");
16
+ assert.equal(decoded.ack, true);
17
+ assert.equal(decoded.replyMode, undefined);
18
+ });
19
+ test("reports reply modes", () => {
20
+ assert.equal(replyModeOf(terminalIdRequest()), "frame");
21
+ assert.equal(replyModeOf(focusRequest({ direction: "left" })), "none");
22
+ assert.equal(replyModeOf(focusRequest({ direction: "left", ack: true })), "frame");
23
+ assert.equal(replyModeOf(pasteRequest()), "stream");
24
+ });
25
+ //# sourceMappingURL=protocol.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.test.js","sourceRoot":"","sources":["../../test/protocol.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAE5B,IAAI,CAAC,kDAAkD,EAAE,GAAG,EAAE;IAC5D,MAAM,OAAO,GAAG,YAAY,CAAC;QAC3B,GAAG,EAAE,cAAc;QACnB,SAAS,EAAE,MAAM;QACjB,GAAG,EAAE,IAAI;KACV,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAEpC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACjC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACvC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAC1C,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACxC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAChC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AAC7C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,qBAAqB,EAAE,GAAG,EAAE;IAC/B,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,iBAAiB,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;IACxD,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACvE,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACnF,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC;AACtD,CAAC,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@thurstonsand/ghosttykit",
3
+ "version": "0.0.0",
4
+ "type": "module",
5
+ "description": "TypeScript SDK for GhosttyKit daemon clients",
6
+ "license": "MIT",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "homepage": "https://github.com/thurstonsand/ghosttykit",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/thurstonsand/ghosttykit.git",
14
+ "directory": "sdk/ts"
15
+ },
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/src/index.d.ts",
19
+ "import": "./dist/src/index.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "README.md"
25
+ ],
26
+ "scripts": {
27
+ "fmt": "biome format --write .",
28
+ "lint": "biome check .",
29
+ "typecheck": "tsc --noEmit",
30
+ "build": "tsc",
31
+ "test": "npm run build && node --test dist/test/*.test.js",
32
+ "check": "npm run fmt && npm run lint && npm run typecheck && npm run test",
33
+ "prepare": "npm run build"
34
+ },
35
+ "devDependencies": {
36
+ "@biomejs/biome": "2.4.15",
37
+ "@types/mime-types": "^3.0.1",
38
+ "@types/node": "^25.6.2",
39
+ "@types/sanitize-filename": "^1.1.28",
40
+ "typescript": "^6.0.3"
41
+ },
42
+ "dependencies": {
43
+ "mime-types": "^3.0.2",
44
+ "sanitize-filename": "^1.6.4"
45
+ }
46
+ }