claude-ide-bridge 2.5.0 → 2.5.2
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 +47 -8
- package/dist/activityLog.d.ts +2 -8
- package/dist/activityLog.js +2 -6
- package/dist/activityLog.js.map +1 -1
- package/dist/activityTypes.d.ts +0 -4
- package/dist/bridge.d.ts +3 -0
- package/dist/bridge.js +36 -39
- package/dist/bridge.js.map +1 -1
- package/dist/config.d.ts +0 -2
- package/dist/config.js +0 -17
- package/dist/config.js.map +1 -1
- package/dist/index.js +0 -95
- package/dist/index.js.map +1 -1
- package/dist/prompts.js +3 -2
- package/dist/prompts.js.map +1 -1
- package/dist/server.d.ts +1 -31
- package/dist/server.js +12 -99
- package/dist/server.js.map +1 -1
- package/dist/streamableHttp.js +5 -10
- package/dist/streamableHttp.js.map +1 -1
- package/dist/tools/auditDependencies.js +5 -2
- package/dist/tools/auditDependencies.js.map +1 -1
- package/dist/tools/fileOperations.js +5 -5
- package/dist/tools/fileOperations.js.map +1 -1
- package/dist/tools/getSecurityAdvisories.js +5 -2
- package/dist/tools/getSecurityAdvisories.js.map +1 -1
- package/dist/tools/handoffNote.d.ts +17 -2
- package/dist/tools/handoffNote.js +56 -18
- package/dist/tools/handoffNote.js.map +1 -1
- package/dist/tools/httpClient.js +17 -1
- package/dist/tools/httpClient.js.map +1 -1
- package/dist/tools/index.js +2 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/searchAndReplace.js +8 -0
- package/dist/tools/searchAndReplace.js.map +1 -1
- package/dist/tools/terminal.js +24 -2
- package/dist/tools/terminal.js.map +1 -1
- package/dist/tools/utils.js +35 -13
- package/dist/tools/utils.js.map +1 -1
- package/dist/transport.d.ts +0 -2
- package/dist/transport.js +2 -32
- package/dist/transport.js.map +1 -1
- package/package.json +1 -1
- package/scripts/gen-mcp-config.sh +15 -4
- package/scripts/install-extension.sh +6 -1
- package/scripts/start-all.sh +86 -9
- package/templates/CLAUDE.bridge.md +37 -1
- package/templates/dispatch-context.md +4 -0
- package/templates/scheduled-tasks/dependency-audit/SKILL.md +27 -2
- package/templates/scheduled-tasks/health-check/SKILL.md +19 -0
- package/templates/scheduled-tasks/nightly-review/SKILL.md +24 -0
- package/dist/teammateTokens.d.ts +0 -61
- package/dist/teammateTokens.js +0 -202
- package/dist/teammateTokens.js.map +0 -1
|
@@ -63,6 +63,8 @@ Path globs on rule files mean Claude only loads them when working on matching fi
|
|
|
63
63
|
|
|
64
64
|
### Dispatch prompts (mobile)
|
|
65
65
|
|
|
66
|
+
When a terse message arrives via Claude Desktop Dispatch (phone/Siri), Claude automatically routes it to the appropriate bridge prompt. You can also invoke these prompts directly by name in any chat.
|
|
67
|
+
|
|
66
68
|
When responding to terse Dispatch messages from a phone, use these prompts for consistent, concise output:
|
|
67
69
|
|
|
68
70
|
| Phone message | Prompt | Tools called |
|
|
@@ -82,4 +84,38 @@ Keep responses concise (under 20 lines) when the conversation arrives via Dispat
|
|
|
82
84
|
| Team lead checking on parallel agents | `team-status` | Workspace state, active tasks, recent activity across sessions |
|
|
83
85
|
| Scheduled nightly/hourly health check | `health-check` | Tests + diagnostics + security advisories + git status |
|
|
84
86
|
|
|
85
|
-
|
|
87
|
+
> Prerequisite for `team-status`: multiple Claude Code sessions must be connected simultaneously. Solo sessions will show empty team activity.
|
|
88
|
+
|
|
89
|
+
> **Claude Code ≥ v2.1.77**: `SendMessage` auto-resumes stopped agents — no need to check whether a teammate is running before sending to it.
|
|
90
|
+
|
|
91
|
+
Ready-made scheduled task templates are available in `templates/scheduled-tasks/` — copy to `~/.claude/scheduled-tasks/` for recurring autonomous workflows (nightly-review, health-check, dependency-audit):
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
cp templates/scheduled-tasks/health-check/SKILL.md ~/.claude/scheduled-tasks/health-check.md
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
(And restart Claude Desktop to detect it.)
|
|
98
|
+
|
|
99
|
+
### Cowork (computer-use)
|
|
100
|
+
|
|
101
|
+
**MCP bridge tools are NOT available inside Cowork sessions.** Always run `/mcp__bridge__cowork` in a regular Claude Code or Claude Desktop chat first to gather context and write a handoff note, then open Cowork.
|
|
102
|
+
|
|
103
|
+
Workflow:
|
|
104
|
+
1. Regular chat: run `/mcp__bridge__cowork` → Claude collects IDE state → calls `setHandoffNote`
|
|
105
|
+
2. Open Cowork (Cmd+2 on Mac) → Cowork reads the handoff note for context
|
|
106
|
+
|
|
107
|
+
**If bridge tools are missing from your tool list inside Cowork:** you're in the wrong context. Exit, run the prompt in regular chat, then return.
|
|
108
|
+
|
|
109
|
+
Full details: [docs/cowork-workflow.md](docs/cowork-workflow.md)
|
|
110
|
+
|
|
111
|
+
**Cowork uses git worktrees:** Cowork sessions operate in an isolated git worktree (separate branch/working copy), not the main workspace root. Files written by Cowork land in the worktree. Always add "write all files to the workspace root, not a subdirectory" as the first instruction in your CLAUDE.md when using Cowork with a synced workspace. After Cowork finishes, review and merge the worktree branch back to main.
|
|
112
|
+
|
|
113
|
+
### Session continuity
|
|
114
|
+
|
|
115
|
+
| Scenario | Action |
|
|
116
|
+
|---|---|
|
|
117
|
+
| Switching CLI → Desktop | Call `setHandoffNote` before switching; bridge auto-snapshots if note is >5 min stale |
|
|
118
|
+
| Session just started | Call `getHandoffNote` to pick up prior context (workspace-scoped). **Caution:** the `onInstructionsLoaded` automation hook may have auto-overwritten the note at session start — if the content looks generic or templated, treat it as stale and consult any persistent session log your project maintains (e.g. `docs/session-log.md`) for authoritative history. |
|
|
119
|
+
| Bridge restarted | First connected client receives a "restored from checkpoint" notification |
|
|
120
|
+
| Preparing for Cowork | Run `/mcp__bridge__cowork` in regular chat first — Cowork has no MCP access |
|
|
121
|
+
| Multi-workspace | Notes are workspace-scoped; switching workspaces won't overwrite each other's notes |
|
|
@@ -27,3 +27,7 @@ When the user message is short (< 20 words), assume it's from Dispatch (phone) a
|
|
|
27
27
|
## Available tools
|
|
28
28
|
|
|
29
29
|
124+ MCP tools across: file ops, git, GitHub, LSP, diagnostics, testing, debugging, terminals, security audits, and more. Call `getToolCapabilities` if unsure what's available.
|
|
30
|
+
|
|
31
|
+
## Scripted / automated `-p` calls
|
|
32
|
+
|
|
33
|
+
For non-interactive scripted invocations using `-p`, pass `--bare` (Claude Code ≥ 2.1.81) to skip hooks, LSP initialization, and plugin sync. This reduces startup overhead significantly for fast one-shot automation.
|
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
## Installation
|
|
2
|
+
|
|
3
|
+
Copy this template to your Claude Desktop scheduled-tasks directory:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
mkdir -p ~/.claude/scheduled-tasks/dependency-audit
|
|
7
|
+
cp /path/to/claude-ide-bridge/templates/scheduled-tasks/dependency-audit/SKILL.md \
|
|
8
|
+
~/.claude/scheduled-tasks/dependency-audit/SKILL.md
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Then restart Claude Desktop to detect the new scheduled task. Configure the schedule in Claude Desktop settings under "Scheduled Tasks".
|
|
12
|
+
|
|
13
|
+
> The bridge must be running when this task fires. Start it with `claude-ide-bridge --watch` or `npm run start-all`.
|
|
14
|
+
|
|
15
|
+
> **Emergency stop**: Set `CLAUDE_CODE_DISABLE_CRON=1` in your environment to immediately halt all scheduled cron jobs mid-session. Useful if a task runs amok or you need to suppress scheduled runs temporarily.
|
|
16
|
+
|
|
17
|
+
---
|
|
1
18
|
---
|
|
2
19
|
name: dependency-audit
|
|
3
20
|
description: Scan dependencies for security vulnerabilities and outdated packages. Run weekly via Claude Desktop scheduled tasks.
|
|
@@ -35,7 +52,8 @@ Scan all project dependencies for known security vulnerabilities.
|
|
|
35
52
|
<package@version — description>
|
|
36
53
|
|
|
37
54
|
## Outdated Packages
|
|
38
|
-
<package — current → latest> (only
|
|
55
|
+
<package — current → latest> (only packages ≥1 major version OR ≥3 minor versions behind)
|
|
56
|
+
Direct: listed in package.json. Transitive: pulled in by direct dependencies.
|
|
39
57
|
|
|
40
58
|
## Recommended Actions
|
|
41
59
|
1. <specific upgrade command or action>
|
|
@@ -44,9 +62,16 @@ Scan all project dependencies for known security vulnerabilities.
|
|
|
44
62
|
## Overall: SECURE | REVIEW NEEDED | ACTION REQUIRED
|
|
45
63
|
```
|
|
46
64
|
|
|
65
|
+
## Grading Criteria
|
|
66
|
+
|
|
67
|
+
- **SECURE** — 0 vulnerabilities + ≤2 patch-level outdated packages
|
|
68
|
+
- **REVIEW NEEDED** — 1-2 moderate advisories OR ≥3 outdated packages
|
|
69
|
+
- **ACTION REQUIRED** — any critical/high vulnerability
|
|
70
|
+
|
|
47
71
|
## Guidelines
|
|
48
72
|
|
|
49
73
|
- Focus on actionable findings — skip informational-only advisories
|
|
74
|
+
- Report only packages ≥1 major version OR ≥3 minor versions behind as "outdated"
|
|
75
|
+
- Direct dependencies: listed in package.json. Transitive: pulled in by direct dependencies. Flag transitive dependencies separately.
|
|
50
76
|
- For each vulnerability, include the fix command if one exists (e.g., `npm install package@version`)
|
|
51
77
|
- If no vulnerabilities found, report "All clear — 0 vulnerabilities across N dependencies"
|
|
52
|
-
- Flag transitive dependencies separately from direct dependencies
|
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
## Installation
|
|
2
|
+
|
|
3
|
+
Copy this template to your Claude Desktop scheduled-tasks directory:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
mkdir -p ~/.claude/scheduled-tasks/health-check
|
|
7
|
+
cp /path/to/claude-ide-bridge/templates/scheduled-tasks/health-check/SKILL.md \
|
|
8
|
+
~/.claude/scheduled-tasks/health-check/SKILL.md
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Then restart Claude Desktop to detect the new scheduled task. Configure the schedule in Claude Desktop settings under "Scheduled Tasks".
|
|
12
|
+
|
|
13
|
+
> The bridge must be running when this task fires. Start it with `claude-ide-bridge --watch` or `npm run start-all`.
|
|
14
|
+
|
|
15
|
+
> **Emergency stop**: Set `CLAUDE_CODE_DISABLE_CRON=1` in your environment to immediately halt all scheduled cron jobs mid-session. Useful if a task runs amok or you need to suppress scheduled runs temporarily.
|
|
16
|
+
|
|
17
|
+
---
|
|
1
18
|
---
|
|
2
19
|
name: health-check
|
|
3
20
|
description: Comprehensive project health — tests, diagnostics, security, and git status. Run hourly or daily via Claude Desktop scheduled tasks.
|
|
@@ -50,5 +67,7 @@ Advisories: <N critical, M high, K moderate | None>
|
|
|
50
67
|
## Guidelines
|
|
51
68
|
|
|
52
69
|
- If `getSecurityAdvisories` or `auditDependencies` are unavailable, note "Security: not checked (tools unavailable)"
|
|
70
|
+
- For security advisories, report only HIGH and CRITICAL severity. Moderate/low can be logged but don't affect the grade.
|
|
53
71
|
- This runs unattended — no interactive prompts, no questions
|
|
54
72
|
- Keep the report structured and scannable
|
|
73
|
+
- Avoid emojis in automated reports for clarity.
|
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
## Installation
|
|
2
|
+
|
|
3
|
+
Copy this template to your Claude Desktop scheduled-tasks directory:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
mkdir -p ~/.claude/scheduled-tasks/nightly-review
|
|
7
|
+
cp /path/to/claude-ide-bridge/templates/scheduled-tasks/nightly-review/SKILL.md \
|
|
8
|
+
~/.claude/scheduled-tasks/nightly-review/SKILL.md
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Then restart Claude Desktop to detect the new scheduled task. Configure the schedule in Claude Desktop settings under "Scheduled Tasks".
|
|
12
|
+
|
|
13
|
+
> The bridge must be running when this task fires. Start it with `claude-ide-bridge --watch` or `npm run start-all`.
|
|
14
|
+
|
|
15
|
+
> **Emergency stop**: Set `CLAUDE_CODE_DISABLE_CRON=1` in your environment to immediately halt all scheduled cron jobs mid-session. Useful if a task runs amok or you need to suppress scheduled runs temporarily.
|
|
16
|
+
|
|
17
|
+
---
|
|
1
18
|
---
|
|
2
19
|
name: nightly-review
|
|
3
20
|
description: Review uncommitted changes, check diagnostics, and summarize test status. Run nightly via Claude Desktop scheduled tasks.
|
|
@@ -25,6 +42,7 @@ Uncommitted: <N files changed, M insertions, K deletions>
|
|
|
25
42
|
|
|
26
43
|
## Changes Summary
|
|
27
44
|
<file-by-file summary, 1 line per file: what changed and why it looks correct or concerning>
|
|
45
|
+
Example: `src/bridge.ts: Added error handling for stale connections (+12 lines)`
|
|
28
46
|
|
|
29
47
|
## Diagnostics
|
|
30
48
|
<N errors, M warnings — list files with errors>
|
|
@@ -38,6 +56,12 @@ Uncommitted: <N files changed, M insertions, K deletions>
|
|
|
38
56
|
<1-3 sentences summarizing the overall state and any recommended actions>
|
|
39
57
|
```
|
|
40
58
|
|
|
59
|
+
## Action Matrix
|
|
60
|
+
|
|
61
|
+
- **CLEAN** — no action needed
|
|
62
|
+
- **NEEDS ATTENTION** — leave a note for the next session
|
|
63
|
+
- **BROKEN** — flag immediately
|
|
64
|
+
|
|
41
65
|
## Guidelines
|
|
42
66
|
|
|
43
67
|
- Be thorough but concise — this report is read the next morning
|
package/dist/teammateTokens.d.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Teammate token management: generation, storage, verification, and hot-reload.
|
|
3
|
-
*
|
|
4
|
-
* Token format: cib_{8-char-identifier}_{32-char-secret}
|
|
5
|
-
* Storage: ~/.claude/ide/tokens.json with SHA-256 hashes (never raw secrets)
|
|
6
|
-
* Lookup: O(1) by identifier → timingSafeEqual on hash (no count leakage)
|
|
7
|
-
*/
|
|
8
|
-
export interface StoredToken {
|
|
9
|
-
identifier: string;
|
|
10
|
-
name: string;
|
|
11
|
-
sha256Hash: string;
|
|
12
|
-
scopes: ("full" | "read-only")[];
|
|
13
|
-
createdAt: string;
|
|
14
|
-
lastUsedAt?: string;
|
|
15
|
-
}
|
|
16
|
-
export interface TokensFile {
|
|
17
|
-
version: 1;
|
|
18
|
-
tokens: StoredToken[];
|
|
19
|
-
}
|
|
20
|
-
export interface VerifiedToken {
|
|
21
|
-
name: string;
|
|
22
|
-
scopes: ("full" | "read-only")[];
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Parse a prefixed token string into its components.
|
|
26
|
-
* Returns null if the format is invalid.
|
|
27
|
-
*/
|
|
28
|
-
export declare function parseToken(raw: string): {
|
|
29
|
-
identifier: string;
|
|
30
|
-
secret: string;
|
|
31
|
-
} | null;
|
|
32
|
-
/**
|
|
33
|
-
* Generate a new teammate token.
|
|
34
|
-
* Returns both the raw token (display once, never store) and the storable form.
|
|
35
|
-
*/
|
|
36
|
-
export declare function generateToken(name: string, scopes?: ("full" | "read-only")[]): {
|
|
37
|
-
token: string;
|
|
38
|
-
stored: StoredToken;
|
|
39
|
-
};
|
|
40
|
-
/** Validate a teammate name. */
|
|
41
|
-
export declare function isValidName(name: string): boolean;
|
|
42
|
-
/** Validate a raw token format. */
|
|
43
|
-
export declare function isValidTokenFormat(raw: string): boolean;
|
|
44
|
-
/** Load tokens from disk into a Map keyed by identifier for O(1) lookup. */
|
|
45
|
-
export declare function loadTokens(tokensPath: string): Map<string, StoredToken>;
|
|
46
|
-
/** Save tokens to disk atomically (write tmp + rename). */
|
|
47
|
-
export declare function saveTokens(tokensPath: string, tokens: Map<string, StoredToken>): void;
|
|
48
|
-
/**
|
|
49
|
-
* Verify a raw token against the stored tokens map.
|
|
50
|
-
* Returns the verified token info or null if not found / invalid.
|
|
51
|
-
* O(1) lookup by identifier, single timingSafeEqual on hash.
|
|
52
|
-
*/
|
|
53
|
-
export declare function verifyToken(raw: string, tokens: Map<string, StoredToken>): VerifiedToken | null;
|
|
54
|
-
/**
|
|
55
|
-
* Watch tokens file for changes and reload automatically.
|
|
56
|
-
* Returns an unsubscribe function.
|
|
57
|
-
*/
|
|
58
|
-
export declare function watchTokensFile(tokensPath: string, onReload: (tokens: Map<string, StoredToken>) => void): () => void;
|
|
59
|
-
export declare function touchLastUsed(tokensPath: string, identifier: string): void;
|
|
60
|
-
/** Get the default tokens file path. */
|
|
61
|
-
export declare function defaultTokensPath(): string;
|
package/dist/teammateTokens.js
DELETED
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Teammate token management: generation, storage, verification, and hot-reload.
|
|
3
|
-
*
|
|
4
|
-
* Token format: cib_{8-char-identifier}_{32-char-secret}
|
|
5
|
-
* Storage: ~/.claude/ide/tokens.json with SHA-256 hashes (never raw secrets)
|
|
6
|
-
* Lookup: O(1) by identifier → timingSafeEqual on hash (no count leakage)
|
|
7
|
-
*/
|
|
8
|
-
import crypto from "node:crypto";
|
|
9
|
-
import fs from "node:fs";
|
|
10
|
-
import os from "node:os";
|
|
11
|
-
import path from "node:path";
|
|
12
|
-
const TOKEN_PREFIX = "cib";
|
|
13
|
-
const IDENTIFIER_LENGTH = 8; // hex chars
|
|
14
|
-
const SECRET_LENGTH = 32; // hex chars
|
|
15
|
-
const TOKEN_REGEX = new RegExp(`^${TOKEN_PREFIX}_[0-9a-f]{${IDENTIFIER_LENGTH}}_[0-9a-f]{${SECRET_LENGTH}}$`);
|
|
16
|
-
const NAME_REGEX = /^[a-zA-Z0-9_-]{1,32}$/;
|
|
17
|
-
/** Debounce interval for updating lastUsedAt (avoid disk thrash). */
|
|
18
|
-
const LAST_USED_DEBOUNCE_MS = 60_000; // 1 minute
|
|
19
|
-
/**
|
|
20
|
-
* Parse a prefixed token string into its components.
|
|
21
|
-
* Returns null if the format is invalid.
|
|
22
|
-
*/
|
|
23
|
-
export function parseToken(raw) {
|
|
24
|
-
if (!TOKEN_REGEX.test(raw))
|
|
25
|
-
return null;
|
|
26
|
-
const parts = raw.split("_");
|
|
27
|
-
if (parts.length !== 3 || !parts[1] || !parts[2])
|
|
28
|
-
return null;
|
|
29
|
-
return { identifier: parts[1], secret: parts[2] };
|
|
30
|
-
}
|
|
31
|
-
/** SHA-256 hash of a raw token string, returned as hex. */
|
|
32
|
-
function hashToken(raw) {
|
|
33
|
-
return crypto.createHash("sha256").update(raw, "utf8").digest("hex");
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Generate a new teammate token.
|
|
37
|
-
* Returns both the raw token (display once, never store) and the storable form.
|
|
38
|
-
*/
|
|
39
|
-
export function generateToken(name, scopes = ["full"]) {
|
|
40
|
-
if (!NAME_REGEX.test(name)) {
|
|
41
|
-
throw new Error(`Invalid teammate name "${name}": must be 1-32 chars [a-zA-Z0-9_-]`);
|
|
42
|
-
}
|
|
43
|
-
const identifier = crypto.randomBytes(4).toString("hex"); // 8 hex chars
|
|
44
|
-
const secret = crypto.randomBytes(16).toString("hex"); // 32 hex chars
|
|
45
|
-
const token = `${TOKEN_PREFIX}_${identifier}_${secret}`;
|
|
46
|
-
return {
|
|
47
|
-
token,
|
|
48
|
-
stored: {
|
|
49
|
-
identifier,
|
|
50
|
-
name,
|
|
51
|
-
sha256Hash: hashToken(token),
|
|
52
|
-
scopes,
|
|
53
|
-
createdAt: new Date().toISOString(),
|
|
54
|
-
},
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
/** Validate a teammate name. */
|
|
58
|
-
export function isValidName(name) {
|
|
59
|
-
return NAME_REGEX.test(name);
|
|
60
|
-
}
|
|
61
|
-
/** Validate a raw token format. */
|
|
62
|
-
export function isValidTokenFormat(raw) {
|
|
63
|
-
return TOKEN_REGEX.test(raw);
|
|
64
|
-
}
|
|
65
|
-
/** Load tokens from disk into a Map keyed by identifier for O(1) lookup. */
|
|
66
|
-
export function loadTokens(tokensPath) {
|
|
67
|
-
const map = new Map();
|
|
68
|
-
try {
|
|
69
|
-
const raw = fs.readFileSync(tokensPath, "utf8");
|
|
70
|
-
const data = JSON.parse(raw);
|
|
71
|
-
if (data.version !== 1 || !Array.isArray(data.tokens))
|
|
72
|
-
return map;
|
|
73
|
-
for (const t of data.tokens) {
|
|
74
|
-
if (typeof t.identifier === "string" &&
|
|
75
|
-
typeof t.name === "string" &&
|
|
76
|
-
typeof t.sha256Hash === "string" &&
|
|
77
|
-
/^[0-9a-f]{64}$/.test(t.sha256Hash) &&
|
|
78
|
-
Array.isArray(t.scopes)) {
|
|
79
|
-
map.set(t.identifier, t);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
catch (err) {
|
|
84
|
-
const code = err.code;
|
|
85
|
-
if (code !== "ENOENT") {
|
|
86
|
-
process.stderr.write(`[teammateTokens] Failed to load ${tokensPath}: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
return map;
|
|
90
|
-
}
|
|
91
|
-
/** Save tokens to disk atomically (write tmp + rename). */
|
|
92
|
-
export function saveTokens(tokensPath, tokens) {
|
|
93
|
-
const dir = path.dirname(tokensPath);
|
|
94
|
-
if (!fs.existsSync(dir)) {
|
|
95
|
-
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
96
|
-
}
|
|
97
|
-
const data = {
|
|
98
|
-
version: 1,
|
|
99
|
-
tokens: [...tokens.values()],
|
|
100
|
-
};
|
|
101
|
-
const tmpPath = `${tokensPath}.tmp.${process.pid}`;
|
|
102
|
-
fs.writeFileSync(tmpPath, JSON.stringify(data, null, 2), {
|
|
103
|
-
mode: 0o600,
|
|
104
|
-
});
|
|
105
|
-
fs.renameSync(tmpPath, tokensPath);
|
|
106
|
-
fs.chmodSync(tokensPath, 0o600);
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Verify a raw token against the stored tokens map.
|
|
110
|
-
* Returns the verified token info or null if not found / invalid.
|
|
111
|
-
* O(1) lookup by identifier, single timingSafeEqual on hash.
|
|
112
|
-
*/
|
|
113
|
-
export function verifyToken(raw, tokens) {
|
|
114
|
-
const parsed = parseToken(raw);
|
|
115
|
-
if (!parsed)
|
|
116
|
-
return null;
|
|
117
|
-
const stored = tokens.get(parsed.identifier);
|
|
118
|
-
if (!stored)
|
|
119
|
-
return null;
|
|
120
|
-
const inputHash = Buffer.from(hashToken(raw), "hex");
|
|
121
|
-
const storedHash = Buffer.from(stored.sha256Hash, "hex");
|
|
122
|
-
if (inputHash.length !== storedHash.length)
|
|
123
|
-
return null;
|
|
124
|
-
if (!crypto.timingSafeEqual(inputHash, storedHash))
|
|
125
|
-
return null;
|
|
126
|
-
return { name: stored.name, scopes: stored.scopes };
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Watch tokens file for changes and reload automatically.
|
|
130
|
-
* Returns an unsubscribe function.
|
|
131
|
-
*/
|
|
132
|
-
export function watchTokensFile(tokensPath, onReload) {
|
|
133
|
-
let debounceTimer = null;
|
|
134
|
-
let watcher = null;
|
|
135
|
-
try {
|
|
136
|
-
// Ensure the file exists before watching (fs.watch requires it on some platforms)
|
|
137
|
-
if (!fs.existsSync(tokensPath)) {
|
|
138
|
-
const dir = path.dirname(tokensPath);
|
|
139
|
-
if (!fs.existsSync(dir)) {
|
|
140
|
-
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
141
|
-
}
|
|
142
|
-
saveTokens(tokensPath, new Map());
|
|
143
|
-
}
|
|
144
|
-
watcher = fs.watch(tokensPath, () => {
|
|
145
|
-
if (debounceTimer)
|
|
146
|
-
clearTimeout(debounceTimer);
|
|
147
|
-
debounceTimer = setTimeout(() => {
|
|
148
|
-
const reloaded = loadTokens(tokensPath);
|
|
149
|
-
onReload(reloaded);
|
|
150
|
-
}, 200);
|
|
151
|
-
});
|
|
152
|
-
// Also listen for SIGHUP for manual reload
|
|
153
|
-
const sighupHandler = () => {
|
|
154
|
-
const reloaded = loadTokens(tokensPath);
|
|
155
|
-
onReload(reloaded);
|
|
156
|
-
};
|
|
157
|
-
process.on("SIGHUP", sighupHandler);
|
|
158
|
-
return () => {
|
|
159
|
-
if (debounceTimer)
|
|
160
|
-
clearTimeout(debounceTimer);
|
|
161
|
-
if (watcher)
|
|
162
|
-
watcher.close();
|
|
163
|
-
process.off("SIGHUP", sighupHandler);
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
catch {
|
|
167
|
-
// If watching fails (e.g., NFS), return no-op unsubscribe
|
|
168
|
-
return () => { };
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* Update lastUsedAt for a token (debounced to avoid disk thrash).
|
|
173
|
-
* Fire-and-forget — never blocks the caller.
|
|
174
|
-
*/
|
|
175
|
-
const lastUsedTimers = new Map();
|
|
176
|
-
export function touchLastUsed(tokensPath, identifier) {
|
|
177
|
-
const now = Date.now();
|
|
178
|
-
const lastTouch = lastUsedTimers.get(identifier) ?? 0;
|
|
179
|
-
if (now - lastTouch < LAST_USED_DEBOUNCE_MS)
|
|
180
|
-
return;
|
|
181
|
-
lastUsedTimers.set(identifier, now);
|
|
182
|
-
// Fire-and-forget async disk update
|
|
183
|
-
void (async () => {
|
|
184
|
-
try {
|
|
185
|
-
const tokens = loadTokens(tokensPath);
|
|
186
|
-
const stored = tokens.get(identifier);
|
|
187
|
-
if (stored) {
|
|
188
|
-
stored.lastUsedAt = new Date().toISOString();
|
|
189
|
-
saveTokens(tokensPath, tokens);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
catch {
|
|
193
|
-
// Best-effort — don't crash on disk errors
|
|
194
|
-
}
|
|
195
|
-
})();
|
|
196
|
-
}
|
|
197
|
-
/** Get the default tokens file path. */
|
|
198
|
-
export function defaultTokensPath() {
|
|
199
|
-
const configDir = process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), ".claude");
|
|
200
|
-
return path.join(configDir, "ide", "tokens.json");
|
|
201
|
-
}
|
|
202
|
-
//# sourceMappingURL=teammateTokens.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"teammateTokens.js","sourceRoot":"","sources":["../src/teammateTokens.ts"],"names":[],"mappings":"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"}
|