@noelclawai/crew 0.1.4

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 noelclaw
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/args.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ export interface McpCliOptions {
2
+ readonly petId?: string;
3
+ readonly help: boolean;
4
+ readonly version: boolean;
5
+ }
6
+ export declare function parseMcpArgs(argv: readonly string[]): McpCliOptions;
7
+ export declare function validatePetId(value: string): string;
8
+ export declare function validateRawPetArg(value: string): string;
9
+ export declare function createHelpText(): string;
10
+ //# sourceMappingURL=args.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,aAAa,CA8BnE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKnD;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOvD;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC"}
package/dist/args.js ADDED
@@ -0,0 +1,49 @@
1
+ export function parseMcpArgs(argv) {
2
+ let petId;
3
+ let help = false;
4
+ let version = false;
5
+ for (let index = 0; index < argv.length; index += 1) {
6
+ const arg = argv[index];
7
+ if (arg === "--help" || arg === "-h") {
8
+ help = true;
9
+ continue;
10
+ }
11
+ if (arg === "--version" || arg === "-v") {
12
+ version = true;
13
+ continue;
14
+ }
15
+ if (arg === "--pet") {
16
+ const next = argv[index + 1];
17
+ if (!next)
18
+ throw new Error("--pet requires a pet id.");
19
+ petId = validateRawPetArg(next);
20
+ index += 1;
21
+ continue;
22
+ }
23
+ if (arg.startsWith("--pet=")) {
24
+ petId = validateRawPetArg(arg.slice("--pet=".length));
25
+ continue;
26
+ }
27
+ throw new Error(`Unknown argument: ${arg}`);
28
+ }
29
+ return { petId, help, version };
30
+ }
31
+ export function validatePetId(value) {
32
+ if (!/^[a-z0-9][a-z0-9_-]{0,63}$/.test(value) || value === "builtin") {
33
+ throw new Error(`Invalid pet id: ${value}`);
34
+ }
35
+ return value;
36
+ }
37
+ export function validateRawPetArg(value) {
38
+ const trimmed = value.trim();
39
+ if (trimmed.length < 1)
40
+ throw new Error("--pet requires a non-empty pet id.");
41
+ if (Buffer.byteLength(trimmed, "utf8") > 128 || /[\x00-\x1F\x7F/\\]/.test(trimmed)) {
42
+ throw new Error("--pet value is outside NoelCrew CLI bounds.");
43
+ }
44
+ return trimmed;
45
+ }
46
+ export function createHelpText() {
47
+ return `NoelCrew MCP server\n\nUsage:\n noel-crew-mcp [--pet <petId>]\n\nOptions:\n --pet <petId> Request an installed NoelCrew pet for this MCP process; missing pets fall back to default.\n --help Show this help.\n --version Show package version.\n`;
48
+ }
49
+ //# sourceMappingURL=args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAMA,MAAM,UAAU,YAAY,CAAC,IAAuB;IAClD,IAAI,KAAyB,CAAC;IAC9B,IAAI,IAAI,GAAG,KAAK,CAAC;IACjB,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACpD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACrC,IAAI,GAAG,IAAI,CAAC;YACZ,SAAS;QACX,CAAC;QACD,IAAI,GAAG,KAAK,WAAW,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACxC,OAAO,GAAG,IAAI,CAAC;YACf,SAAS;QACX,CAAC;QACD,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YAC7B,IAAI,CAAC,IAAI;gBAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;YACvD,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;YAChC,KAAK,IAAI,CAAC,CAAC;YACX,SAAS;QACX,CAAC;QACD,IAAI,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,KAAK,GAAG,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;YACtD,SAAS;QACX,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,IAAI,CAAC,4BAA4B,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,mBAAmB,KAAK,EAAE,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IAC9E,IAAI,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,GAAG,GAAG,IAAI,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACnF,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,qQAAqQ,CAAC;AAC/Q,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=check-mcp-contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-mcp-contract.d.ts","sourceRoot":"","sources":["../src/check-mcp-contract.ts"],"names":[],"mappings":""}
@@ -0,0 +1,122 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
4
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
5
+ import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
6
+ import { CallToolResultSchema } from "@modelcontextprotocol/sdk/types.js";
7
+ import { parseMcpArgs } from "./args.js";
8
+ import { createNoelCrewMcpServer } from "./server.js";
9
+ import { createMcpStatus, sanitizeUnavailableReason } from "./tools.js";
10
+ parseMcpArgs(["--pet", "snoopy"]);
11
+ parseMcpArgs(["--pet=snoopy"]);
12
+ parseMcpArgs(["--pet", "Bad Pet"]);
13
+ parseMcpArgs(["--help"]);
14
+ assertRejects(() => parseMcpArgs(["--pet", "bad/pet"]));
15
+ assertRejects(() => parseMcpArgs(["--agent", "claude"]));
16
+ const unavailableStatus = createMcpStatus({ ok: false, appRunning: false, unavailableReason: "/Users/alvin/.config/NoelCrew/runtime/ipc.json ENOENT" }, "snoopy");
17
+ if (unavailableStatus.routingImplemented !== true || unavailableStatus.configuredPetId !== "snoopy") {
18
+ throw new Error("MCP status did not preserve configured pet during degraded status.");
19
+ }
20
+ if (unavailableStatus.unavailableReason?.includes("/Users/")) {
21
+ throw new Error("Unavailable reason leaked a local path.");
22
+ }
23
+ if (sanitizeUnavailableReason("/tmp/noelcrew-501/noelcrew-1.sock ENOENT")?.includes("/tmp")) {
24
+ throw new Error("Sanitizer leaked socket path.");
25
+ }
26
+ await checkMcpServerContract();
27
+ await checkStdioServerContract();
28
+ const builtEntrypoint = readFileSync(join("dist", "index.js"), "utf8");
29
+ if (!builtEntrypoint.startsWith("#!/usr/bin/env node")) {
30
+ throw new Error("Built MCP entrypoint is missing a Node shebang.");
31
+ }
32
+ console.error("MCP contract validation passed.");
33
+ async function checkMcpServerContract() {
34
+ const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
35
+ const fakeClient = {
36
+ status: async () => ({ ok: true, appRunning: true, defaultPet: { id: "snoopy", displayName: "Snoopy" } }),
37
+ listPets: async () => ({ ok: true, pets: [], defaultPetId: "builtin" }),
38
+ installPet: async () => { throw new Error("unused"); },
39
+ acquireLease: async () => ({ leaseId: "lease-1", requestedPetId: "snoopy", targetKind: "explicit", actualTargetPetId: "snoopy", actualTargetPetName: "Snoopy", usingDefaultPet: false, expiresAt: Date.now() + 15_000, leaseActive: true }),
40
+ heartbeatLease: async (leaseId) => ({ leaseId, expiresAt: Date.now() + 15_000 }),
41
+ releaseLease: async () => ({ released: true }),
42
+ react: async (reaction, options) => ({ ok: true, reaction, leaseId: options?.leaseId }),
43
+ say: async (message, options) => ({ ok: true, message, leaseId: options?.leaseId }),
44
+ hello: async () => ({ ok: true }),
45
+ };
46
+ const server = createNoelCrewMcpServer({ configuredPetId: "snoopy", client: fakeClient, lease: { lease: await fakeClient.acquireLease() }, leaseReady: Promise.resolve() });
47
+ const client = new Client({ name: "noelcrew-contract", version: "0.0.0" });
48
+ await Promise.all([server.connect(serverTransport), client.connect(clientTransport)]);
49
+ try {
50
+ const tools = await client.listTools();
51
+ const names = tools.tools.map((tool) => tool.name).sort();
52
+ if (names.join(",") !== "noelcrew_react,noelcrew_say,noelcrew_status") {
53
+ throw new Error(`Unexpected MCP tool list: ${names.join(",")}`);
54
+ }
55
+ const status = await client.callTool({ name: "noelcrew_status", arguments: {} }, CallToolResultSchema);
56
+ const structured = status.structuredContent;
57
+ if (!structured.ok || structured.configuredPetId !== "snoopy" || structured.routingImplemented !== true || structured.actualTargetPetId !== "snoopy") {
58
+ throw new Error("Status tool returned unexpected structured content.");
59
+ }
60
+ const react = await client.callTool({ name: "noelcrew_react", arguments: { reaction: "waving" } }, CallToolResultSchema);
61
+ if (react.isError)
62
+ throw new Error("Valid reaction unexpectedly failed.");
63
+ const reactStructured = react.structuredContent;
64
+ if (reactStructured?.result?.leaseId !== "lease-1")
65
+ throw new Error("Reaction did not pass lease id to client.");
66
+ const invalidReact = await client.callTool({ name: "noelcrew_react", arguments: { reaction: "bad" } }, CallToolResultSchema);
67
+ if (!invalidReact.isError)
68
+ throw new Error("Invalid reaction was not rejected.");
69
+ const invalidSay = await client.callTool({ name: "noelcrew_say", arguments: { message: "const secret = 1" } }, CallToolResultSchema);
70
+ if (!invalidSay.isError)
71
+ throw new Error("Unsafe say message was not rejected.");
72
+ const stale = createMcpStatus({ ok: false, appRunning: true, leaseId: "missing", leaseActive: false, staleReason: "unknown_lease" }, "snoopy", undefined, "missing", "missing");
73
+ if (stale.leaseActive !== false || stale.staleReason !== "unknown_lease" || stale.ok !== false) {
74
+ throw new Error("Stale MCP lease status was not preserved.");
75
+ }
76
+ }
77
+ finally {
78
+ await client.close();
79
+ await server.close();
80
+ }
81
+ }
82
+ async function checkStdioServerContract() {
83
+ const transport = new StdioClientTransport({
84
+ command: process.execPath,
85
+ args: [join("dist", "index.js"), "--pet", "snoopy"],
86
+ env: { ...process.env, NOELCREW_DISCOVERY_FILE: join(process.cwd(), ".missing-noelcrew-discovery.json") },
87
+ stderr: "pipe",
88
+ });
89
+ const client = new Client({ name: "noelcrew-stdio-contract", version: "0.0.0" });
90
+ await client.connect(transport);
91
+ try {
92
+ const tools = await client.listTools();
93
+ const names = tools.tools.map((tool) => tool.name).sort();
94
+ if (names.join(",") !== "noelcrew_react,noelcrew_say,noelcrew_status") {
95
+ throw new Error(`Unexpected stdio MCP tool list: ${names.join(",")}`);
96
+ }
97
+ const status = await client.callTool({ name: "noelcrew_status", arguments: {} }, CallToolResultSchema);
98
+ const content = Array.isArray(status.content) ? status.content : [];
99
+ const first = content[0];
100
+ const text = first?.type === "text" && typeof first.text === "string" ? first.text : "";
101
+ if (!text.includes("Configured --pet snoopy") || !text.includes("actual target is unavailable")) {
102
+ throw new Error("Unavailable stdio status did not explain configured pet and unavailable target.");
103
+ }
104
+ const structured = status.structuredContent;
105
+ if (structured.appRunning !== false || structured.configuredPetId !== "snoopy" || structured.routingImplemented !== true) {
106
+ throw new Error("Unavailable stdio status returned unexpected structured content.");
107
+ }
108
+ }
109
+ finally {
110
+ await client.close();
111
+ }
112
+ }
113
+ function assertRejects(callback) {
114
+ try {
115
+ callback();
116
+ }
117
+ catch {
118
+ return;
119
+ }
120
+ throw new Error("Expected validation to reject.");
121
+ }
122
+ //# sourceMappingURL=check-mcp-contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-mcp-contract.js","sourceRoot":"","sources":["../src/check-mcp-contract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ensure-executable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensure-executable.d.ts","sourceRoot":"","sources":["../src/ensure-executable.ts"],"names":[],"mappings":""}
@@ -0,0 +1,6 @@
1
+ import { chmodSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ const entrypoint = join(dirname(fileURLToPath(import.meta.url)), "index.js");
5
+ chmodSync(entrypoint, 0o755);
6
+ //# sourceMappingURL=ensure-executable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensure-executable.js","sourceRoot":"","sources":["../src/ensure-executable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;AAE7E,SAAS,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
+ import { createHelpText, parseMcpArgs } from "./args.js";
7
+ import { createNoelCrewMcpServer } from "./server.js";
8
+ import { createToolContext } from "./tools.js";
9
+ async function main() {
10
+ const options = parseMcpArgs(process.argv.slice(2));
11
+ if (options.help) {
12
+ process.stdout.write(createHelpText());
13
+ return;
14
+ }
15
+ if (options.version) {
16
+ process.stdout.write(`${readPackageVersion()}\n`);
17
+ return;
18
+ }
19
+ const lease = {};
20
+ const context = createToolContext(options.petId);
21
+ const leaseReady = acquireStartupLease(context.client, lease, options.petId);
22
+ const server = createNoelCrewMcpServer({ ...context, lease, leaseReady });
23
+ let heartbeatTimer = null;
24
+ let closing = false;
25
+ leaseReady.then(() => {
26
+ if (!lease.lease)
27
+ return;
28
+ heartbeatTimer = setInterval(() => {
29
+ if (!lease.lease)
30
+ return;
31
+ void context.client.heartbeatLease(lease.lease.leaseId).catch((error) => {
32
+ lease.staleLeaseId = lease.lease?.leaseId;
33
+ lease.degradedReason = sanitizeMcpRuntimeError(error);
34
+ lease.lease = undefined;
35
+ if (heartbeatTimer)
36
+ clearInterval(heartbeatTimer);
37
+ heartbeatTimer = null;
38
+ });
39
+ }, 5_000);
40
+ heartbeatTimer.unref?.();
41
+ }).catch(() => { });
42
+ const transport = new StdioServerTransport();
43
+ const close = async () => {
44
+ if (closing)
45
+ return;
46
+ closing = true;
47
+ if (heartbeatTimer)
48
+ clearInterval(heartbeatTimer);
49
+ heartbeatTimer = null;
50
+ const leaseId = lease.lease?.leaseId;
51
+ lease.lease = undefined;
52
+ if (leaseId) {
53
+ try {
54
+ await context.client.releaseLease(leaseId);
55
+ }
56
+ catch { /* best effort */ }
57
+ }
58
+ try {
59
+ await server.close();
60
+ }
61
+ catch { /* ignore shutdown errors */ }
62
+ };
63
+ transport.onclose = () => { void close(); };
64
+ process.on("SIGINT", () => { void close().finally(() => process.exit(0)); });
65
+ process.on("SIGTERM", () => { void close().finally(() => process.exit(0)); });
66
+ await server.connect(transport);
67
+ }
68
+ async function acquireStartupLease(client, lease, requestedPetId) {
69
+ try {
70
+ lease.lease = await client.acquireLease({ requestedPetId });
71
+ lease.staleLeaseId = undefined;
72
+ lease.degradedReason = undefined;
73
+ }
74
+ catch (error) {
75
+ lease.lease = undefined;
76
+ lease.staleLeaseId = undefined;
77
+ lease.degradedReason = sanitizeMcpRuntimeError(error);
78
+ }
79
+ }
80
+ function sanitizeMcpRuntimeError(error) {
81
+ const message = error instanceof Error ? error.message : "NoelCrew lease operation failed.";
82
+ if (/\/|\\|\.sock|pipe|token|ipc\.json|ENOENT|ECONNREFUSED|EACCES/i.test(message)) {
83
+ return "NoelCrew desktop app or local IPC is unavailable.";
84
+ }
85
+ return message.slice(0, 160);
86
+ }
87
+ main().catch((error) => {
88
+ process.stderr.write(`NoelCrew MCP server failed: ${error instanceof Error ? error.message : String(error)}\n`);
89
+ process.exit(1);
90
+ });
91
+ function readPackageVersion() {
92
+ try {
93
+ const here = dirname(fileURLToPath(import.meta.url));
94
+ const packageJson = JSON.parse(readFileSync(join(here, "..", "package.json"), "utf8"));
95
+ return typeof packageJson.version === "string" ? packageJson.version : "0.0.0";
96
+ }
97
+ catch {
98
+ return "0.0.0";
99
+ }
100
+ }
101
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { type ToolContext } from "./tools.js";
3
+ export declare function createNoelCrewMcpServer(context: ToolContext): McpServer;
4
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAkF,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9H,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,CAsEvE"}
package/dist/server.js ADDED
@@ -0,0 +1,63 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { handleEventReact, handleReact, handleSay, handleStatus, reactSchema, saySchema } from "./tools.js";
3
+ export function createNoelCrewMcpServer(context) {
4
+ const server = new McpServer({ name: "noel-crew", version: "0.0.0" }, {
5
+ instructions: "Interact with the user's NoelCrew desktop companion. Use noelcrew_status first. Use noelcrew_say only for short status/personality messages, never code, logs, secrets, URLs, or file paths.",
6
+ });
7
+ server.registerTool("noelcrew_status", {
8
+ title: "NoelCrew Status",
9
+ description: "Check whether NoelCrew is reachable and which pet MCP events currently target.",
10
+ inputSchema: {},
11
+ annotations: { readOnlyHint: true, idempotentHint: true },
12
+ }, async () => handleStatus(context));
13
+ server.registerTool("noelcrew_react", {
14
+ title: "NoelCrew React",
15
+ description: "Set a short coding-oriented reaction on the NoelCrew desktop pet.",
16
+ inputSchema: reactSchema,
17
+ annotations: { readOnlyHint: false, idempotentHint: false },
18
+ }, async (input) => handleReact(input, context));
19
+ server.registerTool("noelcrew_say", {
20
+ title: "NoelCrew Say",
21
+ description: "Show a short safe message on the NoelCrew desktop pet. Do not send code, logs, secrets, URLs, or file paths.",
22
+ inputSchema: saySchema,
23
+ annotations: { readOnlyHint: false, idempotentHint: false },
24
+ }, async (input) => handleSay(input, context));
25
+ server.registerTool("noel_signal_fired", {
26
+ title: "Noel Signal Fired",
27
+ description: "Triggered when a Noel signal fires. Plays the excited (celebrating) animation on the desktop pet.",
28
+ inputSchema: {},
29
+ annotations: { readOnlyHint: false, idempotentHint: false },
30
+ }, async () => handleEventReact("celebrating", context));
31
+ server.registerTool("noel_whale_alert", {
32
+ title: "Noel Whale Alert",
33
+ description: "Triggered on a whale alert. Plays the alert (waiting) animation on the desktop pet.",
34
+ inputSchema: {},
35
+ annotations: { readOnlyHint: false, idempotentHint: false },
36
+ }, async () => handleEventReact("waiting", context));
37
+ server.registerTool("noel_research_start", {
38
+ title: "Noel Research Start",
39
+ description: "Triggered when research begins. Plays the working animation on the desktop pet.",
40
+ inputSchema: {},
41
+ annotations: { readOnlyHint: false, idempotentHint: false },
42
+ }, async () => handleEventReact("working", context));
43
+ server.registerTool("noel_research_complete", {
44
+ title: "Noel Research Complete",
45
+ description: "Triggered when research completes. Plays the success animation on the desktop pet.",
46
+ inputSchema: {},
47
+ annotations: { readOnlyHint: false, idempotentHint: false },
48
+ }, async () => handleEventReact("success", context));
49
+ server.registerTool("noel_swap_executing", {
50
+ title: "Noel Swap Executing",
51
+ description: "Triggered during a swap execution. Plays the running animation on the desktop pet.",
52
+ inputSchema: {},
53
+ annotations: { readOnlyHint: false, idempotentHint: false },
54
+ }, async () => handleEventReact("running", context));
55
+ server.registerTool("noel_error", {
56
+ title: "Noel Error",
57
+ description: "Triggered on an error condition. Plays the error animation on the desktop pet.",
58
+ inputSchema: {},
59
+ annotations: { readOnlyHint: false, idempotentHint: false },
60
+ }, async () => handleEventReact("error", context));
61
+ return server;
62
+ }
63
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
2
+ import { type NoelCrewClient, type NoelCrewLeaseResult, type NoelCrewReaction, type NoelCrewStatusResult } from "@noelclawai/client";
3
+ import { z } from "zod";
4
+ export declare const reactionSchema: z.ZodEnum<{
5
+ idle: "idle";
6
+ thinking: "thinking";
7
+ working: "working";
8
+ editing: "editing";
9
+ running: "running";
10
+ testing: "testing";
11
+ waiting: "waiting";
12
+ waving: "waving";
13
+ success: "success";
14
+ error: "error";
15
+ celebrating: "celebrating";
16
+ }>;
17
+ export declare const saySchema: z.ZodObject<{
18
+ message: z.ZodString;
19
+ reaction: z.ZodOptional<z.ZodEnum<{
20
+ idle: "idle";
21
+ thinking: "thinking";
22
+ working: "working";
23
+ editing: "editing";
24
+ running: "running";
25
+ testing: "testing";
26
+ waiting: "waiting";
27
+ waving: "waving";
28
+ success: "success";
29
+ error: "error";
30
+ celebrating: "celebrating";
31
+ }>>;
32
+ }, z.core.$strip>;
33
+ export declare const reactSchema: z.ZodObject<{
34
+ reaction: z.ZodEnum<{
35
+ idle: "idle";
36
+ thinking: "thinking";
37
+ working: "working";
38
+ editing: "editing";
39
+ running: "running";
40
+ testing: "testing";
41
+ waiting: "waiting";
42
+ waving: "waving";
43
+ success: "success";
44
+ error: "error";
45
+ celebrating: "celebrating";
46
+ }>;
47
+ }, z.core.$strip>;
48
+ export interface NoelCrewMcpStatus {
49
+ readonly [key: string]: unknown;
50
+ ok: boolean;
51
+ appRunning: boolean;
52
+ configuredPetId?: string;
53
+ actualTargetPetId?: string;
54
+ actualTargetPetName?: string;
55
+ usingDefaultPet: boolean;
56
+ routingImplemented: boolean;
57
+ unavailableReason?: string;
58
+ fallbackReason?: string;
59
+ }
60
+ export interface LeaseContext {
61
+ lease?: NoelCrewLeaseResult;
62
+ staleLeaseId?: string;
63
+ degradedReason?: string;
64
+ }
65
+ export interface ToolContext {
66
+ readonly configuredPetId?: string;
67
+ readonly client?: NoelCrewClient;
68
+ readonly lease?: LeaseContext;
69
+ readonly leaseReady?: Promise<void>;
70
+ }
71
+ export declare function createToolContext(configuredPetId?: string): ToolContext & {
72
+ readonly client: NoelCrewClient;
73
+ };
74
+ export declare function handleStatus(context: ToolContext): Promise<CallToolResult>;
75
+ export declare function handleReact(input: unknown, context: ToolContext): Promise<CallToolResult>;
76
+ export declare function handleEventReact(reaction: NoelCrewReaction, context: ToolContext): Promise<CallToolResult>;
77
+ export declare function handleSay(input: unknown, context: ToolContext): Promise<CallToolResult>;
78
+ export declare function createMcpStatus(status: NoelCrewStatusResult, configuredPetId?: string, lease?: NoelCrewLeaseResult, degradedReason?: string, staleLeaseId?: string): NoelCrewMcpStatus;
79
+ export declare function toolError(message: string): CallToolResult;
80
+ export declare function sanitizeUnavailableReason(value: unknown): string | undefined;
81
+ export type { NoelCrewReaction };
82
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EAA+D,KAAK,cAAc,EAAE,KAAK,mBAAmB,EAAE,KAAK,gBAAgB,EAAE,KAAK,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAClM,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,cAAc;;;;;;;;;;;;EAA2B,CAAC;AAEvD,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;iBAOpB,CAAC;AAEH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;iBAAyC,CAAC;AAElE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,EAAE,EAAE,OAAO,CAAC;IACZ,UAAU,EAAE,OAAO,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,eAAe,EAAE,OAAO,CAAC;IACzB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,mBAAmB,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC;IACjC,QAAQ,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CACrC;AAED,wBAAgB,iBAAiB,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;CAAE,CAK7G;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC,CAqBhF;AAED,wBAAsB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC,CAgB/F;AAED,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC,CAahH;AAED,wBAAsB,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC,CAgB7F;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,oBAAoB,EAAE,eAAe,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,mBAAmB,EAAE,cAAc,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAgDtL;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAEzD;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAM5E;AAWD,YAAY,EAAE,gBAAgB,EAAE,CAAC"}
package/dist/tools.js ADDED
@@ -0,0 +1,160 @@
1
+ import { allowedReactions, createNoelCrewClient, NoelCrewClientError } from "@noelclawai/client";
2
+ import { z } from "zod";
3
+ export const reactionSchema = z.enum(allowedReactions);
4
+ export const saySchema = z.object({
5
+ message: z.string().trim().min(1).max(140)
6
+ .refine((value) => !/[\r\n]/.test(value), "Message must be single-line.")
7
+ .refine((value) => !/```|<script|function\s+\w+|=>|\b(class|import|export|const|let|var)\b/.test(value), "Message looks like code.")
8
+ .refine((value) => !/https?:\/\/|www\.|\/[\w.-]+\/[\w./-]+|[A-Za-z]:\\/.test(value), "Message contains URL or path-like content.")
9
+ .refine((value) => !/(api[_-]?key|secret|token|password|passwd|BEGIN [A-Z ]+PRIVATE KEY)/i.test(value), "Message looks secret-like."),
10
+ reaction: reactionSchema.optional(),
11
+ });
12
+ export const reactSchema = z.object({ reaction: reactionSchema });
13
+ export function createToolContext(configuredPetId) {
14
+ return {
15
+ configuredPetId,
16
+ client: createNoelCrewClient(),
17
+ };
18
+ }
19
+ export async function handleStatus(context) {
20
+ await context.leaseReady;
21
+ const client = context.client ?? createNoelCrewClient();
22
+ const leaseId = context.lease?.lease?.leaseId ?? context.lease?.staleLeaseId;
23
+ const status = await client.status({ leaseId });
24
+ const structured = createMcpStatus(status, context.configuredPetId, context.lease?.lease, context.lease?.degradedReason, context.lease?.staleLeaseId);
25
+ const configuredText = context.configuredPetId
26
+ ? `Configured --pet ${context.configuredPetId}; actual target is ${structured.actualTargetPetId ?? "unavailable"}.`
27
+ : "No --pet configured; actual target is the desktop default pet.";
28
+ if (!structured.appRunning) {
29
+ return {
30
+ content: [{ type: "text", text: `NoelCrew is unavailable. ${configuredText} ${structured.unavailableReason ?? "Open the NoelCrew desktop app and try again."}` }],
31
+ structuredContent: structured,
32
+ };
33
+ }
34
+ return {
35
+ content: [{ type: "text", text: `NoelCrew is running. ${configuredText}` }],
36
+ structuredContent: structured,
37
+ };
38
+ }
39
+ export async function handleReact(input, context) {
40
+ await context.leaseReady;
41
+ const parsed = reactSchema.safeParse(input);
42
+ if (!parsed.success)
43
+ return toolError("Invalid reaction. Use one of: " + allowedReactions.join(", "));
44
+ if (!context.lease?.lease)
45
+ return toolError(`NoelCrew lease is unavailable. ${sanitizeUnavailableReason(context.lease?.degradedReason) ?? "Open NoelCrew and try again."}`);
46
+ try {
47
+ const client = context.client ?? createNoelCrewClient();
48
+ const result = await client.react(parsed.data.reaction, { leaseId: context.lease.lease.leaseId });
49
+ return {
50
+ content: [{ type: "text", text: `NoelCrew reaction sent: ${parsed.data.reaction}` }],
51
+ structuredContent: { ok: true, reaction: parsed.data.reaction, result },
52
+ };
53
+ }
54
+ catch (error) {
55
+ return toolError(`NoelCrew desktop app is not running or local IPC is unavailable. ${sanitizeError(error)}`);
56
+ }
57
+ }
58
+ export async function handleEventReact(reaction, context) {
59
+ await context.leaseReady;
60
+ if (!context.lease?.lease)
61
+ return toolError(`Noel Crew lease is unavailable. ${sanitizeUnavailableReason(context.lease?.degradedReason) ?? "Open Noel Crew and try again."}`);
62
+ try {
63
+ const client = context.client ?? createNoelCrewClient();
64
+ const result = await client.react(reaction, { leaseId: context.lease.lease.leaseId });
65
+ return {
66
+ content: [{ type: "text", text: `Noel Crew reaction sent: ${reaction}` }],
67
+ structuredContent: { ok: true, reaction, result },
68
+ };
69
+ }
70
+ catch (error) {
71
+ return toolError(`Noel Crew desktop app is not running or local IPC is unavailable. ${sanitizeError(error)}`);
72
+ }
73
+ }
74
+ export async function handleSay(input, context) {
75
+ await context.leaseReady;
76
+ const parsed = saySchema.safeParse(input);
77
+ if (!parsed.success)
78
+ return toolError("Invalid message. Keep it short, single-line, and avoid code, secrets, URLs, and file paths.");
79
+ if (!context.lease?.lease)
80
+ return toolError(`NoelCrew lease is unavailable. ${sanitizeUnavailableReason(context.lease?.degradedReason) ?? "Open NoelCrew and try again."}`);
81
+ try {
82
+ const client = context.client ?? createNoelCrewClient();
83
+ const result = await client.say(parsed.data.message, { reaction: parsed.data.reaction, leaseId: context.lease.lease.leaseId });
84
+ return {
85
+ content: [{ type: "text", text: "NoelCrew message sent." }],
86
+ structuredContent: { ok: true, result },
87
+ };
88
+ }
89
+ catch (error) {
90
+ return toolError(`NoelCrew desktop app is not running or local IPC is unavailable. ${sanitizeError(error)}`);
91
+ }
92
+ }
93
+ export function createMcpStatus(status, configuredPetId, lease, degradedReason, staleLeaseId) {
94
+ if (status.leaseActive === false || staleLeaseId) {
95
+ return {
96
+ ok: false,
97
+ appRunning: status.appRunning === true,
98
+ configuredPetId,
99
+ usingDefaultPet: true,
100
+ routingImplemented: true,
101
+ unavailableReason: sanitizeUnavailableReason(degradedReason ?? status.unavailableReason ?? status.staleReason),
102
+ leaseId: typeof status.leaseId === "string" ? status.leaseId : staleLeaseId,
103
+ leaseActive: false,
104
+ staleReason: typeof status.staleReason === "string" ? status.staleReason : "unknown_lease",
105
+ };
106
+ }
107
+ if (lease) {
108
+ const statusTargetPetId = typeof status.actualTargetPetId === "string" ? status.actualTargetPetId : undefined;
109
+ const statusTargetPetName = typeof status.actualTargetPetName === "string" ? status.actualTargetPetName : undefined;
110
+ const statusUsingDefault = typeof status.usingDefaultPet === "boolean" ? status.usingDefaultPet : undefined;
111
+ const statusFallbackReason = typeof status.fallbackReason === "string" ? status.fallbackReason : undefined;
112
+ return {
113
+ ok: status.appRunning === true && status.ok !== false,
114
+ appRunning: status.appRunning === true,
115
+ configuredPetId,
116
+ actualTargetPetId: statusTargetPetId ?? lease.actualTargetPetId,
117
+ actualTargetPetName: statusTargetPetName ?? lease.actualTargetPetName,
118
+ usingDefaultPet: statusUsingDefault ?? lease.usingDefaultPet,
119
+ routingImplemented: true,
120
+ fallbackReason: statusFallbackReason ?? lease.fallbackReason,
121
+ leaseId: lease.leaseId,
122
+ leaseActive: lease.leaseActive,
123
+ };
124
+ }
125
+ const defaultPet = isRecord(status.defaultPet) ? status.defaultPet : undefined;
126
+ const actualTargetPetId = typeof defaultPet?.id === "string" ? defaultPet.id : undefined;
127
+ const actualTargetPetName = typeof defaultPet?.displayName === "string" ? defaultPet.displayName : undefined;
128
+ const appRunning = status.appRunning === true;
129
+ return {
130
+ ok: appRunning && status.ok !== false,
131
+ appRunning,
132
+ configuredPetId,
133
+ actualTargetPetId,
134
+ actualTargetPetName,
135
+ usingDefaultPet: true,
136
+ routingImplemented: true,
137
+ unavailableReason: appRunning ? undefined : sanitizeUnavailableReason(degradedReason ?? status.unavailableReason),
138
+ fallbackReason: undefined,
139
+ };
140
+ }
141
+ export function toolError(message) {
142
+ return { content: [{ type: "text", text: message }], isError: true };
143
+ }
144
+ export function sanitizeUnavailableReason(value) {
145
+ if (typeof value !== "string" || value.length === 0)
146
+ return "NoelCrew desktop app is unavailable.";
147
+ if (/\/|\\|\.sock|pipe|token|ipc\.json|ENOENT|ECONNREFUSED|EACCES/i.test(value)) {
148
+ return "NoelCrew desktop app or local IPC is unavailable.";
149
+ }
150
+ return value.slice(0, 160);
151
+ }
152
+ function sanitizeError(error) {
153
+ if (error instanceof NoelCrewClientError)
154
+ return sanitizeUnavailableReason(error.message) ?? "NoelCrew is unavailable.";
155
+ return "Open NoelCrew and try again.";
156
+ }
157
+ function isRecord(value) {
158
+ return typeof value === "object" && value !== null;
159
+ }
160
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@noelclawai/crew",
3
+ "version": "0.1.4",
4
+ "description": "Noel Crew — tray-first desktop companion MCP for AI coding agents",
5
+ "license": "MIT",
6
+ "homepage": "https://noelclaw.fun",
7
+ "keywords": [
8
+ "mcp",
9
+ "noelclaw",
10
+ "desktop-pet",
11
+ "ai-agent",
12
+ "claude-code"
13
+ ],
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/noelclaw/noel-crew.git",
17
+ "directory": "packages/mcp"
18
+ },
19
+ "type": "module",
20
+ "main": "dist/index.js",
21
+ "types": "dist/index.d.ts",
22
+ "bin": {
23
+ "noelclaw-crew": "./dist/index.js"
24
+ },
25
+ "files": [
26
+ "dist"
27
+ ],
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "exports": {
32
+ ".": {
33
+ "types": "./dist/index.d.ts",
34
+ "default": "./dist/index.js"
35
+ }
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^25.6.2",
39
+ "typescript": "^6.0.3"
40
+ },
41
+ "dependencies": {
42
+ "@modelcontextprotocol/sdk": "^1.29.0",
43
+ "zod": "^4.4.3",
44
+ "@noelclawai/client": "2.0.7"
45
+ },
46
+ "scripts": {
47
+ "test": "node dist/check-mcp-contract.js",
48
+ "check": "pnpm --filter @noelclawai/client build && pnpm typecheck && pnpm build && pnpm test",
49
+ "typecheck": "tsc --noEmit",
50
+ "build": "tsc && node dist/ensure-executable.js"
51
+ }
52
+ }