@agenticmail/claudecode 0.2.14 → 0.2.16

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.
@@ -1,7 +1,25 @@
1
1
  // src/claude-config.ts
2
2
  import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync } from "fs";
3
- import { dirname } from "path";
3
+ import { dirname, isAbsolute, resolve, sep } from "path";
4
+ import { homedir, tmpdir } from "os";
5
+ function assertSafeConfigPath(path) {
6
+ if (!path || typeof path !== "string") {
7
+ throw new Error("claude config path is required");
8
+ }
9
+ if (!isAbsolute(path)) {
10
+ throw new Error(`refusing relative claude config path: ${path}`);
11
+ }
12
+ const resolved = resolve(path);
13
+ const home = resolve(homedir());
14
+ const tmp = resolve(tmpdir());
15
+ const insideHome = resolved === home || resolved.startsWith(home + sep);
16
+ const insideTmp = resolved === tmp || resolved.startsWith(tmp + sep);
17
+ if (!insideHome && !insideTmp) {
18
+ throw new Error(`refusing claude config write outside of HOME or tmp: ${path}`);
19
+ }
20
+ }
4
21
  function readClaudeConfig(path) {
22
+ assertSafeConfigPath(path);
5
23
  if (!existsSync(path)) return {};
6
24
  const raw = readFileSync(path, "utf-8");
7
25
  if (!raw.trim()) return {};
@@ -16,6 +34,7 @@ function readClaudeConfig(path) {
16
34
  }
17
35
  }
18
36
  function writeClaudeConfig(path, config) {
37
+ assertSafeConfigPath(path);
19
38
  const dir = dirname(path);
20
39
  if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
21
40
  const text = JSON.stringify(config, null, 2) + "\n";
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  status
3
- } from "./chunk-PDJOVOWH.js";
3
+ } from "./chunk-XOTADT55.js";
4
4
  import {
5
5
  uninstall
6
- } from "./chunk-UGB5UEYX.js";
6
+ } from "./chunk-WNHGDCTG.js";
7
7
  import {
8
8
  install
9
- } from "./chunk-KQ3FJTHT.js";
9
+ } from "./chunk-L35WA2XT.js";
10
10
  import {
11
11
  AgenticMailApiError
12
- } from "./chunk-GVR4HTBB.js";
12
+ } from "./chunk-V62JPM5R.js";
13
13
 
14
14
  // src/http-routes.ts
15
15
  import { Router } from "express";
@@ -4,13 +4,13 @@ import {
4
4
  listPendingTasksForAgent,
5
5
  renderPersonaBody,
6
6
  resolveConfig
7
- } from "./chunk-GVR4HTBB.js";
7
+ } from "./chunk-V62JPM5R.js";
8
8
 
9
9
  // src/persona-loader.ts
10
10
  import { existsSync, readFileSync } from "fs";
11
11
  import { join } from "path";
12
12
  function sanitizeSubagentName(name) {
13
- return name.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
13
+ return name.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+/, "").replace(/-+$/, "");
14
14
  }
15
15
  function stripFrontmatter(raw) {
16
16
  const text = raw.replace(/\r\n/g, "\n");
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  upsertUserPromptSubmitHook
3
- } from "./chunk-LO5EQSQA.js";
3
+ } from "./chunk-SWDS64K2.js";
4
4
  import {
5
5
  startDispatcher,
6
6
  upsertMcpServer
7
- } from "./chunk-US5FT2UB.js";
7
+ } from "./chunk-7DGWW72Q.js";
8
8
  import {
9
9
  MANAGED_BY_MARKER,
10
10
  checkApiHealth,
@@ -14,14 +14,14 @@ import {
14
14
  resolveConfig,
15
15
  setAccountHost,
16
16
  setAccountRole
17
- } from "./chunk-GVR4HTBB.js";
17
+ } from "./chunk-V62JPM5R.js";
18
18
 
19
19
  // src/install.ts
20
20
  import { existsSync, mkdirSync, readdirSync, writeFileSync, readFileSync, unlinkSync } from "fs";
21
- import { join } from "path";
21
+ import { safeJoin, tryJoin, PathTraversalError } from "@agenticmail/core";
22
22
  import { fileURLToPath } from "url";
23
23
  function sanitizeSubagentName(name) {
24
- return name.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
24
+ return name.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+/, "").replace(/-+$/, "");
25
25
  }
