agentrace 0.0.7 → 0.0.8

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/README.md CHANGED
@@ -31,14 +31,15 @@ That's it! When you use Claude Code, sessions will be automatically sent to Agen
31
31
 
32
32
  ## Commands
33
33
 
34
- | Command | Description |
35
- | ---------------------------- | -------------------------------------- |
36
- | `agentrace init --url <url>` | Initial setup + hooks installation |
37
- | `agentrace login` | Open the web dashboard |
38
- | `agentrace send` | Send transcript diff (used by hooks) |
39
- | `agentrace on` | Enable hooks |
40
- | `agentrace off` | Disable hooks |
41
- | `agentrace uninstall` | Remove hooks and configuration |
34
+ | Command | Description |
35
+ | -------------------------------------------- | -------------------------------------- |
36
+ | `agentrace init --url <url>` | Initial setup + hooks installation |
37
+ | `agentrace init --url <url> --proxy <proxy>` | Setup with proxy |
38
+ | `agentrace login` | Open the web dashboard |
39
+ | `agentrace send` | Send transcript diff (used by hooks) |
40
+ | `agentrace on` | Enable hooks |
41
+ | `agentrace off` | Disable hooks |
42
+ | `agentrace uninstall` | Remove hooks and configuration |
42
43
 
43
44
  ## Command Details
44
45
 
@@ -122,6 +123,38 @@ Configuration is stored in the following locations:
122
123
  - Only the transcript diff is sent to the server when a Claude Code conversation ends
123
124
  - Errors do not block Claude Code's operation by design
124
125
 
126
+ ## Proxy Configuration
127
+
128
+ If you need to connect through an HTTP proxy, you can configure it in several ways:
129
+
130
+ ### 1. Using the `--proxy` Option
131
+
132
+ ```bash
133
+ npx agentrace init --url http://localhost:9080 --proxy http://proxy.example.com:8080
134
+ ```
135
+
136
+ For proxies requiring authentication:
137
+
138
+ ```bash
139
+ npx agentrace init --url http://localhost:9080 --proxy http://user:pass@proxy.example.com:8080
140
+ ```
141
+
142
+ ### 2. Using Environment Variables
143
+
144
+ If `proxy_url` is not set in the config file, the CLI will check the following environment variables (in order):
145
+
146
+ 1. `HTTPS_PROXY`
147
+ 2. `https_proxy`
148
+ 3. `HTTP_PROXY`
149
+ 4. `http_proxy`
150
+
151
+ ```bash
152
+ export HTTPS_PROXY=http://proxy.example.com:8080
153
+ npx agentrace send
154
+ ```
155
+
156
+ **Priority:** Config file > Environment variables
157
+
125
158
  ## Requirements
126
159
 
127
160
  - Node.js 18 or later
@@ -1,5 +1,6 @@
1
1
  export interface InitOptions {
2
2
  url?: string;
3
+ proxy?: string;
3
4
  dev?: boolean;
4
5
  }
5
6
  export declare function initCommand(options?: InitOptions): Promise<void>;
@@ -25,6 +25,18 @@ export async function initCommand(options = {}) {
25
25
  console.error("Error: Invalid URL format");
26
26
  process.exit(1);
27
27
  }
28
+ // Validate proxy URL if provided
29
+ if (options.proxy) {
30
+ try {
31
+ new URL(options.proxy);
32
+ }
33
+ catch {
34
+ console.error("Error: Invalid proxy URL format");
35
+ console.error("Example: http://proxy.example.com:8080");
36
+ console.error(" http://user:pass@proxy.example.com:8080");
37
+ process.exit(1);
38
+ }
39
+ }
28
40
  console.log("AgenTrace Setup\n");
