@nema-project/nema 0.0.0-stage → 0.1.3

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 (114) hide show
  1. package/LICENSE +21 -0
  2. package/dist/chunks/chunk-HEIQINX3.js +825 -0
  3. package/dist/chunks/chunk-WT3XUFWU.js +86 -0
  4. package/dist/claude/adapter.d.ts +19 -0
  5. package/dist/claude/adapter.js +258 -0
  6. package/dist/claude/events.d.ts +29 -0
  7. package/dist/claude/events.js +75 -0
  8. package/dist/claude/launch.d.ts +22 -0
  9. package/dist/claude/launch.js +80 -0
  10. package/dist/claude/token.d.ts +9 -0
  11. package/dist/claude/token.js +87 -0
  12. package/dist/codex/adapter.d.ts +17 -0
  13. package/dist/codex/adapter.js +151 -0
  14. package/dist/codex/events.d.ts +16 -0
  15. package/dist/codex/events.js +47 -0
  16. package/dist/codex/isolation.d.ts +33 -0
  17. package/dist/codex/isolation.js +115 -0
  18. package/dist/config.d.ts +29 -0
  19. package/dist/config.js +75 -0
  20. package/dist/configCommands.d.ts +13 -0
  21. package/dist/configCommands.js +69 -0
  22. package/dist/daemon/cleanup.d.ts +5 -0
  23. package/dist/daemon/cleanup.js +49 -0
  24. package/dist/daemon/connection.d.ts +22 -0
  25. package/dist/daemon/connection.js +166 -0
  26. package/dist/daemon/rpc.d.ts +14 -0
  27. package/dist/daemon/rpc.js +20 -0
  28. package/dist/daemon/runner.d.ts +34 -0
  29. package/dist/daemon/runner.js +94 -0
  30. package/dist/daemon/setup.d.ts +39 -0
  31. package/dist/daemon/setup.js +95 -0
  32. package/dist/direct/adapter.d.ts +30 -0
  33. package/dist/direct/adapter.js +190 -0
  34. package/dist/direct/authCommands.d.ts +54 -0
  35. package/dist/direct/authCommands.js +268 -0
  36. package/dist/direct/authStore.d.ts +120 -0
  37. package/dist/direct/authStore.js +351 -0
  38. package/dist/direct/byok.d.ts +27 -0
  39. package/dist/direct/byok.js +67 -0
  40. package/dist/direct/codexLogin.d.ts +34 -0
  41. package/dist/direct/codexLogin.js +93 -0
  42. package/dist/direct/jwt.d.ts +4 -0
  43. package/dist/direct/jwt.js +22 -0
  44. package/dist/direct/lock.d.ts +16 -0
  45. package/dist/direct/lock.js +134 -0
  46. package/dist/direct/loop.d.ts +33 -0
  47. package/dist/direct/loop.js +110 -0
  48. package/dist/direct/siwc.d.ts +63 -0
  49. package/dist/direct/siwc.js +403 -0
  50. package/dist/direct/tools.d.ts +17 -0
  51. package/dist/direct/tools.js +104 -0
  52. package/dist/direct/transport.d.ts +177 -0
  53. package/dist/direct/transport.js +437 -0
  54. package/dist/doctor.d.ts +28 -0
  55. package/dist/doctor.js +178 -0
  56. package/dist/extensions/handlers.d.ts +2 -0
  57. package/dist/extensions/handlers.js +10 -0
  58. package/dist/extensions/store.d.ts +11 -0
  59. package/dist/extensions/store.js +132 -0
  60. package/dist/github/client.d.ts +47 -0
  61. package/dist/github/client.js +383 -0
  62. package/dist/github/gh.d.ts +56 -0
  63. package/dist/github/gh.js +385 -0
  64. package/dist/index.d.ts +2 -0
  65. package/dist/index.js +144 -0
  66. package/dist/localSettings.d.ts +8 -0
  67. package/dist/localSettings.js +26 -0
  68. package/dist/mcp/server.d.ts +5 -0
  69. package/dist/mcp/server.js +83 -0
  70. package/dist/ownedProcess.d.ts +39 -0
  71. package/dist/ownedProcess.js +229 -0
  72. package/dist/platform.d.ts +10 -0
  73. package/dist/platform.js +60 -0
  74. package/dist/report/commands.d.ts +41 -0
  75. package/dist/report/commands.js +159 -0
  76. package/dist/report/desktop.d.ts +3 -0
  77. package/dist/report/desktop.js +123 -0
  78. package/dist/report/git.d.ts +5 -0
  79. package/dist/report/git.js +42 -0
  80. package/dist/report/install.d.ts +22 -0
  81. package/dist/report/install.js +183 -0
  82. package/dist/report/send.d.ts +35 -0
  83. package/dist/report/send.js +208 -0
  84. package/dist/report/token.d.ts +5 -0
  85. package/dist/report/token.js +86 -0
  86. package/dist/repos/git.d.ts +48 -0
  87. package/dist/repos/git.js +370 -0
  88. package/dist/repos/graphify.d.ts +32 -0
  89. package/dist/repos/graphify.js +292 -0
  90. package/dist/repos/handlers.d.ts +20 -0
  91. package/dist/repos/handlers.js +255 -0
  92. package/dist/repos/indexState.d.ts +10 -0
  93. package/dist/repos/indexState.js +45 -0
  94. package/dist/repos/pickDirectory.d.ts +11 -0
  95. package/dist/repos/pickDirectory.js +140 -0
  96. package/dist/repos/reportCheck.d.ts +13 -0
  97. package/dist/repos/reportCheck.js +268 -0
  98. package/dist/repos/watcher.d.ts +64 -0
  99. package/dist/repos/watcher.js +202 -0
  100. package/dist/room/client.d.ts +26 -0
  101. package/dist/room/client.js +76 -0
  102. package/dist/secrets/file.d.ts +12 -0
  103. package/dist/secrets/file.js +89 -0
  104. package/dist/secrets/github.d.ts +10 -0
  105. package/dist/secrets/github.js +29 -0
  106. package/dist/secrets/permissions.d.ts +7 -0
  107. package/dist/secrets/permissions.js +86 -0
  108. package/dist/systemGit.d.ts +14 -0
  109. package/dist/systemGit.js +75 -0
  110. package/dist/wp/commands.d.ts +15 -0
  111. package/dist/wp/commands.js +103 -0
  112. package/package.json +26 -4
  113. package/src/report/SKILL.md +21 -0
  114. package/README.md +0 -3
