@antodevs/groundtruth 0.1.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/README.md ADDED
@@ -0,0 +1,130 @@
1
+ ![GroundTruth Banner](assets/banner.png)
2
+
3
+ # GroundTruth
4
+
5
+ > Zero-configuration context injection layer for LLM-based coding agents.
6
+
7
+ ![npm](https://img.shields.io/npm/v/groundtruth)
8
+ ![license](https://img.shields.io/npm/l/groundtruth)
9
+ ![node](https://img.shields.io/node/v/groundtruth)
10
+
11
+ ---
12
+
13
+ ## Architecture Overview
14
+
15
+ Current-generation AI coding assistants (Claude Code, Antigravity, Cursor) suffer from deterministic knowledge cutoffs, rendering them ineffective when working with bleeding-edge frameworks (e.g., Svelte 5+, React 19).
16
+
17
+ **GroundTruth** acts as a transparent middleware layer that resolves this by dynamically injecting real-time, stack-specific documentation directly into the agent's context window prior to inference.
18
+
19
+ ---
20
+
21
+ ## Architecture & Operational Mechanics
22
+
23
+ GroundTruth operates in two distinct execution modes depending on the target agent's architecture.
24
+
25
+ ### 1. Proxy Intercept Mode (Designed for `claude-code`)
26
+
27
+ In this mode, GroundTruth provisions a local HTTP proxy that intercepts outbound API calls targeting Anthropic's endpoints.
28
+
29
+ ```mermaid
30
+ sequenceDiagram
31
+ participant Agent as Claude Code
32
+ participant Proxy as GroundTruth Proxy
33
+ participant Search as DuckDuckGo
34
+ participant API as Anthropic API
35
+
36
+ Agent->>Proxy: Send Prompt (POST /v1/messages)
37
+ Proxy->>Search: Extract stack/query & scrape live docs
38
+ Search-->>Proxy: Return real-time web context
39
+ Note over Proxy: Injects live context<br/>into System Prompt
40
+ Proxy->>API: Forward mutated request
41
+ API-->>Agent: Return completion with fresh knowledge
42
+ ```
43
+
44
+ - **Query Extraction**: Parses the user prompt to identify context dependencies.
45
+ - **Data Hydration**: Orchestrates an automated DuckDuckGo search to fetch the most recent documentation. It relies on a deterministic `LRUCache`, TCP keep-alive Pool configurations, and a 429-aware `CircuitBreaker` pattern to safeguard network operations safely.
46
+ - **Payload Mutation**: Mutates the outgoing system prompt to inject the scraped live context before forwarding the request to the Anthropic completion endpoint. (It includes type-guard structures making it safe from undocumented Gemini system changes).
47
+
48
+ ### 2. File Watcher Mode (Designed for `antigravity` / `gemini`)
49
+
50
+ For agents that support side-channel context ingestion via dotfiles (like Antigravity Rules), GroundTruth runs as a background daemon.
51
+
52
+ ```mermaid
53
+ flowchart TD
54
+ pkg([package.json]) -->|Parse Dependencies| GT{GroundTruth Watcher}
55
+ GT -->|Search Stack Queries| DDG[(DuckDuckGo)]
56
+ DDG -->|Return Live Docs| GT
57
+ GT -->|Sync periodically| File[~/.gemini/GEMINI.md]
58
+ File -->|Auto-loaded| Agent(Antigravity Agent)
59
+ Agent -->|Execute| Prompt[Prompt with Fresh Context]
60
+
61
+ classDef core fill:#3B82F6,stroke:#fff,stroke-width:2px,color:#fff;
62
+ class GT,Agent core;
63
+ ```
64
+
65
+ - **Stack Introspection**: Analyzes the local `package.json` to infer the project's dependency graph.
66
+ - **Intelligent Chunking**: Groups the filtered dependencies in configurable size batches (default 3) and uniquely hashes them to avoid redundant context-fetching loops unless changes are detected.
67
+ - **Automated Polling**: Periodically fetches updated documentation for the detected stack chunks in parallel.
68
+ - **State Persistence**: Hashes are serialized persistently avoiding redundant DuckDuckGo scraping operations across application crashes.
69
+ - **Block-Based Synchronization**: Writes the parsed context discretely into hash-oriented blocks inside `~/.gemini/GEMINI.md`. Native POSIX bindings are leveraged ensuring `Atomic Writes`. Stale contexts are efficiently garbage-collected via regex matching over tracked batch hashes.
70
+
71
+ ---
72
+
73
+ ## Installation & Usage
74
+
75
+ ### Usage with Claude Code
76
+ ```bash
77
+ # Initialize GroundTruth in proxy mode (auto-exports ANTHROPIC_BASE_URL)
78
+ npx groundtruth --claude-code
79
+
80
+ # Execute your agent in a separate TTY
81
+ claude
82
+ ```
83
+ > **Note:** The daemon automatically mutates your shell environment (`~/.zshrc`, `~/.bashrc`, `config.fish`) to route traffic through the localhost proxy.
84
+
85
+ ### Usage with Antigravity / Gemini
86
+ ```bash
87
+ cd /workspace/your-project
88
+
89
+ # Initialize the daemon in file watcher mode
90
+ npx groundtruth --antigravity
91
+ ```
92
+ > **Note:** GroundTruth will continuously poll and sync documentation based on your `package.json` manifest.
93
+
94
+ ---
95
+
96
+ ## CLI Reference
97
+
98
+ | Flag | Mode | Technical Description |
99
+ |------|------|-------------|
100
+ | `--claude-code` | Proxy | Initializes HTTP interceptor for Anthropic API payloads. |
101
+ | `--antigravity` | Rules | Initializes background daemon for dotfile synchronization. |
102
+ | `--use-package-json` | Both | Enforces AST/manifest parsing of `package.json` for query generation. |
103
+ | `--port <n>` | Proxy | Overrides default proxy listener port (Default: `8080`). |
104
+ | `--interval <n>` | Rules | Overrides the polling interval for documentation refresh in minutes (Default: `5`). |
105
+ | `--batch-size <n>` | Rules | Changes the amount of dependencies per query chunk for block fetching (Default: `3`, Min: `2`, Max: `5`). |
106
+
107
+ ---
108
+
109
+ ## Benchmark & Comparison
110
+
111
+ GroundTruth is heavily optimized for zero-configuration deployments and minimal token overhead compared to existing MCP (Model Context Protocol) solutions.
112
+
113
+ | Feature | GroundTruth | Brave MCP | Playwright MCP | Firecrawl |
114
+ |---------|-------------|-----------|----------------|-----------|
115
+ | **Authentication** | None Required | API Key | None Required | API Key |
116
+ | **Token Overhead** | ~500 tokens | ~800 tokens | ~13,000 tokens | ~800 tokens |
117
+ | **Antigravity Support** | Native | Unsupported | Unsupported | Unsupported |
118
+ | **Runtime Footprint** | < 1MB | < 1MB | ~200MB | < 1MB |
119
+ | **Shell Auto-config** | Automated | Manual | Manual | Manual |
120
+
121
+ ---
122
+
123
+ ## System Requirements
124
+ - Node.js runtime (v18.0.0 or higher)
125
+ - Supported Agent (Antigravity or Claude Code)
126
+
127
+ ---
128
+
129
+ ## License
130
+ MIT
Binary file
package/index.js ADDED
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @module index
4
+ * @description Entry point runtime groundtruth delegazione CLI o proxy flow logic.
5
+ */
6
+ import { chalk, label } from './src/logger.js';
7
+ import { usePackageJson, antigravityMode, claudeCodeMode, port, intervalMinutes, batchSize, version } from './src/cli.js';
8
+ import { createServer } from './src/proxy.js';
9
+ import { autoSetEnv } from './src/env.js';
10
+ import { startWatcher } from './src/watcher.js';
11
+
12
+ // ─── Dispatcher start app logic ──────────────────────
13
+
14
+ if (antigravityMode) {
15
+ startWatcher({ intervalMinutes, usePackageJson, batchSize });
16
+ } else if (claudeCodeMode) {
17
+ const server = await createServer(usePackageJson);
18
+ const startServer = (p) => {
19
+ // EADDRINUSE fallback listener fail chain ricorsivo su port shift param logic
20
+ server.on('error', (e) => (e.code === 'EADDRINUSE' ? startServer(p + 1) : console.error(chalk.red(`Server error: ${e.message}`))));
21
+ server.listen(p, async () => {
22
+ console.log(`\n ${chalk.white.bold('GroundTruth')} ${chalk.gray(`v${version}`)} ${chalk.gray('[claude-code mode]')}\n`);
23
+ console.log(label('◆', 'proxy', `localhost:${p}`));
24
+ console.log(label('◆', 'anthropic', '/v1/messages'));
25
+ console.log(label('◆', 'gemini', '/v1beta/…'));
26
+ console.log(label('◆', 'context', 'DuckDuckGo → live'));
27
+ console.log(`\n ${chalk.cyan('✻')} Listening. Set ANTHROPIC_BASE_URL=http://localhost:${p}\n`);
28
+ await autoSetEnv(p);
29
+ });
30
+ };
31
+ startServer(port);
32
+ }
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@antodevs/groundtruth",
3
+ "version": "0.1.0",
4
+ "description": "Lightweight Node.js proxy to intercept API requests from coding agents and inject fresh web context",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Anto",
8
+ "keywords": [
9
+ "llm",
10
+ "context",
11
+ "ai",
12
+ "proxy",
13
+ "gemini",
14
+ "anthropic",
15
+ "claude",
16
+ "antigravity",
17
+ "coding-assistant"
18
+ ],
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/anto0102/GroundTruth.git"
22
+ },
23
+ "engines": {
24
+ "node": ">=18.0.0"
25
+ },
26
+ "files": [
27
+ "index.js",
28
+ "src/",
29
+ "assets/",
30
+ "specification.yaml",
31
+ "README.md",
32
+ "LICENSE"
33
+ ],
34
+ "bin": {
35
+ "groundtruth": "index.js"
36
+ },
37
+ "scripts": {
38
+ "start": "node index.js",
39
+ "dev": "node --watch index.js"
40
+ },
41
+ "dependencies": {
42
+ "@mozilla/readability": "^0.5.0",
43
+ "chalk": "^5.3.0",
44
+ "cheerio": "^1.0.0",
45
+ "linkedom": "^0.18.12",
46
+ "node-fetch": "^3.3.2"
47
+ }
48
+ }
@@ -0,0 +1,143 @@
1
+ name: GroundTruth
2
+ version: 0.1.0
3
+ description: |
4
+ GroundTruth is a zero-configuration, transparent middleware context injection layer.
5
+ It is designed to bridge the deterministic knowledge cutoff gap of LLM-based coding agents
6
+ (such as Claude Code or Antigravity) by dynamically fetching and injecting live,
7
+ dependency-specific documentation right before inference or via out-of-band rule files.
8
+
9
+ architecture:
10
+ modes:
11
+ - name: Proxy Intercept Mode
12
+ alias: claude-code
13
+ description: |
14
+ Operates as a local HTTP reverse-proxy interceptor that captures outgoing API payloads
15
+ targeting Anthropic or Google Gemini endpoints, mutating them in transit.
16
+ target_endpoints:
17
+ - "https://api.anthropic.com/v1/messages"
18
+ - "https://generativelanguage.googleapis.com/v1beta/models/*"
19
+ flow:
20
+ 1: "Listen on localhost port (default: 8080) and capture POST requests."
21
+ 2: "Extract the last user message from the JSON body (supports `messages` array for Anthropic and `contents` array for Gemini)."
22
+ 3: "Determine search query: use `--use-package-json` AST parsing, or fallback to the user message text."
23
+ 4: "Scrape DuckDuckGo concurrently to retrieve live context (title, snippet, Readability-parsed text up to 4000 chars)."
24
+ 5: "Mutate the `system` instruction prompt in the JSON payload by appending the live context block."
25
+ 6: "Forward the modified request to the actual LLM provider, streaming the response back to the client."
26
+ components:
27
+ - src/proxy.js
28
+
29
+ - name: File Watcher Mode
30
+ alias: antigravity
31
+ description: |
32
+ Runs as a persistent background daemon. It polls the local project's dependencies,
33
+ fetches up-to-date documentation, and generates synchronized knowledge base dotfiles
34
+ (`GEMINI.md`) that the agent natively reads on invocation.
35
+ flow:
36
+ 1: "Parses `package.json` dependencies and filters out build/tooling packages (e.g., eslint, vite, adapter)."
37
+ 2: "Groups the filtered dependencies into chunks (batching) of configurable size (default: 3, max: 5) using `groupIntoBatches`."
38
+ 3: "Hashes each dependency chunk (`batchHash` md5 sliced to 8 chars) to uniquely identify rule blocks and track state."
39
+ 4: "Checks previous state to avoid redundant network fetches if the batch hasn't changed (`previousDepsKey` mapping)."
40
+ 5: "Fetches live DuckDuckGo results per batch asynchronously, filtering out low-quality pages (403, captcha, < 200 chars)."
41
+ 6: "Injects distinct dependency rule blocks bounded by `<!-- groundtruth:block-{hash}:start/end -->` directly inside `~/.gemini/GEMINI.md` (global) and `./.gemini/GEMINI.md` (workspace)."
42
+ 7: "Garbage-collects stale blocks (`removeStaleBlocks`) belonging to evicted or resolved dependencies by regex matching active block IDs."
43
+ components:
44
+ - src/watcher.js
45
+ - src/inject.js
46
+
47
+ core_modules:
48
+ - name: cli.js
49
+ responsibilities:
50
+ - "Process `process.argv` argument parsing."
51
+ - "Validation and defaulting of arguments (`--port`, `--interval`, `--batch-size`)."
52
+ - "Help/Docs Screen rendering and early exit conditions."
53
+
54
+ - name: search.js
55
+ responsibilities:
56
+ - "DuckDuckGo HTML scraping using `cheerio`."
57
+ - "URL resolution from DuckDuckGo's `uddg` tracking links."
58
+ - "User-Agent rotation to mitigate scraping blocks."
59
+ - "Integration with `CircuitBreaker` pattern for rate-limit protection."
60
+ - "Integration with bounded custom O(1) `LRUCache` from `cache.js`."
61
+ - "Page content extraction using `linkedom` and Mozilla's `Readability`."
62
+ - "Integration with persistent connection pooling components from `http-agent.js`."
63
+
64
+ - name: packages.js
65
+ responsibilities:
66
+ - "Read local Node modules context (`package.json`)."
67
+ - "Clean semantic versions (e.g., `^1.2.3` -> `1.2`)."
68
+ - "Filter out non-informative tooling (`vite`, `prettier`, `eslint`)."
69
+ - "Group dependencies into manageable batches (`groupIntoBatches`)."
70
+ - "Generate deterministic MD5 identifiers per batch for block management (`batchHash`)."
71
+ - "Construct search queries based on dependency batches plus temporal identifiers (`latest 2026`)."
72
+
73
+ - name: logger.js
74
+ responsibilities:
75
+ - "Chalk-driven aesthetic terminal formatting."
76
+ - "Centralized status symbolizing constants (✓, ⚠, ⚡, ↻, ◆, ✻)."
77
+ - "Timestamp generation mapped to `it-IT` locale."
78
+
79
+ - name: env.js
80
+ responsibilities:
81
+ - "Shell configuration auto-instrumentation (`.zshrc`, `.bashrc`, `.bash_profile`, `config.fish`)."
82
+ - "Exporting `ANTHROPIC_BASE_URL` to route CLI tools (like Claude Code) through the proxy."
83
+ - "Cross-Platform Environment Override (Bypassing Windows systems safely)."
84
+
85
+ - name: inject.js
86
+ responsibilities:
87
+ - "File I/O operations for `GEMINI.md` in both `$HOME` and `$CWD`."
88
+ - "Regex-based block injection using exact start/end bounds matching."
89
+ - "Stale block eviction via `removeStaleBlocks`."
90
+ - "Uses `atomicWrite` for zero-corruption file replacements."
91
+
92
+ - name: cache.js
93
+ responsibilities:
94
+ - "Implements zero-dependency O(1) bounded LRU caching logic."
95
+ - "Provides getter/setter mechanisms tied to temporal eviction limits."
96
+
97
+ - name: circuit-breaker.js
98
+ responsibilities:
99
+ - "Manages DuckDuckGo fetch attempts via threshold-based error state wrapping (OPEN/HALF_OPEN/CLOSED)."
100
+
101
+ - name: state.js
102
+ responsibilities:
103
+ - "Persistent recovery system for dependency batch hashes mapping across system crash/restarts."
104
+ - "Reads and writes `.gemini/watcher-state.json`."
105
+
106
+ - name: http-agent.js
107
+ responsibilities:
108
+ - "Creates reusable Keep-Alive HTTP and HTTPS configuration agents to mitigate handshake overheads."
109
+
110
+ - name: utils/atomic-write.js
111
+ responsibilities:
112
+ - "Creates temporary file blocks performing `fs.rename` (POSIX) or falls back to standard `fs.copyFile` safe-copies (Windows)."
113
+
114
+ dependencies:
115
+ runtime: "Node.js >= 18.0.0 (uses ES Modules)"
116
+ built_ins:
117
+ - fs
118
+ - path
119
+ - os
120
+ - http
121
+ - https
122
+ - crypto
123
+ third_party:
124
+ - chalk: "^5.3.0" # Terminal styling
125
+ - cheerio: "^1.0.0" # Fast HTML parsing for DDG results
126
+ - linkedom: "^0.18.5" # Lightweight DOM emulation for Mozilla Readability
127
+ - node-fetch: "^3.3.2" # WHATWG Fetch API polyfill for Node
128
+ - "@mozilla/readability": "^0.5.0" # Main content extraction
129
+
130
+ mechanics:
131
+ caching_and_eviction:
132
+ - "Search level caching: Runtime searches are cached for 5 minutes (`CACHE_TTL`), matching identical queries to avoid redundant network transit."
133
+ - "Watcher level caching: the daemon uses a Map tracking `blockId` -> `JSON.stringify(batch)`. If the hash signature matches across cycles, the network layer is skipped."
134
+ quality_assurance:
135
+ - "Content verification: Extracted text is sanitized and evaluated. If a page returns < 200 characters, or contains indicators of bot protection (e.g., '403', 'captcha', 'access denied'), the result is flagged."
136
+ - "Fallback mechanism: If a result is flagged as low-quality, the watcher rolls back and retains the successfully injected markdown block from the previous cycle."
137
+ network_resilience:
138
+ - "Timeouts: All outbound `node-fetch` requests strictly adhere to a 5-second `AbortSignal.timeout(5000)`."
139
+ - "Retries & Bans: `search.js` relies on a `CircuitBreaker` class mitigating recursive DuckDuckGo IP bans."
140
+ - "Resource Connection: Avoids TCP handshakes through persistent keep-alive Agent dispatching."
141
+ shell_integration:
142
+ - "Darwin/Linux-first: Windows OS (`win32`) skips autoconfig cleanly."
143
+ - "Fish Shell paths uniquely utilize `set -gx` constructs unlike standard Bash/Zsh `export` syntax, appending recursively or mutating existing assignments."
package/src/cache.js ADDED
@@ -0,0 +1,107 @@
1
+ /**
2
+ * @module cache
3
+ * @description Implementazione zero-dep LRU Cache limitata memory bounds.
4
+ */
5
+
6
+ /**
7
+ * @description Store memory con eviction LRU O(1) in get/set.
8
+ */
9
+ class LRUCache {
10
+ /**
11
+ * @param {Object} options - Impostazioni max size e ttl ms
12
+ */
13
+ constructor(options = {}) {
14
+ this.max = options.max || 500;
15
+ this.ttl = options.ttl || 5 * 60 * 1000; // 5 min default TTL
16
+ this.cache = new Map();
17
+ // Doubly-linked list base structure per LRU policy cost O(1)
18
+ this.head = { key: null, next: null, prev: null };
19
+ this.tail = { key: null, next: null, prev: null };
20
+ this.head.next = this.tail;
21
+ this.tail.prev = this.head;
22
+ this.size = 0;
23
+ }
24
+
25
+ _remove(node) {
26
+ node.prev.next = node.next;
27
+ node.next.prev = node.prev;
28
+ }
29
+
30
+ _addToFront(node) {
31
+ node.next = this.head.next;
32
+ node.prev = this.head;
33
+ this.head.next.prev = node;
34
+ this.head.next = node;
35
+ }
36
+
37
+ /**
38
+ * @description Fetch nodo con eviction passiva su scadenza TTL.
39
+ * @param {string} key - Chiave archivio identificativa
40
+ * @returns {any} Valore salvato o undefined su miss
41
+ */
42
+ get(key) {
43
+ const node = this.cache.get(key);
44
+ if (!node) return undefined;
45
+
46
+ // TTL lazy evict check se expiro
47
+ if (Date.now() > node.expiresAt) {
48
+ this.delete(key);
49
+ return undefined;
50
+ }
51
+
52
+ // Promote a recency target node
53
+ this._remove(node);
54
+ this._addToFront(node);
55
+ return node.value;
56
+ }
57
+
58
+ /**
59
+ * @description Assegna un nodo alla testa (recent).
60
+ * @param {string} key - Target key
61
+ * @param {any} value - Target val
62
+ * @returns {LRUCache} Istanza chaining
63
+ */
64
+ set(key, value) {
65
+ // Pulizia pre-insert per sovrascrittura o cap bounds
66
+ if (this.cache.has(key)) {
67
+ const old = this.cache.get(key);
68
+ this._remove(old);
69
+ this.cache.delete(key);
70
+ this.size--;
71
+ } else if (this.size >= this.max) {
72
+ const lru = this.tail.prev;
73
+ if (lru.key) {
74
+ this._remove(lru);
75
+ this.cache.delete(lru.key);
76
+ this.size--;
77
+ }
78
+ }
79
+
80
+ const node = {
81
+ key,
82
+ value,
83
+ expiresAt: Date.now() + this.ttl,
84
+ next: null,
85
+ prev: null
86
+ };
87
+
88
+ this.cache.set(key, node);
89
+ this._addToFront(node);
90
+ this.size++;
91
+ return this;
92
+ }
93
+
94
+ delete(key) {
95
+ const node = this.cache.get(key);
96
+ if (node) {
97
+ this._remove(node);
98
+ this.cache.delete(key);
99
+ this.size--;
100
+ return true;
101
+ }
102
+ return false;
103
+ }
104
+ }
105
+
106
+ // Esporta singola cache istanza module globale (singleton per memory context node)
107
+ export const searchCache = new LRUCache({ max: 500, ttl: 5 * 60 * 1000 });
@@ -0,0 +1,63 @@
1
+ /**
2
+ * @module circuit-breaker
3
+ * @description Fail-fast strategy su DDG in caso di cap HTTP bloccati IP.
4
+ */
5
+
6
+ export class CircuitBreaker {
7
+ /**
8
+ * @param {Object} options Imposta le policies di fault limit e timeout windows.
9
+ */
10
+ constructor(options = {}) {
11
+ this.failureThreshold = options.failureThreshold || 5;
12
+ this.resetTimeout = options.resetTimeout || 60000;
13
+ this.state = 'CLOSED'; // CLOSED, OPEN, HALF_OPEN
14
+ this.failures = 0;
15
+ this.lastFailureTime = null;
16
+ }
17
+
18
+ /**
19
+ * @description Esegue logica async proteggendola da cascading failure DDG
20
+ * @param {Function} fn - Ritorna Promise async operation DDG fetch
21
+ * @returns {Promise<any>} Risultato esecuzione
22
+ * @throws {Error} Fallimento execution o cb open rejection error
23
+ */
24
+ async execute(fn) {
25
+ if (this.state === 'OPEN') {
26
+ if (Date.now() - this.lastFailureTime < this.resetTimeout) {
27
+ throw new Error('Circuit breaker is OPEN');
28
+ }
29
+ // Tentativo check dopo finestra timeout
30
+ this.state = 'HALF_OPEN';
31
+ }
32
+
33
+ try {
34
+ const result = await fn();
35
+ this.onSuccess();
36
+ return result;
37
+ } catch (err) {
38
+ this.onFailure();
39
+ throw err;
40
+ }
41
+ }
42
+
43
+ onSuccess() {
44
+ if (this.state === 'HALF_OPEN') {
45
+ this.halfOpenSuccesses = (this.halfOpenSuccesses || 0) + 1;
46
+ if (this.halfOpenSuccesses >= 2) {
47
+ this.failures = 0;
48
+ this.state = 'CLOSED';
49
+ this.halfOpenSuccesses = 0;
50
+ }
51
+ } else {
52
+ this.failures = 0;
53
+ }
54
+ }
55
+
56
+ onFailure() {
57
+ this.failures++;
58
+ this.lastFailureTime = Date.now();
59
+ if (this.failures >= this.failureThreshold) {
60
+ this.state = 'OPEN';
61
+ }
62
+ }
63
+ }
package/src/cli.js ADDED
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @module cli
3
+ * @description Parsing degli argomenti CLI process.argv e logica help screen.
4
+ */
5
+ import { chalk } from './logger.js';
6
+ import { createRequire } from 'module';
7
+
8
+ const { version } = createRequire(import.meta.url)('../package.json');
9
+
10
+ // ─── Arg Parsers ─────────────────────────────────────
11
+
12
+ const args = process.argv.slice(2);
13
+ const usePackageJson = args.includes('--use-package-json');
14
+ const antigravityMode = args.includes('--antigravity');
15
+ const claudeCodeMode = args.includes('--claude-code');
16
+
17
+ // Stop immediato se nessun mode definito
18
+ if (!antigravityMode && !claudeCodeMode) {
19
+ console.log();
20
+ console.log(` ${chalk.white.bold('GroundTruth')} ${chalk.gray(`v${version}`)}`);
21
+ console.log();
22
+ console.log(` Usage:`);
23
+ console.log(` groundtruth --claude-code proxy mode (Claude Code)`);
24
+ console.log(` groundtruth --antigravity rules mode (Antigravity/Gemini)`);
25
+ console.log();
26
+ console.log(` Options:`);
27
+ console.log(` --use-package-json use package.json as search query`);
28
+ console.log(` --port <n> custom port, default 8080 (claude-code only)`);
29
+ console.log(` --interval <n> refresh in minutes, default 5 (antigravity only)`);
30
+ console.log(` --batch-size <n> deps per search batch (default: 3)`);
31
+ console.log();
32
+ console.log(` Docs:`);
33
+ console.log(` Claude Code → export ANTHROPIC_BASE_URL=http://localhost:8080`);
34
+ console.log(` Antigravity → just run groundtruth --antigravity in your project`);
35
+ console.log();
36
+ process.exit(0);
37
+ }
38
+
39
+ // ─── Default params override ─────────────────────────
40
+
41
+ let port = 8080; // Default Anthropic proxy
42
+ const portArgIndex = args.indexOf('--port');
43
+ if (portArgIndex !== -1 && args[portArgIndex + 1]) {
44
+ port = parseInt(args[portArgIndex + 1], 10);
45
+ }
46
+
47
+ let intervalMinutes = 5; // Default context refresh
48
+ const intervalArgIndex = args.indexOf('--interval');
49
+ if (intervalArgIndex !== -1 && args[intervalArgIndex + 1]) {
50
+ intervalMinutes = parseInt(args[intervalArgIndex + 1], 10) || 5;
51
+ }
52
+
53
+ const batchSizeIndex = args.indexOf('--batch-size');
54
+ const batchSize = batchSizeIndex !== -1
55
+ ? Math.max(2, Math.min(parseInt(args[batchSizeIndex + 1]) || 3, 5))
56
+ : 3;
57
+
58
+ export { args, usePackageJson, antigravityMode, claudeCodeMode, port, intervalMinutes, batchSize, version };