claude-all-hands 1.0.6 → 1.0.7

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.
@@ -21,6 +21,15 @@ envoy <group> --help
21
21
  | `tavily extract` | Extract full content from URLs |
22
22
  | `xai search` | X/Twitter search for community opinions, alternatives, discussions |
23
23
 
24
+ ### Context7 (External Documentation)
25
+
26
+ | Tool | Use Case |
27
+ |------|----------|
28
+ | `context7 search` | Find library by name, returns IDs for context command |
29
+ | `context7 context` | Get documentation for known library (use search first) |
30
+
31
+ *Flow: search → get library ID → context with query*
32
+
24
33
  ### Vertex (Gemini)
25
34
 
26
35
  | Tool | Use Case |
@@ -44,6 +53,7 @@ envoy <group> --help
44
53
  - Pre-synthesized findings → `perplexity research`
45
54
  - Raw sources for processing → `tavily search` → `tavily extract`
46
55
  - Community opinions/alternatives → `xai search` (can build on previous findings with `--context`)
56
+ - Library documentation → `context7 search <lib>` → `context7 context <id> <query>`
47
57
 
48
58
  **Vertex:**
49
59
  - Arbitrary Gemini query → `vertex ask`
@@ -63,6 +73,7 @@ These tools read files directly and pass to external LLMs. Claude only receives
63
73
  | `TAVILY_API_KEY` | tavily | Tavily API key |
64
74
  | `VERTEX_API_KEY` | vertex | Google AI API key (Vertex Express) |
65
75
  | `X_AI_API_KEY` | xai | xAI Grok API key |
76
+ | `CONTEXT7_API_KEY` | context7 | Context7 API key (upstash.com) |
66
77
  | `ENVOY_TIMEOUT_MS` | optional | Global timeout (default: 120000) |
67
78
 
68
79
  ## Discovery
@@ -9,6 +9,7 @@
9
9
  "version": "0.1.0",
10
10
  "dependencies": {
11
11
  "@google/genai": "^0.14.0",
12
+ "@upstash/context7-sdk": "^0.3.0",
12
13
  "@visheratin/tokenizers-node": "0.1.5",
13
14
  "@visheratin/web-ai-node": "^1.4.5",
14
15
  "chokidar": "^5.0.0",
@@ -522,6 +523,12 @@
522
523
  "pino": "*"
523
524
  }
524
525
  },