@@ -0,0 +1,383 @@
1
+ import {
2
+ runHelperFile
3
+ } from "../chunks/chunk-WT3XUFWU.js";
4
+ import {
5
+ GH_COMMAND_TOOLS,
6
+ PLUGINS
7
+ } from "../chunks/chunk-HEIQINX3.js";
8
+
9
+ // github/client.js
10
+ import { execFile, spawn } from "node:child_process";
11
+ import { mkdirSync } from "node:fs";
12
+ import path from "node:path";
13
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
14
+ import { ReadBuffer, serializeMessage } from "@modelcontextprotocol/sdk/shared/stdio.js";
15
+ import { readGithubToken } from "../secrets/github.js";
16
+ import { commandSpec, windowsRuntimeEnv } from "../platform.js";
17
+ var GITHUB_ARGS = ["stdio", "--read-only", "--toolsets", "pull_requests,issues"];
18
+ var NOT_INSTALLED = "github-mcp-server \u672A\u5B89\u88C5";
19
+ var STOPPED = "GitHub \u63D2\u4EF6\u5DF2\u505C\u6B62";
20
+ var TIMED_OUT = "GitHub \u63D2\u4EF6\u8C03\u7528\u8D85\u65F6";
21
+ var START_FAILED = "GitHub \u63D2\u4EF6\u542F\u52A8\u5931\u8D25";
22
+ var MAX_TEXT = 65536;
23
+ var CALL_TIMEOUT_MS = 6e4;
24
+ var RETRY_DELAY_MS = 6e4;
25
+ var STATUS_TIMEOUT_MS = 1e4;
26
+ var GITHUB_TOOLS = (PLUGINS.find((plugin) => plugin.id === "github")?.functions ?? []).map((fn) => fn.name.slice("github__".length)).filter((name) => !GH_COMMAND_TOOLS.includes(name));
27
+ var noTool = (tool) => new Error(`GitHub \u63D2\u4EF6\u6CA1\u6709\u5DE5\u5177 ${tool}`);
28
+ function cutUtf8(text, maxBytes) {
29
+ if (Buffer.byteLength(text) <= maxBytes)
30
+ return text;
31
+ let bytes = 0;
32
+ let index = 0;
33
+ for (const ch of text) {
34
+ const size = Buffer.byteLength(ch);
35
+ if (bytes + size > maxBytes)
36
+ break;
37
+ bytes += size;
38
+ index += ch.length;
39
+ }
40
+ return text.slice(0, index);
41
+ }
42
+ var ExactEnvStdioTransport = class {
43
+ bin;
44
+ env;
45
+ cwd;
46
+ ownedHelpers;
47
+ child;
48
+ buffer = new ReadBuffer();
49
+ closing;
50
+ spawnedChild;
51
+ startPromise;
52
+ closed = false;
53
+ onclose;
54
+ onerror;
55
+ onmessage;
56
+ constructor(bin, env, cwd, ownedHelpers) {
57
+ this.bin = bin;
58
+ this.env = env;
59
+ this.cwd = cwd;
60
+ this.ownedHelpers = ownedHelpers;
61
+ }
62
+ start() {
63
+ if (this.ownedHelpers) {
64
+ this.startPromise = this.startOwned();
65
+ return this.startPromise;
66
+ }
67
+ return new Promise((resolve, reject) => {
68
+ const command = commandSpec(this.bin, [...GITHUB_ARGS], this.env);
69
+ const child = spawn(command.bin, command.args, { env: this.env, cwd: this.cwd, stdio: ["pipe", "pipe", "ignore"], shell: false, windowsHide: true });
70
+ this.child = child;
71
+ this.spawnedChild = child;
72
+ let spawned = false;
73
+ child.on("error", (error) => {
74
+ if (!spawned)
75
+ reject(error);
76
+ else
77
+ this.onerror?.(error);
78
+ });
79
+ child.on("spawn", () => {
80
+ spawned = true;
81
+ resolve();
82
+ });
83
+ child.on("close", () => {
84
+ this.child = void 0;
85
+ this.onclose?.();
86
+ });
87
+ child.stdin?.on("error", (error) => this.onerror?.(error));
88
+ child.stdout?.on("data", (chunk) => this.readMessages(chunk));
89
+ });
90
+ }
91
+ async startOwned() {
92
+ const command = commandSpec(this.bin, [...GITHUB_ARGS], this.env);
93
+ const child = await this.ownedHelpers.spawn(command.bin, command.args, {
94
+ env: this.env,
95
+ cwd: this.cwd,
96
+ stdio: ["pipe", "pipe", "ignore"],
97
+ windowsHide: true
98
+ });
99
+ if (this.closed) {
100
+ child.kill("SIGTERM");
101
+ await child.closed;
102
+ throw new Error(STOPPED);
103
+ }
104
+ this.child = child;
105
+ this.spawnedChild = child;
106
+ void child.closed.then(() => {
107
+ this.child = void 0;
108
+ this.onclose?.();
109
+ });
110
+ child.stdin?.on("error", (error) => this.onerror?.(error));
111
+ child.stdout?.on("data", (chunk) => this.readMessages(chunk));
112
+ }
113
+ readMessages(chunk) {
114
+ this.buffer.append(chunk);
115
+ for (; ; ) {
116
+ let message;
117
+ try {
118
+ message = this.buffer.readMessage();
119
+ } catch (error) {
120
+ this.onerror?.(error);
121
+ continue;
122
+ }
123
+ if (message === null)
124
+ break;
125
+ this.onmessage?.(message);
126
+ }
127
+ }
128
+ send(message) {
129
+ return new Promise((resolve, reject) => {
130
+ const stdin = this.child?.stdin;
131
+ if (!stdin || !stdin.writable) {
132
+ reject(new Error(STOPPED));
133
+ return;
134
+ }
135
+ if (stdin.write(serializeMessage(message)))
136
+ resolve();
137
+ else
138
+ stdin.once("drain", resolve);
139
+ });
140
+ }
141
+ async close() {
142
+ if (this.closing)
143
+ return this.closing;
144
+ this.closed = true;
145
+ this.closing = this.closeChild();
146
+ return this.closing;
147
+ }
148
+ async closeChild() {
149
+ if (this.startPromise)
150
+ await this.startPromise.catch(() => {
151
+ });
152
+ const child = this.spawnedChild;
153
+ this.child = void 0;
154
+ this.buffer.clear();
155
+ if (child && !isChildProcess(child)) {
156
+ child.kill("SIGTERM");
157
+ await child.closed;
158
+ return;
159
+ }
160
+ if (child && child.exitCode === null && child.signalCode === null) {
161
+ await new Promise((resolve) => {
162
+ let killTimer;
163
+ const done = () => {
164
+ if (killTimer)
165
+ clearTimeout(killTimer);
166
+ resolve();
167
+ };
168
+ child.once("close", done);
169
+ try {
170
+ child.kill("SIGTERM");
171
+ } catch {
172
+ }
173
+ killTimer = setTimeout(() => {
174
+ try {
175
+ child.kill("SIGKILL");
176
+ } catch {
177
+ }
178
+ }, 2e3);
179
+ killTimer.unref();
180
+ });
181
+ }
182
+ }
183
+ };
184
+ function isChildProcess(child) {
185
+ return "exitCode" in child;
186
+ }
187
+ var GithubMcp = class {
188
+ opts;
189
+ conn = null;
190
+ starting = null;
191
+ startError = null;
192
+ closed = false;
193
+ closing;
194
+ startingTransport;
195
+ constructor(opts) {
196
+ this.opts = opts;
197
+ }
198
+ get bin() {
199
+ return this.opts.bin || "github-mcp-server";
200
+ }
201
+ homeDir() {
202
+ const dir = path.join(this.opts.nemaHome, "run", "github", "home");
203
+ mkdirSync(dir, { recursive: true, mode: 448 });
204
+ return dir;
205
+ }
206
+ basePath() {
207
+ return this.opts.spawnEnv?.PATH ?? process.env.PATH ?? "";
208
+ }
209
+ warn(message) {
210
+ (this.opts.warn ?? ((m) => console.warn(m)))(message);
211
+ }
212
+ /** `installed`: the binary runs. `loggedIn`: the token file is readable. Never starts the server. */
213
+ async status() {
214
+ let loggedIn = true;
215
+ let tokenDetail = "";
216
+ try {
217
+ readGithubToken(this.opts.nemaHome);
218
+ } catch (e) {
219
+ loggedIn = false;
220
+ tokenDetail = e instanceof Error ? e.message : String(e);
221
+ }
222
+ const version = await this.version();
223
+ if (!version.ok)
224
+ return { installed: false, loggedIn, detail: version.detail };
225
+ return { installed: true, loggedIn, detail: loggedIn ? version.detail : tokenDetail };
226
+ }
227
+ version() {
228
+ const home = this.homeDir();
229
+ const command = commandSpec(this.bin, ["--version"]);
230
+ if (this.opts.ownedHelpers) {
231
+ return runHelperFile(command.bin, command.args, {
232
+ env: { ...windowsRuntimeEnv(process.env), PATH: this.basePath(), HOME: home },
233
+ cwd: home,
234
+ timeout: STATUS_TIMEOUT_MS,
235
+ maxBuffer: 1024 * 1024,
236
+ encoding: "utf8"
237
+ }, this.opts.ownedHelpers).then((result) => result.error ? { ok: false, detail: result.error.code === "ENOENT" ? NOT_INSTALLED : START_FAILED } : { ok: true, detail: cutUtf8(result.stdout.toString("utf8").trim(), 200) });
238
+ }
239
+ return new Promise((resolve) => {
240
+ execFile(command.bin, command.args, { env: { ...windowsRuntimeEnv(process.env), PATH: this.basePath(), HOME: home }, cwd: home, timeout: STATUS_TIMEOUT_MS, shell: false, maxBuffer: 1024 * 1024 }, (error, stdout) => {
241
+ if (error) {
242
+ resolve({ ok: false, detail: error.code === "ENOENT" ? NOT_INSTALLED : START_FAILED });
243
+ return;
244
+ }
245
+ resolve({ ok: true, detail: cutUtf8(String(stdout).trim(), 200) });
246
+ });
247
+ });
248
+ }
249
+ /** Calls one fixed read tool and returns its text content, capped at 64 KB. */
250
+ async call(tool, args) {
251
+ if (!GITHUB_TOOLS.includes(tool))
252
+ throw noTool(tool);
253
+ if (this.closed)
254
+ throw new Error(STOPPED);
255
+ const conn = await this.ensure();
256
+ if (!conn.tools.has(tool))
257
+ throw noTool(tool);
258
+ let result;
259
+ try {
260
+ result = await Promise.race([
261
+ conn.client.callTool({ name: tool, arguments: args }, void 0, {
262
+ timeout: this.opts.timeoutMs ?? CALL_TIMEOUT_MS
263
+ }),
264
+ conn.stopped
265
+ ]);
266
+ } catch (e) {
267
+ if (!conn.alive)
268
+ throw new Error(STOPPED);
269
+ const message = e instanceof Error ? e.message : String(e);
270
+ if (/timed out|timeout/i.test(message))
271
+ throw new Error(TIMED_OUT);
272
+ throw new Error(`GitHub \u63D2\u4EF6\u8C03\u7528\u5931\u8D25\uFF1A${cutUtf8(message, 2e3)}`);
273
+ }
274
+ const content = Array.isArray(result.content) ? result.content : [];
275
+ const text = content.filter((item) => item.type === "text" && typeof item.text === "string").map((item) => item.text).join("\n");
276
+ if (result.isError)
277
+ throw new Error(`GitHub\uFF1A${cutUtf8(text, 2e3)}`);
278
+ return cutUtf8(text, MAX_TEXT);
279
+ }
280
+ async ensure() {
281
+ if (this.conn?.alive)
282
+ return this.conn;
283
+ const token = readGithubToken(this.opts.nemaHome);
284
+ if (this.startError && Date.now() < this.startError.until)
285
+ throw new Error(this.startError.message);
286
+ if (!this.starting) {
287
+ this.starting = this.start(token).then((conn) => {
288
+ this.starting = null;
289
+ this.startError = null;
290
+ this.conn = conn;
291
+ return conn;
292
+ }, (error) => {
293
+ this.starting = null;
294
+ const message = error instanceof Error ? error.message : String(error);
295
+ this.startError = { message, until: Date.now() + (this.opts.retryDelayMs ?? RETRY_DELAY_MS) };
296
+ throw new Error(message);
297
+ });
298
+ }
299
+ return this.starting;
300
+ }
301
+ async start(token) {
302
+ if (this.closed)
303
+ throw new Error(STOPPED);
304
+ const home = this.homeDir();
305
+ const transport = new ExactEnvStdioTransport(this.bin, { ...windowsRuntimeEnv(process.env), PATH: this.basePath(), HOME: home, GITHUB_PERSONAL_ACCESS_TOKEN: token }, home, this.opts.ownedHelpers);
306
+ this.startingTransport = transport;
307
+ const client = new Client({ name: "nema-daemon", version: "0.1.0" });
308
+ let markStopped = () => {
309
+ };
310
+ const stopped = new Promise((_, reject) => {
311
+ markStopped = reject;
312
+ });
313
+ stopped.catch(() => {
314
+ });
315
+ const conn = { client, transport, tools: /* @__PURE__ */ new Set(), alive: true, stopped };
316
+ client.onclose = () => {
317
+ conn.alive = false;
318
+ if (this.conn === conn)
319
+ this.conn = null;
320
+ markStopped(new Error(STOPPED));
321
+ };
322
+ client.onerror = () => {
323
+ };
324
+ try {
325
+ await client.connect(transport, { timeout: this.opts.timeoutMs ?? CALL_TIMEOUT_MS });
326
+ const listed = await client.listTools(void 0, { timeout: this.opts.timeoutMs ?? CALL_TIMEOUT_MS });
327
+ const offered = new Set(listed.tools.map((item) => item.name));
328
+ for (const tool of GITHUB_TOOLS) {
329
+ if (offered.has(tool))
330
+ conn.tools.add(tool);
331
+ else
332
+ this.warn(`[nema] github-mcp-server \u6CA1\u6709\u5DE5\u5177 ${tool}\uFF0C\u5DF2\u8DF3\u8FC7`);
333
+ }
334
+ } catch (e) {
335
+ conn.alive = false;
336
+ await transport.close().catch(() => {
337
+ });
338
+ if (this.startingTransport === transport)
339
+ this.startingTransport = void 0;
340
+ if (this.closed)
341
+ throw new Error(STOPPED);
342
+ if (e.code === "ENOENT")
343
+ throw new Error(NOT_INSTALLED);
344
+ throw new Error(START_FAILED);
345
+ }
346
+ if (this.closed) {
347
+ conn.alive = false;
348
+ await transport.close().catch(() => {
349
+ });
350
+ if (this.startingTransport === transport)
351
+ this.startingTransport = void 0;
352
+ throw new Error(STOPPED);
353
+ }
354
+ if (this.startingTransport === transport)
355
+ this.startingTransport = void 0;
356
+ return conn;
357
+ }
358
+ close() {
359
+ if (this.closing)
360
+ return this.closing;
361
+ this.closed = true;
362
+ const conn = this.conn;
363
+ this.conn = null;
364
+ if (conn) {
365
+ conn.alive = false;
366
+ conn.client.onclose?.();
367
+ }
368
+ const starting = this.starting;
369
+ this.closing = Promise.all([
370
+ conn?.transport.close() ?? Promise.resolve(),
371
+ this.startingTransport?.close() ?? Promise.resolve(),
372
+ starting?.then((pending) => pending.transport.close(), () => {
373
+ }) ?? Promise.resolve()
374
+ ]).then(() => {
375
+ });
376
+ return this.closing;
377
+ }
378
+ };
379
+ export {
380
+ GITHUB_ARGS,
381
+ GITHUB_TOOLS,
382
+ GithubMcp
383
+ };
@@ -0,0 +1,56 @@
1
+ import type { OwnedHelperScope } from "@nema/shared/ownedHelper";
2
+ export type GithubStatus = {
3
+ installed: boolean;
4
+ loggedIn: boolean;
5
+ detail: string;
6
+ };
7
+ export interface GithubReader {
8
+ call(tool: string, args: object): Promise<unknown>;
9
+ status(): Promise<GithubStatus>;
10
+ close(): Promise<void>;
11
+ }
12
+ export type GithubRequest = {
13
+ kind: "rest";
14
+ endpoint: string;
15
+ fields: Record<string, string>;
16
+ accept?: string;
17
+ } | {
18
+ kind: "graphql";
19
+ query: string;
20
+ variables: Record<string, unknown>;
21
+ } | {
22
+ kind: "pr_status";
23
+ owner: string;
24
+ repo: string;
25
+ number: number;
26
+ fields: Record<string, string>;
27
+ } | {
28
+ kind: "check_runs";
29
+ owner: string;
30
+ repo: string;
31
+ number: number;
32
+ fields: Record<string, string>;
33
+ };
34
+ /** Translate the six declared GitHub tools into reviewed, fixed read-only API requests. */
35
+ export declare function githubApiRequest(tool: string, input: object): GithubRequest;
36
+ export type GithubGhOptions = {
37
+ bin?: string;
38
+ env?: NodeJS.ProcessEnv;
39
+ ownedHelpers?: OwnedHelperScope;
40
+ timeoutMs?: number;
41
+ };
42
+ export declare class GithubGh implements GithubReader {
43
+ private readonly options;
44
+ private readonly abort;
45
+ private closed;
46
+ private readonly pending;
47
+ constructor(options?: GithubGhOptions);
48
+ private get bin();
49
+ private get env();
50
+ private execute;
51
+ /** `github__gh_read` / `github__gh_write`: the hub already scoped the call; the table is applied again here. */
52
+ private command;
53
+ call(tool: string, args: object): Promise<unknown>;
54
+ status(): Promise<GithubStatus>;
55
+ close(): Promise<void>;
56
+ }