29
41
  if (options.dev) {
30
42
  console.log("[Dev Mode] Using local CLI for hooks\n");
@@ -61,8 +73,12 @@ export async function initCommand(options = {}) {
61
73
  saveConfig({
62
74
  server_url: serverUrlStr,
63
75
  api_key: result.apiKey,
76
+ ...(options.proxy && { proxy_url: options.proxy }),
64
77
  });
65
78
  console.log(`✓ Config saved to ${getConfigPath()}`);
79
+ if (options.proxy) {
80
+ console.log(` Proxy: ${options.proxy}`);
81
+ }
66
82
  // Determine hook command
67
83
  let hookCommand;
68
84
  if (options.dev) {
@@ -1,6 +1,7 @@
1
1
  export interface AgentraceConfig {
2
2
  server_url: string;
3
3
  api_key: string;
4
+ proxy_url?: string;
4
5
  }
5
6
  export declare function getConfigPath(): string;
6
7
  export declare function loadConfig(): AgentraceConfig | null;
package/dist/index.js CHANGED
@@ -13,9 +13,10 @@ program
13
13
  .command("init")
14
14
  .description("Initialize agentrace configuration and hooks")
15
15
  .requiredOption("--url <url>", "Server URL (required)")
16
+ .option("--proxy <url>", "HTTP/HTTPS proxy URL")
16
17
  .option("--dev", "Use local CLI path for development")
17
18
  .action(async (options) => {
18
- await initCommand({ url: options.url, dev: options.dev });
19
+ await initCommand({ url: options.url, proxy: options.proxy, dev: options.dev });
19
20
  });
20
21
  program
21
22
  .command("login")
@@ -1,4 +1,6 @@
1
+ import { fetch } from "undici";
1
2
  import { loadConfig } from "../config/manager.js";
3
+ import { createDispatcher } from "../utils/proxy.js";
2
4
  export class PlanDocumentClient {
3
5
  serverUrl;
4
6
  apiKey;
@@ -20,6 +22,7 @@ export class PlanDocumentClient {
20
22
  method,
21
23
  headers,
22
24
  body: body ? JSON.stringify(body) : undefined,
25
+ dispatcher: createDispatcher(),
23
26
  });
24
27
  if (!response.ok) {
25
28
  const errorText = await response.text();
@@ -1,4 +1,6 @@
1
+ import { fetch } from "undici";
1
2
  import { loadConfig } from "../config/manager.js";
3
+ import { createDispatcher } from "./proxy.js";
2
4
  function getBaseUrl(config) {
3
5
  return config.server_url.replace(/\/+$/, '');
4
6
  }
@@ -16,6 +18,7 @@ export async function sendIngest(payload) {
16
18
  Authorization: `Bearer ${config.api_key}`,
17
19
  },
18
20
  body: JSON.stringify(payload),
21
+ dispatcher: createDispatcher(),
19
22
  });
20
23
  if (!response.ok) {
21
24
  const text = await response.text();
@@ -41,6 +44,7 @@ export async function createWebSession() {
41
44
  "Content-Type": "application/json",
42
45
  Authorization: `Bearer ${config.api_key}`,
43
46
  },
47
+ dispatcher: createDispatcher(),
44
48
  });
45
49
  if (!response.ok) {
46
50
  const text = await response.text();
@@ -0,0 +1,11 @@
1
+ import { ProxyAgent } from 'undici';
2
+ /**
3
+ * プロキシURLを取得する
4
+ * 優先順位: 設定ファイル > 環境変数(HTTPS_PROXY > HTTP_PROXY)
5
+ */
6
+ export declare function getProxyUrl(): string | undefined;
7
+ /**
8
+ * undici の dispatcher を生成する
9
+ * プロキシ設定がない場合は undefined を返す(デフォルト動作)
10
+ */
11
+ export declare function createDispatcher(): ProxyAgent | undefined;
@@ -0,0 +1,29 @@
1
+ import { ProxyAgent } from 'undici';
2
+ import { loadConfig } from '../config/manager.js';
3
+ /**
4
+ * プロキシURLを取得する
5
+ * 優先順位: 設定ファイル > 環境変数(HTTPS_PROXY > HTTP_PROXY)
6
+ */
7
+ export function getProxyUrl() {
8
+ const config = loadConfig();
9
+ // 設定ファイル優先
10
+ if (config?.proxy_url) {
11
+ return config.proxy_url;
12
+ }
13
+ // 環境変数フォールバック(大文字・小文字両方サポート)
14
+ return process.env.HTTPS_PROXY
15
+ || process.env.https_proxy
16
+ || process.env.HTTP_PROXY
17
+ || process.env.http_proxy;
18
+ }
19
+ /**
20
+ * undici の dispatcher を生成する
21
+ * プロキシ設定がない場合は undefined を返す(デフォルト動作)
22
+ */
23
+ export function createDispatcher() {
24
+ const proxyUrl = getProxyUrl();
25
+ if (!proxyUrl) {
26
+ return undefined;
27
+ }
28
+ return new ProxyAgent(proxyUrl);
29
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,116 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { ProxyAgent } from 'undici';
3
+ // モックを設定
4
+ vi.mock('../config/manager.js', () => ({
5
+ loadConfig: vi.fn(),
6
+ }));
7
+ import { getProxyUrl, createDispatcher } from './proxy.js';
8
+ import { loadConfig } from '../config/manager.js';
9
+ const mockedLoadConfig = vi.mocked(loadConfig);
10
+ describe('proxy', () => {
11
+ const originalEnv = process.env;
12
+ beforeEach(() => {
13
+ // 環境変数をリセット
14
+ process.env = { ...originalEnv };
15
+ delete process.env.HTTPS_PROXY;
16
+ delete process.env.https_proxy;
17
+ delete process.env.HTTP_PROXY;
18
+ delete process.env.http_proxy;
19
+ // モックをリセット
20
+ vi.clearAllMocks();
21
+ });
22
+ afterEach(() => {
23
+ process.env = originalEnv;
24
+ });
25
+ describe('getProxyUrl', () => {
26
+ it('設定ファイルにproxy_urlがある場合、それを返す', () => {
27
+ mockedLoadConfig.mockReturnValue({
28
+ server_url: 'http://localhost:8080',
29
+ api_key: 'test-key',
30
+ proxy_url: 'http://proxy.example.com:8080',
31
+ });
32
+ expect(getProxyUrl()).toBe('http://proxy.example.com:8080');
33
+ });
34
+ it('設定ファイルにproxy_urlがなく、HTTPS_PROXYがある場合、それを返す', () => {
35
+ mockedLoadConfig.mockReturnValue({
36
+ server_url: 'http://localhost:8080',
37
+ api_key: 'test-key',
38
+ });
39
+ process.env.HTTPS_PROXY = 'http://https-proxy.example.com:8080';
40
+ expect(getProxyUrl()).toBe('http://https-proxy.example.com:8080');
41
+ });
42
+ it('設定ファイルにproxy_urlがなく、https_proxy(小文字)がある場合、それを返す', () => {
43
+ mockedLoadConfig.mockReturnValue({
44
+ server_url: 'http://localhost:8080',
45
+ api_key: 'test-key',
46
+ });
47
+ process.env.https_proxy = 'http://https-proxy-lower.example.com:8080';
48
+ expect(getProxyUrl()).toBe('http://https-proxy-lower.example.com:8080');
49
+ });
50
+ it('設定ファイルにproxy_urlがなく、HTTP_PROXYがある場合、それを返す', () => {
51
+ mockedLoadConfig.mockReturnValue({
52
+ server_url: 'http://localhost:8080',
53
+ api_key: 'test-key',
54
+ });
55
+ process.env.HTTP_PROXY = 'http://http-proxy.example.com:8080';
56
+ expect(getProxyUrl()).toBe('http://http-proxy.example.com:8080');
57
+ });
58
+ it('設定ファイルにproxy_urlがなく、http_proxy(小文字)がある場合、それを返す', () => {
59
+ mockedLoadConfig.mockReturnValue({
60
+ server_url: 'http://localhost:8080',
61
+ api_key: 'test-key',
62
+ });
63
+ process.env.http_proxy = 'http://http-proxy-lower.example.com:8080';
64
+ expect(getProxyUrl()).toBe('http://http-proxy-lower.example.com:8080');
65
+ });
66
+ it('設定ファイルも環境変数もない場合、undefinedを返す', () => {
67
+ mockedLoadConfig.mockReturnValue({
68
+ server_url: 'http://localhost:8080',
69
+ api_key: 'test-key',
70
+ });
71
+ expect(getProxyUrl()).toBeUndefined();
72
+ });
73
+ it('設定ファイルがnullの場合、環境変数にフォールバックする', () => {
74
+ mockedLoadConfig.mockReturnValue(null);
75
+ process.env.HTTPS_PROXY = 'http://env-proxy.example.com:8080';
76
+ expect(getProxyUrl()).toBe('http://env-proxy.example.com:8080');
77
+ });
78
+ it('設定ファイルが環境変数より優先される', () => {
79
+ mockedLoadConfig.mockReturnValue({
80
+ server_url: 'http://localhost:8080',
81
+ api_key: 'test-key',
82
+ proxy_url: 'http://config-proxy.example.com:8080',
83
+ });
84
+ process.env.HTTPS_PROXY = 'http://env-proxy.example.com:8080';
85
+ expect(getProxyUrl()).toBe('http://config-proxy.example.com:8080');
86
+ });
87
+ it('HTTPS_PROXYがHTTP_PROXYより優先される', () => {
88
+ mockedLoadConfig.mockReturnValue({
89
+ server_url: 'http://localhost:8080',
90
+ api_key: 'test-key',
91
+ });
92
+ process.env.HTTPS_PROXY = 'http://https-proxy.example.com:8080';
93
+ process.env.HTTP_PROXY = 'http://http-proxy.example.com:8080';
94
+ expect(getProxyUrl()).toBe('http://https-proxy.example.com:8080');
95
+ });
96
+ });
97
+ describe('createDispatcher', () => {
98
+ it('プロキシURLがある場合、ProxyAgentを返す', () => {
99
+ mockedLoadConfig.mockReturnValue({
100
+ server_url: 'http://localhost:8080',
101
+ api_key: 'test-key',
102
+ proxy_url: 'http://proxy.example.com:8080',
103
+ });
104
+ const dispatcher = createDispatcher();
105
+ expect(dispatcher).toBeInstanceOf(ProxyAgent);
106
+ });
107
+ it('プロキシURLがない場合、undefinedを返す', () => {
108
+ mockedLoadConfig.mockReturnValue({
109
+ server_url: 'http://localhost:8080',
110
+ api_key: 'test-key',
111
+ });
112
+ const dispatcher = createDispatcher();
113
+ expect(dispatcher).toBeUndefined();
114
+ });
115
+ });
116
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentrace",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "description": "CLI for AgenTrace - Claude Code session tracker",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,6 +13,8 @@
13
13
  "scripts": {
14
14
  "build": "tsc",
15
15
  "dev": "tsx src/index.ts",
16
+ "test": "vitest run",
17
+ "test:watch": "vitest",
16
18
  "prepublishOnly": "npm run build"
17
19
  },
18
20
  "keywords": [
@@ -38,12 +40,14 @@
38
40
  "@modelcontextprotocol/sdk": "^1.0.0",
39
41
  "commander": "^12.0.0",
40
42
  "diff-match-patch-es": "^1.0.0",
43
+ "undici": "^7.18.2",
41
44
  "zod": "^3.25.0"
42
45
  },
43
46
  "devDependencies": {
44
47
  "@types/node": "^20.0.0",
45
48
  "tsx": "^4.0.0",
46
- "typescript": "^5.0.0"
49
+ "typescript": "^5.0.0",
50
+ "vitest": "^4.0.17"
47
51
  },
48
52
  "engines": {
49
53
  "node": ">=18.0.0"