526
+ "node_modules/@upstash/context7-sdk": {
527
+ "version": "0.3.0",
528
+ "resolved": "https://registry.npmjs.org/@upstash/context7-sdk/-/context7-sdk-0.3.0.tgz",
529
+ "integrity": "sha512-kW5UV49mG9hh30sWP7nLq0mF7YHbTtfWrnm1VsT0UFW8mR6ovlYp7anobUh5qOaewSzraq9o2QyY77KVpI1twg==",
530
+ "license": "MIT"
531
+ },
525
532
  "node_modules/@visheratin/tokenizers-node": {
526
533
  "version": "0.1.5",
527
534
  "resolved": "https://registry.npmjs.org/@visheratin/tokenizers-node/-/tokenizers-node-0.1.5.tgz",
@@ -12,6 +12,7 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "@google/genai": "^0.14.0",
15
+ "@upstash/context7-sdk": "^0.3.0",
15
16
  "@visheratin/tokenizers-node": "0.1.5",
16
17
  "@visheratin/web-ai-node": "^1.4.5",
17
18
  "chokidar": "^5.0.0",
@@ -30,6 +30,7 @@ async function getInfo(
30
30
  TAVILY_API_KEY: process.env.TAVILY_API_KEY ? "set" : "missing",
31
31
  VERTEX_API_KEY: process.env.VERTEX_API_KEY ? "set" : "missing",
32
32
  X_AI_API_KEY: process.env.X_AI_API_KEY ? "set" : "missing",
33
+ CONTEXT7_API_KEY: process.env.CONTEXT7_API_KEY ? "set" : "missing",
33
34
  },
34
35
  timeout_ms: process.env.ENVOY_TIMEOUT_MS ?? "120000",
35
36
  },
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Context7 API commands - library documentation search and context retrieval.
3
+ *
4
+ * Flow: search (find library) → context (get docs for known library)
5
+ */
6
+
7
+ import { Command } from "commander";
8
+ import { BaseCommand, type CommandResult } from "./base.js";
9
+ import { Context7, Context7Error, type Library } from "@upstash/context7-sdk";
10
+
11
+ /** Shared base for Context7 commands - DRY for auth + error handling */
12
+ abstract class Context7BaseCommand extends BaseCommand {
13
+ protected requireApiKey(): CommandResult | Context7 {
14
+ const apiKey = process.env.CONTEXT7_API_KEY;
15
+ if (!apiKey) {
16
+ return this.error("auth_error", "CONTEXT7_API_KEY not set");
17
+ }
18
+ return new Context7({ apiKey });
19
+ }
20
+
21
+ protected async withTimeout<T>(fn: () => Promise<T>): Promise<[T, number]> {
22
+ const start = performance.now();
23
+ const timeout = new Promise<never>((_, reject) =>
24
+ setTimeout(() => reject(new Error("timeout")), this.timeoutMs)
25
+ );
26
+ const result = await Promise.race([fn(), timeout]);
27
+ return [result, Math.round(performance.now() - start)];
28
+ }
29
+
30
+ protected handleError(e: unknown, extraHint?: string): CommandResult {
31
+ if (e instanceof Context7Error) {
32
+ return this.error("api_error", e.message, extraHint);
33
+ }
34
+ if (e instanceof Error && e.message.includes("timeout")) {
35
+ return this.error("timeout", `Request timed out after ${this.timeoutMs}ms`);
36
+ }
37
+ return this.error("api_error", e instanceof Error ? e.message : String(e));
38
+ }
39
+ }
40
+
41
+ class Context7SearchCommand extends Context7BaseCommand {
42
+ readonly name = "search";
43
+ readonly description = "Search for libraries by name, returns IDs for context command";
44
+
45
+ defineArguments(cmd: Command): void {
46
+ cmd
47
+ .argument("<library>", "Library name to search (e.g., react, fastify)")
48
+ .argument("[query]", "Optional query for relevance ranking")
49
+ .option("--limit <n>", "Max results (default: 5)", parseInt);
50
+ }
51
+
52
+ async execute(args: Record<string, unknown>): Promise<CommandResult> {
53
+ const clientOrError = this.requireApiKey();
54
+ if ("status" in clientOrError) return clientOrError;
55
+
56
+ const library = args.library as string;
57
+ const query = (args.query as string) ?? `How to use ${library}`;
58
+ const limit = (args.limit as number) ?? 5;
59
+
60
+ try {
61
+ const [libraries, durationMs] = await this.withTimeout(() =>
62
+ clientOrError.searchLibrary(query, library)
63
+ );
64
+
65
+ if (!Array.isArray(libraries)) {
66
+ return this.error("api_error", "Unexpected response format from Context7");
67
+ }
68
+
69
+ const results = libraries.slice(0, limit).map((lib: Library) => ({
70
+ id: lib.id, // Required for context command
71
+ name: lib.name,
72
+ description: lib.description,
73
+ snippets: lib.totalSnippets,
74
+ trust: lib.trustScore,
75
+ }));
76
+
77
+ return this.success(
78
+ {
79
+ query: library,
80
+ results,
81
+ usage: results.length > 0
82
+ ? `Use: envoy context7 context "${results[0].id}" "your question"`
83
+ : undefined,
84
+ ...(results.length === 0 && {
85
+ suggestion: "Library not found. Try different search term or library may not be indexed.",
86
+ }),
87
+ },
88
+ {
89
+ result_count: results.length,
90
+ command: "context7 search",
91
+ duration_ms: durationMs,
92
+ }
93
+ );
94
+ } catch (e) {
95
+ return this.handleError(e);
96
+ }
97
+ }
98
+ }
99
+
100
+ class Context7ContextCommand extends Context7BaseCommand {
101
+ readonly name = "context";
102
+ readonly description = "Get documentation context for a known library (use search first)";
103
+
104
+ defineArguments(cmd: Command): void {
105
+ cmd
106
+ .argument("<libraryId>", "Library ID from search (e.g., /facebook/react)")
107
+ .argument("<query>", "What you need docs for (e.g., 'hooks usage')")
108
+ .option("--text", "Return plain text instead of JSON (better for direct LLM use)");
109
+ }
110
+
111
+ async execute(args: Record<string, unknown>): Promise<CommandResult> {
112
+ const clientOrError = this.requireApiKey();
113
+ if ("status" in clientOrError) return clientOrError;
114
+
115
+ const libraryId = args.libraryId as string;
116
+ const query = args.query as string;
117
+ const useText = args.text as boolean;
118
+
119
+ try {
120
+ if (useText) {
121
+ // Plain text mode - directly usable in LLM prompts
122
+ const [content, durationMs] = await this.withTimeout(() =>
123
+ clientOrError.getContext(query, libraryId, { type: "txt" })
124
+ );
125
+
126
+ return this.success(
127
+ {
128
+ library: libraryId,
129
+ query,
130
+ content,
131
+ },
132
+ {
133
+ format: "text",
134
+ command: "context7 context",
135
+ duration_ms: durationMs,
136
+ }
137
+ );
138
+ }
139
+
140
+ // JSON mode - structured docs
141
+ const [docs, durationMs] = await this.withTimeout(() =>
142
+ clientOrError.getContext(query, libraryId, { type: "json" })
143
+ );
144
+
145
+ if (!Array.isArray(docs)) {
146
+ return this.error("api_error", "Unexpected response format from Context7");
147
+ }
148
+
149
+ const documentation = docs.map((doc) => ({
150
+ title: doc.title,
151
+ content: doc.content,
152
+ source: doc.source,
153
+ }));
154
+
155
+ return this.success(
156
+ {
157
+ library: libraryId,
158
+ query,
159
+ docs: documentation,
160
+ },
161
+ {
162
+ doc_count: documentation.length,
163
+ command: "context7 context",
164
+ duration_ms: durationMs,
165
+ }
166
+ );
167
+ } catch (e) {
168
+ return this.handleError(e, "Ensure libraryId is valid (from search results)");
169
+ }
170
+ }
171
+ }
172
+
173
+ export const COMMANDS = {
174
+ search: Context7SearchCommand,
175
+ context: Context7ContextCommand,
176
+ };
@@ -1,10 +1,10 @@
1
1
  ---