26
26
  function buildMcpEntry(cfg, bridgeKey, accountKeys) {
27
27
  const env = {
@@ -71,7 +71,13 @@ function writeSubagentFiles(agentsDir, cfg, agents) {
71
71
  const updated = [];
72
72
  for (const agent of agents) {
73
73
  const baseName = sanitizeSubagentName(`${cfg.subagentPrefix}${agent.name}`);
74
- const filePath = join(agentsDir, `${baseName}.md`);
74
+ let filePath;
75
+ try {
76
+ filePath = safeJoin(agentsDir, `${baseName}.md`);
77
+ } catch (err) {
78
+ if (err instanceof PathTraversalError) continue;
79
+ throw err;
80
+ }
75
81
  const content = renderSubagentMarkdown({
76
82
  name: baseName,
77
83
  agent,
@@ -94,8 +100,8 @@ function pruneStaleSubagentFiles(agentsDir, cfg, liveAgentNames) {
94
100
  for (const file of readdirSync(agentsDir)) {
95
101
  if (!file.endsWith(".md")) continue;
96
102
  if (!file.toLowerCase().startsWith(prefix)) continue;
97
- const full = join(agentsDir, file);
98
- if (!isOwnedSubagent(full)) continue;
103
+ const full = tryJoin(agentsDir, file);
104
+ if (!full || !isOwnedSubagent(full)) continue;
99
105
  const stem = file.slice(prefix.length, -3);
100
106
  if (liveAgentNames.has(stem.toLowerCase())) continue;
101
107
  try {
@@ -1,6 +1,23 @@
1
1
  // src/claude-hooks-config.ts
2
2
  import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync } from "fs";
3
- import { dirname } from "path";
3
+ import { dirname, isAbsolute, resolve, sep } from "path";
4
+ import { homedir, tmpdir } from "os";
5
+ function assertSafeHooksPath(path) {
6
+ if (!path || typeof path !== "string") {
7
+ throw new Error("claude hooks path is required");
8
+ }
9
+ if (!isAbsolute(path)) {
10
+ throw new Error(`refusing relative claude hooks path: ${path}`);
11
+ }
12
+ const resolved = resolve(path);
13
+ const home = resolve(homedir());
14
+ const tmp = resolve(tmpdir());
15
+ const insideHome = resolved === home || resolved.startsWith(home + sep);
16
+ const insideTmp = resolved === tmp || resolved.startsWith(tmp + sep);
17
+ if (!insideHome && !insideTmp) {
18
+ throw new Error(`refusing claude hooks write outside of HOME or tmp: ${path}`);
19
+ }
20
+ }
4
21
  function isAgenticMailHookCommand(command) {
5
22
  if (typeof command !== "string") return false;
6
23
  return command.includes("agenticmail-mail-hook") || command.includes("mail-hook.js");
@@ -8,6 +25,7 @@ function isAgenticMailHookCommand(command) {
8
25
  var HOOK_EVENTS_TO_REGISTER = ["UserPromptSubmit", "Stop", "SessionStart"];
9
26
  var HOOK_EVENTS_TO_REMOVE = ["UserPromptSubmit", "Stop", "PreToolUse", "SessionStart"];
10
27
  function readSettings(path) {
28
+ assertSafeHooksPath(path);
11
29
  if (!existsSync(path)) return {};
12
30
  const raw = readFileSync(path, "utf-8");
13
31
  if (!raw.trim()) return {};
@@ -22,6 +40,7 @@ function readSettings(path) {
22
40
  }
23
41
  }
24
42
  function writeSettings(path, settings) {
43
+ assertSafeHooksPath(path);
25
44
  const dir = dirname(path);
26
45
  if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
27
46
  const text = JSON.stringify(settings, null, 2) + "\n";
@@ -1,4 +1,5 @@
1
1
  // src/api.ts
2
+ import { validateApiUrl, buildApiUrl } from "@agenticmail/core";
2
3
  var AgenticMailApiError = class extends Error {
3
4
  constructor(status, message) {
4
5
  super(message);
@@ -10,7 +11,7 @@ async function request(apiUrl, masterKey, path, opts = {}) {
10
11
  if (!masterKey) {
11
12
  throw new AgenticMailApiError(0, "AgenticMail master key is required \u2014 could not find one in ~/.agenticmail/config.json.");
12
13
  }
13
- const url = `${apiUrl.replace(/\/$/, "")}/api/agenticmail${path}`;
14
+ const url = buildApiUrl(validateApiUrl(apiUrl), `/api/agenticmail${path}`);
14
15
  const headers = { "Authorization": `Bearer ${masterKey}` };
15
16
  if (opts.body !== void 0) headers["Content-Type"] = "application/json";
16
17
  let res;
@@ -40,7 +41,7 @@ async function request(apiUrl, masterKey, path, opts = {}) {
40
41
  return await res.json();
41
42
  }
42
43
  async function checkApiHealth(apiUrl) {
43
- const url = `${apiUrl.replace(/\/$/, "")}/api/agenticmail/health`;
44
+ const url = buildApiUrl(validateApiUrl(apiUrl), "/api/agenticmail/health");
44
45
  try {
45
46
  const res = await fetch(url, { signal: AbortSignal.timeout(5e3) });
46
47
  if (!res.ok) throw new AgenticMailApiError(res.status, `Health check returned HTTP ${res.status}`);
@@ -1,20 +1,20 @@
1
1
  import {
2
2
  removeUserPromptSubmitHook
3
- } from "./chunk-LO5EQSQA.js";
3
+ } from "./chunk-SWDS64K2.js";
4
4
  import {
5
5
  removeMcpServer,
6
6
  stopDispatcher
7
- } from "./chunk-US5FT2UB.js";
7
+ } from "./chunk-7DGWW72Q.js";
8
8
  import {
9
9
  MANAGED_BY_MARKER,
10
10
  deleteAccount,
11
11
  getAccountByName,
12
12
  resolveConfig
13
- } from "./chunk-GVR4HTBB.js";
13
+ } from "./chunk-V62JPM5R.js";
14
14
 
15
15
  // src/uninstall.ts
16
16
  import { existsSync, readdirSync, readFileSync, unlinkSync } from "fs";
17
- import { join } from "path";
17
+ import { tryJoin } from "@agenticmail/core";
18
18
  function removeOwnedSubagents(agentsDir, prefix) {
19
19
  if (!existsSync(agentsDir)) return [];
20
20
  const safePrefix = prefix.toLowerCase();
@@ -22,7 +22,8 @@ function removeOwnedSubagents(agentsDir, prefix) {
22
22
  for (const file of readdirSync(agentsDir)) {
23
23
  if (!file.endsWith(".md")) continue;
24
24
  if (!file.toLowerCase().startsWith(safePrefix)) continue;
25
- const full = join(agentsDir, file);
25
+ const full = tryJoin(agentsDir, file);
26
+ if (!full) continue;
26
27
  let head;
27
28
  try {
28
29
  head = readFileSync(full, "utf-8").slice(0, 1024);
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  getDispatcherStatus,
3
3
  readClaudeConfig
4
- } from "./chunk-US5FT2UB.js";
4
+ } from "./chunk-7DGWW72Q.js";
5
5
  import {
6
6
  AgenticMailApiError,
7
7
  MANAGED_BY_MARKER,
8
8
  getAccountByName,
9
9
  resolveConfig
10
- } from "./chunk-GVR4HTBB.js";
10
+ } from "./chunk-V62JPM5R.js";
11
11
 
12
12
  // src/status.ts
13
13
  import { existsSync, readFileSync, readdirSync } from "fs";
package/dist/cli.js CHANGED
@@ -6,21 +6,21 @@ import {
6
6
  } from "./chunk-B5JDOV32.js";
7
7
  import {
8
8
  status
9
- } from "./chunk-PDJOVOWH.js";
9
+ } from "./chunk-XOTADT55.js";
10
10
  import {
11
11
  uninstall
12
- } from "./chunk-UGB5UEYX.js";
12
+ } from "./chunk-WNHGDCTG.js";
13
13
  import {
14
14
  install
15
- } from "./chunk-KQ3FJTHT.js";
16
- import "./chunk-LO5EQSQA.js";
17
- import "./chunk-US5FT2UB.js";
15
+ } from "./chunk-L35WA2XT.js";
16
+ import "./chunk-SWDS64K2.js";
17
+ import "./chunk-7DGWW72Q.js";
18
18
  import {
19
19
  AgenticMailApiError,
20
20
  listAccounts,
21
21
  resolveConfig,
22
22
  setAccountHost
23
- } from "./chunk-GVR4HTBB.js";
23
+ } from "./chunk-V62JPM5R.js";
24
24
 
25
25
  // src/cli.ts
26
26
  var GREEN = (s) => `\x1B[32m${s}\x1B[0m`;
@@ -4,8 +4,8 @@ import {
4
4
  } from "./chunk-B5JDOV32.js";
5
5
  import {
6
6
  Dispatcher
7
- } from "./chunk-QSOMPN2D.js";
8
- import "./chunk-GVR4HTBB.js";
7
+ } from "./chunk-KRB453TM.js";
8
+ import "./chunk-V62JPM5R.js";
9
9
 
10
10
  // src/dispatcher-bin.ts
11
11
  async function main() {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  Dispatcher
3
- } from "./chunk-QSOMPN2D.js";
4
- import "./chunk-GVR4HTBB.js";
3
+ } from "./chunk-KRB453TM.js";
4
+ import "./chunk-V62JPM5R.js";
5
5
  export {
6
6
  Dispatcher
7
7
  };
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  createIntegrationRoutes
3
- } from "./chunk-IMSFAZWV.js";
4
- import "./chunk-PDJOVOWH.js";
5
- import "./chunk-UGB5UEYX.js";
6
- import "./chunk-KQ3FJTHT.js";
7
- import "./chunk-LO5EQSQA.js";
8
- import "./chunk-US5FT2UB.js";
9
- import "./chunk-GVR4HTBB.js";
3
+ } from "./chunk-IXYJ4O5M.js";
4
+ import "./chunk-XOTADT55.js";
5
+ import "./chunk-WNHGDCTG.js";
6
+ import "./chunk-L35WA2XT.js";
7
+ import "./chunk-SWDS64K2.js";
8
+ import "./chunk-7DGWW72Q.js";
9
+ import "./chunk-V62JPM5R.js";
10
10
  export {
11
11
  createIntegrationRoutes
12
12
  };
package/dist/index.js CHANGED
@@ -6,21 +6,21 @@ import {
6
6
  import {
7
7
  Dispatcher,
8
8
  loadPersonaForAgent
9
- } from "./chunk-QSOMPN2D.js";
9
+ } from "./chunk-KRB453TM.js";
10
10
  import {
11
11
  createIntegrationRoutes
12
- } from "./chunk-IMSFAZWV.js";
12
+ } from "./chunk-IXYJ4O5M.js";
13
13
  import {
14
14
  status
15
- } from "./chunk-PDJOVOWH.js";
15
+ } from "./chunk-XOTADT55.js";
16
16
  import {
17
17
  uninstall
18
- } from "./chunk-UGB5UEYX.js";
18
+ } from "./chunk-WNHGDCTG.js";
19
19
  import {
20
20
  install
21
- } from "./chunk-KQ3FJTHT.js";
22
- import "./chunk-LO5EQSQA.js";
23
- import "./chunk-US5FT2UB.js";
21
+ } from "./chunk-L35WA2XT.js";
22
+ import "./chunk-SWDS64K2.js";
23
+ import "./chunk-7DGWW72Q.js";
24
24
  import {
25
25
  AgenticMailApiError,
26
26
  MANAGED_BY_MARKER,
@@ -32,7 +32,7 @@ import {
32
32
  renderPersonaBody,
33
33
  renderSubagentMarkdown,
34
34
  resolveConfig
35
- } from "./chunk-GVR4HTBB.js";
35
+ } from "./chunk-V62JPM5R.js";
36
36
  export {
37
37
  AgenticMailApiError,
38
38
  Dispatcher,
package/dist/install.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  install,
3
3
  selectExposableAgents
4
- } from "./chunk-KQ3FJTHT.js";
5
- import "./chunk-LO5EQSQA.js";
6
- import "./chunk-US5FT2UB.js";
7
- import "./chunk-GVR4HTBB.js";
4
+ } from "./chunk-L35WA2XT.js";
5
+ import "./chunk-SWDS64K2.js";
6
+ import "./chunk-7DGWW72Q.js";
7
+ import "./chunk-V62JPM5R.js";
8
8
  export {
9
9
  install,
10
10
  selectExposableAgents
package/dist/status.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  status
3
- } from "./chunk-PDJOVOWH.js";
4
- import "./chunk-US5FT2UB.js";
5
- import "./chunk-GVR4HTBB.js";
3
+ } from "./chunk-XOTADT55.js";
4
+ import "./chunk-7DGWW72Q.js";
5
+ import "./chunk-V62JPM5R.js";
6
6
  export {
7
7
  status
8
8
  };
