agent-manifest 3.2.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Ayobami Adefolalu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,204 @@
1
+ # agentjson
2
+
3
+ A universal CLI compiler that scans any web app codebase and generates a `public/agent.json` manifest — so AI agents can discover and interact with your app without custom integration work.
4
+
5
+ Works with Next.js (App Router + Pages Router), Express, Hono, Fastify, and any TypeScript/JavaScript project with smart contracts.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ # Run once, no install
11
+ npx agent-manifest
12
+
13
+ # Or install globally
14
+ npm install -g agent-manifest
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ```bash
20
+ # Scan current directory, output to public/agent.json
21
+ agentjson
22
+
23
+ # Specify project path and output
24
+ agentjson -p ./my-app -o ./public/agent.json
25
+
26
+ # With auth metadata
27
+ agentjson --auth-type bearer --auth-header Authorization --auth-docs https://myapp.xyz/docs/auth
28
+
29
+ # Add author / URL to manifest
30
+ agentjson --author "0xDev" --url https://myapp.xyz
31
+
32
+ # Validate an existing agent.json
33
+ agentjson validate ./public/agent.json
34
+ ```
35
+
36
+ ## What gets generated
37
+
38
+ ```json
39
+ {
40
+ "name": "FlipIt",
41
+ "description": "On-chain coin flip game",
42
+ "version": "1.0.0",
43
+ "author": "0xDev",
44
+ "url": "https://flipit.xyz",
45
+ "auth": { "type": "farcaster-frame" },
46
+ "capabilities": ["wallet", "payments"],
47
+ "actions": [
48
+ {
49
+ "name": "flip",
50
+ "description": "Flip a coin and bet ETH",
51
+ "intent": "game.play",
52
+ "type": "contract",
53
+ "location": "./src/abis/FlipABI.json",
54
+ "abiFunction": "flip",
55
+ "chainId": 8453,
56
+ "contractAddress": { "$env": "NEXT_PUBLIC_FLIP_ADDRESS" },
57
+ "safety": "financial",
58
+ "agentSafe": false,
59
+ "requiredAuth": { "required": "farcaster-signed" },
60
+ "inputs": {
61
+ "choice": { "type": "string", "enum": ["heads", "tails"], "required": true },
62
+ "amount": { "type": "number", "required": true }
63
+ },
64
+ "outputs": { "type": "void" }
65
+ }
66
+ ],
67
+ "metadata": {}
68
+ }
69
+ ```
70
+
71
+ ## Automatic detection
72
+
73
+ ### API routes
74
+ - **Next.js App Router** — `app/api/**/route.ts` (GET, POST, PUT, DELETE, PATCH)
75
+ - **Next.js Pages Router** — `pages/api/**/*.ts`
76
+ - **Express / Hono / Fastify** — `app.get('/path', handler)` and `router.post(...)` patterns
77
+ - **Server Actions** — `'use server'` files
78
+
79
+ ### Smart contracts
80
+ - ABI JSON files (`*ABI.json`, `abi/*.json`, `abis/*.json`)
81
+ - Wagmi hooks — `useWriteContract`, `useContractWrite`, `writeContract`
82
+ - Contract addresses extracted as `{ "$env": "VAR_NAME" }` — secrets never embedded
83
+
84
+ ### Zod schemas
85
+ - Inline `z.object(...)` schemas in the same file as `.parse()` / `.safeParse()`
86
+ - **Cross-file** — schemas imported from centralised files (e.g. `src/lib/schemas.ts`) are resolved via the import graph
87
+
88
+ ### Auth
89
+ - Detected from source code and `package.json` dependencies:
90
+ `bearer` · `api-key` · `oauth2` · `basic` · `farcaster-frame` · `cookie`
91
+ - Override with `--auth-type` if detection misses
92
+
93
+ ### Capabilities
94
+ `wallet` · `payments` · `ai` · `database` · `realtime` · `storage` · `farcaster`
95
+
96
+ ---
97
+
98
+ ## Safety levels
99
+
100
+ Every action is classified automatically:
101
+
102
+ | Level | Meaning | `agentSafe` |
103
+ |---|---|---|
104
+ | `read` | Read-only, no side effects | `true` |
105
+ | `write` | Mutates state, no money movement | `true` |
106
+ | `financial` | Moves tokens or value | `false` |
107
+ | `destructive` | Deletes or burns irreversibly | `false` |
108
+ | `confidential` | Handles PII, passwords, credentials, KYC | `false` |
109
+
110
+ `agentSafe: false` means the agent must ask for human confirmation before executing.
111
+
112
+ ---
113
+
114
+ ## Intent taxonomy
115
+
116
+ Actions get a `domain.verb` intent so agents understand what they do:
117
+
118
+ | Domain | Examples |
119
+ |---|---|
120
+ | `game.*` | `game.play`, `game.join`, `game.score` |
121
+ | `finance.*` | `finance.transfer`, `finance.swap`, `finance.stake`, `finance.approve` |
122
+ | `nft.*` | `nft.mint`, `nft.burn`, `nft.list` |
123
+ | `social.*` | `social.cast`, `social.follow`, `social.react`, `social.share` |
124
+ | `governance.*` | `governance.vote`, `governance.propose`, `governance.delegate` |
125
+ | `auth.*` | `auth.session`, `auth.register`, `auth.verify` |
126
+ | `data.*` | `data.read`, `data.create`, `data.update`, `data.delete` |
127
+ | `media.*` | `media.upload` |
128
+
129
+ Override with a JSDoc tag: `@agent-action intent=custom.thing`
130
+
131
+ ---
132
+
133
+ ## Explicit annotation (optional)
134
+
135
+ The compiler discovers actions automatically, but you can annotate for precision:
136
+
137
+ ```typescript
138
+ /**
139
+ * @agent-action intent=game.play
140
+ * @description Flip a coin and bet ETH on the outcome.
141
+ * @param choice The side to bet on — "heads" or "tails".
142
+ * @param amount The amount of ETH to wager in wei.
143
+ */
144
+ export async function flip(choice: string, amount: bigint) {
145
+ // ...
146
+ }
147
+ ```
148
+
149
+ ---
150
+
151
+ ## Auth scopes
152
+
153
+ Per-action auth is inferred automatically:
154
+
155
+ | Condition | `requiredAuth` |
156
+ |---|---|
157
+ | Contract `view`/`pure` function | `public` |
158
+ | GET endpoint on public app | `public` |
159
+ | Farcaster frame app + write action | `farcaster-signed` |
160
+ | Financial action | `required` + scope `payments:write` |
161
+ | Confidential action (POST) | `required` + scope `pii:write` |
162
+ | Confidential action (GET) | `required` + scope `pii:read` |
163
+ | Everything else | `required` |
164
+
165
+ ---
166
+
167
+ ## CLI options
168
+
169
+ ```
170
+ agentjson [options]
171
+
172
+ Options:
173
+ -p, --path <path> Project root (default: ".")
174
+ -o, --output <output> Output path (default: "./public/agent.json")
175
+ --author <author> Author name or organization
176
+ --url <url> App homepage URL
177
+ --auth-type <type> Override detected auth type
178
+ none | bearer | api-key | oauth2 | basic | farcaster-frame | cookie
179
+ --auth-header <header> Auth header name (default: Authorization)
180
+ --auth-docs <url> URL where agents can obtain credentials
181
+ -V, --version Show version
182
+ -h, --help Show help
183
+
184
+ Commands:
185
+ validate <file> Validate an existing agent.json against the schema
186
+ ```
187
+
188
+ ---
189
+
190
+ ## JSON Schema
191
+
192
+ A full JSON Schema is bundled at `node_modules/@0xdeve/agentjson/schema/agent.schema.json` for editor autocomplete and CI validation.
193
+
194
+ ---
195
+
196
+ ## Performance
197
+
198
+ On large repos the compiler skips unchanged files using SHA-1 content hashing. Cache is stored in `.agentjson-cache.json` at the project root (add to `.gitignore`).
199
+
200
+ ---
201
+
202
+ ## License
203
+
204
+ ISC
package/dist/cli.js ADDED
@@ -0,0 +1,174 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ const commander_1 = require("commander");
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const index_1 = require("./index");
41
+ const program = new commander_1.Command();
42
+ // ─── compile ─────────────────────────────────────────────────────────────────
43
+ program
44
+ .name('agentjson')
45
+ .description('Universal agent manifest compiler — generates agent.json for any web app')
46
+ .version('3.1.0')
47
+ .option('-p, --path <path>', 'path to the project root', '.')
48
+ .option('-o, --output <output>', 'output path for agent.json', './public/agent.json')
49
+ .option('--author <author>', 'author name or organization')
50
+ .option('--url <url>', 'app homepage URL')
51
+ .option('--auth-type <type>', 'override detected auth type: none | bearer | api-key | oauth2 | basic | farcaster-frame | cookie')
52
+ .option('--auth-header <header>', 'auth header name (default: Authorization)')
53
+ .option('--auth-docs <url>', 'URL where agents can obtain credentials')
54
+ .action(async (options) => {
55
+ const projectPath = path.resolve(options.path);
56
+ const outputPath = path.resolve(options.output);
57
+ console.log(`🚀 Scanning project at: ${projectPath}`);
58
+ const discovery = new index_1.DiscoveryService(projectPath);
59
+ const files = await discovery.findRelevantFiles();
60
+ console.log(`🔍 Found ${files.length} relevant files.`);
61
+ const tsParser = new index_1.TSParser(projectPath);
62
+ const expressParser = new index_1.ExpressParser(tsParser.getProject());
63
+ const actions = [];
64
+ for (const file of files) {
65
+ console.log(`📄 Parsing: ${path.relative(projectPath, file)}`);
66
+ const fileActions = await tsParser.parseFile(file);
67
+ actions.push(...fileActions);
68
+ if (file.endsWith('.ts') || file.endsWith('.js')) {
69
+ try {
70
+ const content = fs.readFileSync(file, 'utf8');
71
+ if ((0, index_1.looksLikeRouteFile)(content)) {
72
+ const expressActions = await expressParser.parseFile(file, projectPath);
73
+ actions.push(...expressActions);
74
+ }
75
+ }
76
+ catch { /* ignore */ }
77
+ }
78
+ }
79
+ console.log(`✨ Detected ${actions.length} agent actions.`);
80
+ const uniqueActions = new Map();
81
+ for (const action of actions) {
82
+ const existing = uniqueActions.get(action.name);
83
+ if (!existing || Object.keys(action.inputs).length > Object.keys(existing.inputs).length) {
84
+ uniqueActions.set(action.name, action);
85
+ }
86
+ }
87
+ const appMetadata = tsParser.getAppMetadata();
88
+ if (options.author)
89
+ appMetadata.author = options.author;
90
+ if (options.url)
91
+ appMetadata.url = options.url;
92
+ const detectedAuth = tsParser.getAuth();
93
+ const auth = {
94
+ ...detectedAuth,
95
+ ...(options.authType && { type: options.authType }),
96
+ ...(options.authHeader && { header: options.authHeader }),
97
+ ...(options.authDocs && { docsUrl: options.authDocs }),
98
+ };
99
+ const generator = new index_1.ManifestGenerator();
100
+ const manifest = generator.generate(Array.from(uniqueActions.values()), appMetadata, tsParser.getCapabilities(), auth);
101
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
102
+ fs.writeFileSync(outputPath, JSON.stringify(manifest, null, 2));
103
+ console.log(`✅ agent.json generated at: ${outputPath}`);
104
+ console.log(` ${uniqueActions.size} actions · ${manifest.capabilities.length} capabilities · auth: ${auth.type}`);
105
+ });
106
+ // ─── validate ────────────────────────────────────────────────────────────────
107
+ program
108
+ .command('validate [file]')
109
+ .description('Validate an agent.json manifest against the schema')
110
+ .action((file = './public/agent.json') => {
111
+ const manifestPath = path.resolve(file);
112
+ if (!fs.existsSync(manifestPath)) {
113
+ console.error(`❌ File not found: ${manifestPath}`);
114
+ process.exit(1);
115
+ }
116
+ let manifest;
117
+ try {
118
+ manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
119
+ }
120
+ catch {
121
+ console.error(`❌ Invalid JSON in: ${manifestPath}`);
122
+ process.exit(1);
123
+ }
124
+ const errors = validateManifest(manifest);
125
+ if (errors.length === 0) {
126
+ console.log(`✅ ${manifestPath} is valid`);
127
+ console.log(` ${manifest.actions.length} actions · ${manifest.capabilities.length} capabilities · auth: ${manifest.auth.type}`);
128
+ }
129
+ else {
130
+ console.error(`❌ Validation failed (${errors.length} error${errors.length > 1 ? 's' : ''}):`);
131
+ for (const err of errors)
132
+ console.error(` • ${err}`);
133
+ process.exit(1);
134
+ }
135
+ });
136
+ // ─── Structural validator ────────────────────────────────────────────────────
137
+ const SAFETY_LEVELS = new Set(['read', 'write', 'financial', 'destructive', 'confidential']);
138
+ const ACTION_TYPES = new Set(['api', 'contract', 'function']);
139
+ const AUTH_TYPES = new Set(['none', 'bearer', 'api-key', 'oauth2', 'basic', 'farcaster-frame', 'cookie']);
140
+ const INTENT_RE = /^[a-z][a-z0-9]*\.[a-z][a-z0-9]*$/;
141
+ function validateManifest(m) {
142
+ const errors = [];
143
+ if (typeof m.name !== 'string' || !m.name)
144
+ errors.push('`name` must be a non-empty string');
145
+ if (typeof m.version !== 'string' || !/^\d+\.\d+\.\d+$/.test(m.version))
146
+ errors.push('`version` must be a semver string');
147
+ if (!m.auth || !AUTH_TYPES.has(m.auth.type))
148
+ errors.push('`auth.type` must be one of: ' + [...AUTH_TYPES].join(' | '));
149
+ if (!Array.isArray(m.capabilities))
150
+ errors.push('`capabilities` must be an array');
151
+ if (!Array.isArray(m.actions))
152
+ errors.push('`actions` must be an array');
153
+ else {
154
+ m.actions.forEach((action, i) => {
155
+ const prefix = `actions[${i}] ("${action.name ?? '?'}")`;
156
+ if (!action.name)
157
+ errors.push(`${prefix}: missing \`name\``);
158
+ if (!action.intent)
159
+ errors.push(`${prefix}: missing \`intent\``);
160
+ else if (!INTENT_RE.test(action.intent))
161
+ errors.push(`${prefix}: \`intent\` must match domain.verb format`);
162
+ if (!ACTION_TYPES.has(action.type))
163
+ errors.push(`${prefix}: \`type\` must be one of api|contract|function`);
164
+ if (!SAFETY_LEVELS.has(action.safety))
165
+ errors.push(`${prefix}: \`safety\` must be one of read|write|financial|destructive|confidential`);
166
+ if (typeof action.agentSafe !== 'boolean')
167
+ errors.push(`${prefix}: \`agentSafe\` must be a boolean`);
168
+ if (!action.requiredAuth)
169
+ errors.push(`${prefix}: \`requiredAuth\` is missing`);
170
+ });
171
+ }
172
+ return errors;
173
+ }
174
+ program.parse();
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.DiscoveryService = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const crypto = __importStar(require("crypto"));
40
+ const tinyglobby_1 = require("tinyglobby");
41
+ const express_parser_1 = require("../parser/express-parser");
42
+ /** SHA-1 of a file's content — used for change detection caching. */
43
+ function fileHash(filePath) {
44
+ try {
45
+ return crypto.createHash('sha1').update(fs.readFileSync(filePath)).digest('hex');
46
+ }
47
+ catch {
48
+ return '';
49
+ }
50
+ }
51
+ const CACHE_FILE = '.agentjson-cache.json';
52
+ /** Glob negations applied to every pattern to keep node_modules and build artifacts out. */
53
+ const ALWAYS_EXCLUDE = [
54
+ '!**/node_modules/**',
55
+ '!**/.next/**',
56
+ '!**/dist/**',
57
+ '!**/.turbo/**',
58
+ '!**/.cache/**',
59
+ '!**/.git/**',
60
+ '!**/out/**',
61
+ '!**/build/**',
62
+ '!**/.vercel/**',
63
+ // Never scan env files — they may contain secrets
64
+ '!**/.env',
65
+ '!**/.env.*',
66
+ '!**/secrets/**',
67
+ '!**/credentials/**',
68
+ ];
69
+ class DiscoveryService {
70
+ projectPath;
71
+ cache = {};
72
+ cachePath;
73
+ cacheModified = false;
74
+ constructor(projectPath) {
75
+ this.projectPath = projectPath;
76
+ this.cachePath = path.join(projectPath, CACHE_FILE);
77
+ this.loadCache();
78
+ }
79
+ loadCache() {
80
+ try {
81
+ this.cache = JSON.parse(fs.readFileSync(this.cachePath, 'utf8'));
82
+ }
83
+ catch {
84
+ this.cache = {};
85
+ }
86
+ }
87
+ saveCache() {
88
+ if (!this.cacheModified)
89
+ return;
90
+ try {
91
+ fs.writeFileSync(this.cachePath, JSON.stringify(this.cache, null, 2));
92
+ }
93
+ catch { /* ignore */ }
94
+ }
95
+ async findRelevantFiles() {
96
+ const relevantFiles = [];
97
+ // 0. Farcaster manifest (app identity / metadata)
98
+ const manifests = await (0, tinyglobby_1.glob)([
99
+ '.well-known/farcaster.json',
100
+ 'public/.well-known/farcaster.json',
101
+ '**/public/.well-known/farcaster.json',
102
+ ], { cwd: this.projectPath, absolute: true });
103
+ relevantFiles.push(...manifests);
104
+ // 0.5. ABI JSON files (smart contract definitions)
105
+ const abis = await (0, tinyglobby_1.glob)([
106
+ '**/*ABI.json',
107
+ '**/abi/*.json',
108
+ '**/abis/*.json',
109
+ 'contracts/*.json',
110
+ '**/contracts/*.json',
111
+ ...ALWAYS_EXCLUDE,
112
+ ], { cwd: this.projectPath, absolute: true });
113
+ relevantFiles.push(...abis);
114
+ // 1. API routes — support monorepo layouts (apps/*/src/app/api, apps/*/pages/api, etc.)
115
+ const apiRoutes = await (0, tinyglobby_1.glob)([
116
+ // Next.js App Router
117
+ '**/app/api/**/*.{ts,js,tsx,jsx}',
118
+ // Next.js Pages Router
119
+ '**/pages/api/**/*.{ts,js,tsx,jsx}',
120
+ // Generic api/ folder
121
+ '**/api/**/*.{ts,js,tsx,jsx}',
122
+ ...ALWAYS_EXCLUDE,
123
+ ], { cwd: this.projectPath, absolute: true });
124
+ relevantFiles.push(...apiRoutes);
125
+ // 2. Scan all TS/TSX files for signal keywords
126
+ const allTsFiles = await (0, tinyglobby_1.glob)([
127
+ '**/*.{ts,tsx}',
128
+ ...ALWAYS_EXCLUDE,
129
+ ], { cwd: this.projectPath, absolute: true });
130
+ for (const file of allTsFiles) {
131
+ if (relevantFiles.includes(file))
132
+ continue;
133
+ const hash = fileHash(file);
134
+ const cached = this.cache[file];
135
+ // Cache hit: file unchanged, reuse previous relevance decision
136
+ if (cached && cached.hash === hash) {
137
+ if (cached.relevant)
138
+ relevantFiles.push(file);
139
+ continue;
140
+ }
141
+ // Cache miss: read and classify
142
+ const content = fs.readFileSync(file, 'utf8');
143
+ const relevant = content.includes('@agent-action') ||
144
+ content.includes('useWriteContract') ||
145
+ content.includes('useContractWrite') ||
146
+ content.includes('writeContract') ||
147
+ content.includes("'use server'") ||
148
+ content.includes('"use server"') ||
149
+ (0, express_parser_1.looksLikeRouteFile)(content);
150
+ this.cache[file] = { hash, relevant };
151
+ this.cacheModified = true;
152
+ if (relevant)
153
+ relevantFiles.push(file);
154
+ }
155
+ this.saveCache();
156
+ return Array.from(new Set(relevantFiles));
157
+ }
158
+ }
159
+ exports.DiscoveryService = DiscoveryService;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ManifestGenerator = void 0;
4
+ class ManifestGenerator {
5
+ generate(actions, metadata = {}, capabilities = [], auth = { type: 'none' }, version = '1.0.0') {
6
+ return {
7
+ name: metadata.name ?? 'Web App',
8
+ description: metadata.description ?? 'Auto-generated agent manifest',
9
+ version,
10
+ ...(metadata.author && { author: metadata.author }),
11
+ ...(metadata.url && { url: metadata.url }),
12
+ auth,
13
+ metadata: {
14
+ ...(metadata.iconUrl && { iconUrl: metadata.iconUrl }),
15
+ ...(metadata.homeUrl && { homeUrl: metadata.homeUrl }),
16
+ ...(metadata.imageUrl && { imageUrl: metadata.imageUrl }),
17
+ ...(metadata.splashImageUrl && { splashImageUrl: metadata.splashImageUrl }),
18
+ ...(metadata.splashBackgroundColor && { splashBackgroundColor: metadata.splashBackgroundColor }),
19
+ },
20
+ capabilities,
21
+ actions,
22
+ };
23
+ }
24
+ }
25
+ exports.ManifestGenerator = ManifestGenerator;
package/dist/index.js ADDED
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.CapabilityDetector = exports.AuthDetector = exports.ManifestGenerator = exports.ZodExtractor = exports.ContractParser = exports.looksLikeRouteFile = exports.ExpressParser = exports.TSParser = exports.DiscoveryService = void 0;
18
+ __exportStar(require("./types"), exports);
19
+ var service_1 = require("./discovery/service");
20
+ Object.defineProperty(exports, "DiscoveryService", { enumerable: true, get: function () { return service_1.DiscoveryService; } });
21
+ var ts_parser_1 = require("./parser/ts-parser");
22
+ Object.defineProperty(exports, "TSParser", { enumerable: true, get: function () { return ts_parser_1.TSParser; } });
23
+ var express_parser_1 = require("./parser/express-parser");
24
+ Object.defineProperty(exports, "ExpressParser", { enumerable: true, get: function () { return express_parser_1.ExpressParser; } });
25
+ Object.defineProperty(exports, "looksLikeRouteFile", { enumerable: true, get: function () { return express_parser_1.looksLikeRouteFile; } });
26
+ var contract_parser_1 = require("./parser/contract-parser");
27
+ Object.defineProperty(exports, "ContractParser", { enumerable: true, get: function () { return contract_parser_1.ContractParser; } });
28
+ var zod_extractor_1 = require("./parser/zod-extractor");
29
+ Object.defineProperty(exports, "ZodExtractor", { enumerable: true, get: function () { return zod_extractor_1.ZodExtractor; } });
30
+ var json_1 = require("./generator/json");
31
+ Object.defineProperty(exports, "ManifestGenerator", { enumerable: true, get: function () { return json_1.ManifestGenerator; } });
32
+ var auth_detector_1 = require("./parser/auth-detector");
33
+ Object.defineProperty(exports, "AuthDetector", { enumerable: true, get: function () { return auth_detector_1.AuthDetector; } });
34
+ var capability_detector_1 = require("./parser/capability-detector");
35
+ Object.defineProperty(exports, "CapabilityDetector", { enumerable: true, get: function () { return capability_detector_1.CapabilityDetector; } });
36
+ __exportStar(require("./parser/intent-classifier"), exports);