2
2
  name: research-tools
3
- description: External research via envoy commands. Use for "search the web", "research [topic]", "extract URL content", "find sources". Provides Tavily (search/extract), Perplexity (deep research), Grok (X/Twitter). Curator/researcher agents only.
3
+ description: Use for research needs. IE "search the web", "research [topic]", "extract URL content", "find sources". Provides Tavily (search/extract), Perplexity (deep research), Grok (X/Twitter).
4
4
  ---
5
5
 
6
6
  <objective>
7
- External research capability for curator/researcher agents. Web search, deep research with citations, and real-time social signals via envoy commands.
7
+ External research capability for agents. Web search, deep research with citations, and real-time social signals via envoy commands.
8
8
  </objective>
9
9
 
10
10
  <quick_start>
@@ -17,6 +17,14 @@ envoy tavily search "query"
17
17
 
18
18
  # Extract URL content
19
19
  envoy tavily extract "url1" "url2"
20
+
21
+ # Library documentation search (Context7)
22
+ envoy context7 search "react"
23
+ envoy context7 search "fastify" "middleware patterns"
24
+
25
+ # Get library docs for known library (Context7)
26
+ envoy context7 context "/facebook/react" "hooks usage"
27
+ envoy context7 context "/fastify/fastify" "routing" --text
20
28
  ```
21
29
  </quick_start>
22
30
 
@@ -25,6 +33,7 @@ envoy tavily extract "url1" "url2"
25
33
  - GitHub content: use `gh` CLI instead of extract
26
34
  - All commands return JSON - parse `data.content` or `data.results`
27
35
  - Use TODAY's date for time-sensitive queries: `date +%Y-%m-%d`
36
+ - Context7 requires search → context flow (search gives libraryId for context)
28
37
  </constraints>
29
38
 
30
39
  <workflow>
@@ -35,6 +44,7 @@ Clarify: What to learn? What for? Depth needed?
35
44
  <step name="choose_tool">
36
45
  | Need | Tool | Cost |
37
46
  |------|------|------|
47
+ | Library docs (known library) | `context7 search` → `context7 context` | Low |
38
48
  | Broad question, synthesis | `perplexity research` | High |
39
49
  | Synthesis + real-time validation | `perplexity research --grok-challenge` | Higher |
40
50
  | X/Twitter community insights | `xai search` | Medium |
@@ -50,6 +60,12 @@ All tools return JSON. Parse `data.content` or `data.results` for findings.
50
60
  <examples>
51
61
  <command_reference>
52
62
  ```bash