package/dist/uninstall.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  uninstall
3
- } from "./chunk-UGB5UEYX.js";
4
- import "./chunk-LO5EQSQA.js";
5
- import "./chunk-US5FT2UB.js";
6
- import "./chunk-GVR4HTBB.js";
3
+ } from "./chunk-WNHGDCTG.js";
4
+ import "./chunk-SWDS64K2.js";
5
+ import "./chunk-7DGWW72Q.js";
6
+ import "./chunk-V62JPM5R.js";
7
7
  export {
8
8
  uninstall
9
9
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agenticmail/claudecode",
3
- "version": "0.2.14",
3
+ "version": "0.2.16",
4
4
  "description": "Claude Code integration for AgenticMail — surfaces every AgenticMail agent as a native Claude Code subagent so any Claude Code session can delegate to them with the Agent tool",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -47,8 +47,8 @@
47
47
  "prepublishOnly": "npm run build"
48
48
  },
49
49
  "dependencies": {
50
- "@agenticmail/core": "^0.9.4",
51
- "@agenticmail/mcp": "^0.9.4",
50
+ "@agenticmail/core": "^0.9.5",
51
+ "@agenticmail/mcp": "^0.9.6",
52
52
  "@anthropic-ai/claude-agent-sdk": "^0.2.140"
53
53
  },
54
54
  "peerDependencies": {