senq-mcp 1.1.0 → 1.3.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.
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ if (process.argv[2] === "setup") {
9
9
  await runSetup();
10
10
  process.exit(0);
11
11
  }
12
- const server = new Server({ name: "senq-mcp", version: "1.1.0" }, { capabilities: { tools: {} } });
12
+ const server = new Server({ name: "senq-mcp", version: "1.3.0" }, { capabilities: { tools: {} } });
13
13
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
14
14
  tools: [
15
15
  {
@@ -289,7 +289,7 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
289
289
  params.limit = String(args.limit);
290
290
  if (args?.offset)
291
291
  params.offset = String(args.offset);
292
- const data = await apiGet("/api/admin/tasks", params);
292
+ const data = await apiGet("/api/tasks/team", params);
293
293
  const tasks = data.tasks ?? [];
294
294
  const total = data.total ?? tasks.length;
295
295
  return {
@@ -308,7 +308,7 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
308
308
  params.projectId = String(args.projectId);
309
309
  if (args?.areaId)
310
310
  params.areaId = String(args.areaId);
311
- const data = await apiGet("/api/admin/tasks", params);
311
+ const data = await apiGet("/api/tasks/team", params);
312
312
  const allTasks = data.tasks ?? [];
313
313
  const dateFrom = args?.dateFrom ? String(args.dateFrom) : undefined;
314
314
  const dateTo = args?.dateTo ? String(args.dateTo) : undefined;
package/dist/setup.js CHANGED
@@ -23,6 +23,7 @@ const CLIENTS = [
23
23
  { id: "claude", label: "Claude Desktop", configPath: getConfigPath("claude") },
24
24
  { id: "cursor", label: "Cursor", configPath: getConfigPath("cursor") },
25
25
  { id: "claudecode", label: "Claude Code", configPath: getConfigPath("claudecode") },
26
+ { id: "codex", label: "Codex", configPath: path.join(os.homedir(), ".codex", "config.toml") },
26
27
  ];
27
28
  function readHidden(prompt) {
28
29
  return new Promise((resolve) => {
@@ -82,6 +83,27 @@ function mergeConfig(configPath, apiKey) {
82
83
  fs.mkdirSync(path.dirname(configPath), { recursive: true });
83
84
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
84
85
  }
86
+ function mergeCodexConfig(configPath, apiKey) {
87
+ fs.mkdirSync(path.dirname(configPath), { recursive: true });
88
+ let existing = "";
89
+ if (fs.existsSync(configPath)) {
90
+ existing = fs.readFileSync(configPath, "utf8");
91
+ }
92
+ const senqBlock = `[mcp_servers.senq]\ncommand = "npx"\nargs = ["senq-mcp"]\n\n[mcp_servers.senq.env]\nSENQ_API_KEY = "${apiKey}"`;
93
+ if (existing.includes("[mcp_servers.senq]")) {
94
+ // Replace existing senq block
95
+ const updated = existing.replace(/\[mcp_servers\.senq\][\s\S]*?SENQ_API_KEY\s*=\s*"[^"]*"/, senqBlock);
96
+ fs.writeFileSync(configPath, updated);
97
+ }
98
+ else if (existing.includes("[sandbox_workspace_write]")) {
99
+ // Insert before sandbox section
100
+ const updated = existing.replace("[sandbox_workspace_write]", `${senqBlock}\n\n[sandbox_workspace_write]`);
101
+ fs.writeFileSync(configPath, updated);
102
+ }
103
+ else {
104
+ fs.writeFileSync(configPath, existing + (existing.endsWith("\n") || !existing ? "" : "\n") + "\n" + senqBlock + "\n");
105
+ }
106
+ }
85
107
  export async function runSetup() {
86
108
  console.log("\n🤖 Настройка Senq MCP\n");
87
109
  const apiKey = await readHidden("Вставь API-ключ из Senq: ");
@@ -94,7 +116,7 @@ export async function runSetup() {
94
116
  const exists = fs.existsSync(c.configPath);
95
117
  console.log(` ${i + 1}) ${c.label}${exists ? " (конфиг найден)" : ""}`);
96
118
  });
97
- console.log(` ${CLIENTS.length + 1}) Все три\n`);
119
+ console.log(` ${CLIENTS.length + 1}) Все четыре\n`);
98
120
  const choice = await ask("Введи номер [1]: ", "1");
99
121
  const num = parseInt(choice, 10);
100
122
  let selected;
@@ -110,7 +132,12 @@ export async function runSetup() {
110
132
  console.log("");
111
133
  for (const client of selected) {
112
134
  try {
113
- mergeConfig(client.configPath, apiKey);
135
+ if (client.id === "codex") {
136
+ mergeCodexConfig(client.configPath, apiKey);
137
+ }
138
+ else {
139
+ mergeConfig(client.configPath, apiKey);
140
+ }
114
141
  console.log(` ✅ ${client.label}: ${client.configPath}`);
115
142
  }
116
143
  catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "senq-mcp",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "description": "MCP server for Senq — connect your AI to tasks and knowledge",
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.ts CHANGED
@@ -15,7 +15,7 @@ if (process.argv[2] === "setup") {
15
15
  }
16
16
 
17
17
  const server = new Server(
18
- { name: "senq-mcp", version: "1.1.0" },
18
+ { name: "senq-mcp", version: "1.3.0" },
19
19
  { capabilities: { tools: {} } },
20
20
  );
21
21
 
@@ -266,7 +266,7 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
266
266
  if (args?.dateTo) params.dateTo = String(args.dateTo);
267
267
  if (args?.limit) params.limit = String(args.limit);
268
268
  if (args?.offset) params.offset = String(args.offset);
269
- const data = await apiGet<{ tasks?: unknown[]; total?: number }>("/api/admin/tasks", params);
269
+ const data = await apiGet<{ tasks?: unknown[]; total?: number }>("/api/tasks/team", params);
270
270
  const tasks = data.tasks ?? [];
271
271
  const total = data.total ?? tasks.length;
272
272
  return {
@@ -289,7 +289,7 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
289
289
  dueDate?: string | null; completedAt?: string | null;
290
290
  projectName?: string | null; areaName?: string | null;
291
291
  assigneeName?: string | null;
292
- }>; total?: number }>("/api/admin/tasks", params);
292
+ }>; total?: number }>("/api/tasks/team", params);
293
293
 
294
294
  const allTasks = data.tasks ?? [];
295
295
  const dateFrom = args?.dateFrom ? String(args.dateFrom) : undefined;
package/src/setup.ts CHANGED
@@ -31,6 +31,7 @@ const CLIENTS: ClientInfo[] = [
31
31
  { id: "claude", label: "Claude Desktop", configPath: getConfigPath("claude") },
32
32
  { id: "cursor", label: "Cursor", configPath: getConfigPath("cursor") },
33
33
  { id: "claudecode", label: "Claude Code", configPath: getConfigPath("claudecode") },
34
+ { id: "codex", label: "Codex", configPath: path.join(os.homedir(), ".codex", "config.toml") },
34
35
  ];
35
36
 
36
37
  function readHidden(prompt: string): Promise<string> {
@@ -87,6 +88,31 @@ function mergeConfig(configPath: string, apiKey: string): void {
87
88
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
88
89
  }
89
90
 
91
+ function mergeCodexConfig(configPath: string, apiKey: string): void {
92
+ fs.mkdirSync(path.dirname(configPath), { recursive: true });
93
+ let existing = "";
94
+ if (fs.existsSync(configPath)) {
95
+ existing = fs.readFileSync(configPath, "utf8");
96
+ }
97
+
98
+ const senqBlock = `[mcp_servers.senq]\ncommand = "npx"\nargs = ["senq-mcp"]\n\n[mcp_servers.senq.env]\nSENQ_API_KEY = "${apiKey}"`;
99
+
100
+ if (existing.includes("[mcp_servers.senq]")) {
101
+ // Replace existing senq block
102
+ const updated = existing.replace(
103
+ /\[mcp_servers\.senq\][\s\S]*?SENQ_API_KEY\s*=\s*"[^"]*"/,
104
+ senqBlock,
105
+ );
106
+ fs.writeFileSync(configPath, updated);
107
+ } else if (existing.includes("[sandbox_workspace_write]")) {
108
+ // Insert before sandbox section
109
+ const updated = existing.replace("[sandbox_workspace_write]", `${senqBlock}\n\n[sandbox_workspace_write]`);
110
+ fs.writeFileSync(configPath, updated);
111
+ } else {
112
+ fs.writeFileSync(configPath, existing + (existing.endsWith("\n") || !existing ? "" : "\n") + "\n" + senqBlock + "\n");
113
+ }
114
+ }
115
+
90
116
  export async function runSetup(): Promise<void> {
91
117
  console.log("\n🤖 Настройка Senq MCP\n");
92
118
 
@@ -102,7 +128,7 @@ export async function runSetup(): Promise<void> {
102
128
  const exists = fs.existsSync(c.configPath);
103
129
  console.log(` ${i + 1}) ${c.label}${exists ? " (конфиг найден)" : ""}`);
104
130
  });
105
- console.log(` ${CLIENTS.length + 1}) Все три\n`);
131
+ console.log(` ${CLIENTS.length + 1}) Все четыре\n`);
106
132
 
107
133
  const choice = await ask("Введи номер [1]: ", "1");
108
134
  const num = parseInt(choice, 10);
@@ -119,7 +145,11 @@ export async function runSetup(): Promise<void> {
119
145
  console.log("");
120
146
  for (const client of selected) {
121
147
  try {
122
- mergeConfig(client.configPath, apiKey);
148
+ if (client.id === "codex") {
149
+ mergeCodexConfig(client.configPath, apiKey);
150
+ } else {
151
+ mergeConfig(client.configPath, apiKey);
152
+ }
123
153
  console.log(` ✅ ${client.label}: ${client.configPath}`);
124
154
  } catch (err) {
125
155
  const msg = err instanceof Error ? err.message : String(err);