63
+ # Context7 (library documentation)
64
+ envoy context7 search "react" # Find react libraries
65
+ envoy context7 search "fastify" "middleware handling" # Search with query context
66
+ envoy context7 context "/facebook/react" "hooks" # Get docs (JSON)
67
+ envoy context7 context "/facebook/react" "hooks" --text # Get docs (plain text)
68
+
53
69
  # Perplexity (deep research)
54
70
  envoy perplexity research "query"
55
71
  envoy perplexity research "query" --grok-challenge
@@ -72,13 +88,36 @@ gh issue view {number} --repo {owner}/{repo}
72
88
  <decision_tree>
73
89
  ```
74
90
  Need information?
91
+ ├─ How does library X work? → context7 search "X" → context7 context "<id>" "question"
92
+ ├─ Library docs for codebase dependency? → context7 search → context7 context
75
93
  ├─ Know exact URL? → tavily extract
76
94
  ├─ Need to find sources? → tavily search → extract promising URLs
77
95
  ├─ Tech research for planning? → perplexity research --grok-challenge
96
+ ├─ Implementation patterns/best practices? → perplexity research
78
97
  └─ Quick answer, no validation? → perplexity research
79
98
  ```
80
99
  </decision_tree>
81
100
 
101
+ <context7_flow>
102
+ Context7 is for library/package documentation. Two-step flow:
103
+
104
+ 1. **Search**: Find the library and get its ID
105
+ ```bash
106
+ envoy context7 search "react"
107
+ # Returns: { results: [{ id: "/facebook/react", name: "React", ... }] }
108
+ ```
109
+
110
+ 2. **Context**: Get docs for specific questions using the ID
111
+ ```bash
112
+ envoy context7 context "/facebook/react" "useState and useEffect"
113
+ # Returns: { docs: [{ title, content, source }] }
114
+ ```
115
+
116
+ **Tips for minimal context usage:**
117
+ - Use `--text` for direct LLM consumption (no JSON parsing)
118
+ - Be specific in query to get relevant docs only
119
+ </context7_flow>
120
+
82
121
  <output_format>
83
122
  ```markdown
84
123
  ## Research: [Topic]
@@ -100,10 +139,13 @@ Actions based on findings.
100
139
  - Skipping scope clarification before research
101
140
  - Not parsing JSON response properly
102
141
  - Using from non-curator/researcher agents
142
+ - Calling context7 context without searching first (need libraryId)
143
+ - Using context7 for non-library questions (use perplexity instead)
103
144
  </anti_patterns>
104
145
 
105
146
  <success_criteria>
106
147
  - JSON response: `status: success` with `data` containing findings
107
148
  - Sources/citations included for synthesis queries
108
149
  - Content extracted for known URLs
150
+ - Context7: Valid libraryId used in context command
109
151
  </success_criteria>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-all-hands",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "description": "CLI for syncing Claude agent configurations to all-hands repository",
5
5
  "type": "module",
6
6
  "bin": {