agent-manifest 3.2.0 → 3.3.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.
@@ -0,0 +1,168 @@
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.WebSocketParser = void 0;
37
+ exports.looksLikeWebSocketFile = looksLikeWebSocketFile;
38
+ const ts_morph_1 = require("ts-morph");
39
+ const intent_classifier_1 = require("./intent-classifier");
40
+ const path = __importStar(require("path"));
41
+ /**
42
+ * Parses raw WebSocket servers (the `ws` npm package) and extracts
43
+ * message type handlers as agent actions.
44
+ *
45
+ * Detects:
46
+ * // ws library
47
+ * const wss = new WebSocketServer({ port: 8080 })
48
+ * wss.on('connection', (ws) => {
49
+ * ws.on('message', (data) => {
50
+ * const { type, payload } = JSON.parse(data)
51
+ * if (type === 'ping') { ... }
52
+ * switch (type) { case 'chat': ... }
53
+ * })
54
+ * })
55
+ *
56
+ * When individual message types are discriminated by a `type` / `action`
57
+ * string field, each branch is emitted as a separate action. Otherwise
58
+ * a single `ws_message` action is emitted for the whole handler.
59
+ */
60
+ class WebSocketParser {
61
+ project;
62
+ constructor(sharedProject) {
63
+ this.project = sharedProject ?? new ts_morph_1.Project({
64
+ compilerOptions: { allowJs: true, checkJs: false },
65
+ });
66
+ }
67
+ async parseFile(filePath, projectPath) {
68
+ const sourceFile = this.project.addSourceFileAtPath(filePath);
69
+ const relativePath = './' + path.relative(projectPath, filePath).replace(/\\/g, '/');
70
+ const actions = [];
71
+ const seen = new Set();
72
+ sourceFile.forEachDescendant(node => {
73
+ if (!ts_morph_1.Node.isCallExpression(node))
74
+ return;
75
+ const expr = node.getExpression();
76
+ if (!ts_morph_1.Node.isPropertyAccessExpression(expr))
77
+ return;
78
+ if (expr.getName() !== 'on')
79
+ return;
80
+ const args = node.getArguments();
81
+ if (args.length < 2)
82
+ return;
83
+ const eventArg = args[0];
84
+ if (!ts_morph_1.Node.isStringLiteral(eventArg))
85
+ return;
86
+ if (eventArg.getLiteralValue() !== 'message')
87
+ return;
88
+ const handler = args[1];
89
+ if (!ts_morph_1.Node.isArrowFunction(handler) && !ts_morph_1.Node.isFunctionExpression(handler))
90
+ return;
91
+ // Try to detect discriminated message types inside the handler body
92
+ const messageTypes = this.extractMessageTypes(handler);
93
+ if (messageTypes.length > 0) {
94
+ for (const msgType of messageTypes) {
95
+ if (seen.has(msgType))
96
+ continue;
97
+ seen.add(msgType);
98
+ const safety = (0, intent_classifier_1.classifySafety)({ name: msgType, type: 'socket' });
99
+ actions.push({
100
+ name: msgType,
101
+ description: `WebSocket message type: ${msgType}`,
102
+ intent: (0, intent_classifier_1.inferIntent)(msgType),
103
+ type: 'socket',
104
+ location: relativePath,
105
+ socketEvent: msgType,
106
+ safety,
107
+ agentSafe: (0, intent_classifier_1.deriveAgentSafe)(safety),
108
+ requiredAuth: (0, intent_classifier_1.inferActionAuth)({ safety, type: 'socket' }),
109
+ inputs: { type: { type: 'string', required: true }, payload: { type: 'object', required: false } },
110
+ outputs: { type: 'object' },
111
+ });
112
+ }
113
+ }
114
+ else {
115
+ // Generic message handler — emit a single action
116
+ const name = 'ws_message';
117
+ if (!seen.has(name)) {
118
+ seen.add(name);
119
+ actions.push({
120
+ name,
121
+ description: 'Raw WebSocket message handler',
122
+ intent: 'util.action',
123
+ type: 'socket',
124
+ location: relativePath,
125
+ socketEvent: 'message',
126
+ safety: 'write',
127
+ agentSafe: true,
128
+ requiredAuth: (0, intent_classifier_1.inferActionAuth)({ safety: 'write', type: 'socket' }),
129
+ inputs: { data: { type: 'string', required: true } },
130
+ outputs: { type: 'object' },
131
+ });
132
+ }
133
+ }
134
+ });
135
+ return actions;
136
+ }
137
+ /**
138
+ * Look inside the message handler body for discriminated type patterns:
139
+ * if (type === 'chat') → extracts 'chat'
140
+ * switch (type) { case 'ping': → extracts 'ping'
141
+ * if (msg.type === 'join') → extracts 'join'
142
+ */
143
+ extractMessageTypes(handler) {
144
+ const types = [];
145
+ const body = handler.getBody?.();
146
+ if (!body)
147
+ return types;
148
+ const text = body.getText();
149
+ // switch (type) { case 'value': ... }
150
+ for (const match of text.matchAll(/case\s+['"`]([^'"`]+)['"`]\s*:/g)) {
151
+ types.push(match[1]);
152
+ }
153
+ // if (type === 'value') or if (msg.type === 'value')
154
+ for (const match of text.matchAll(/(?:type|action|event)\s*(?:===?|==)\s*['"`]([^'"`]+)['"`]/g)) {
155
+ if (!types.includes(match[1]))
156
+ types.push(match[1]);
157
+ }
158
+ // Filter out framework noise
159
+ return types.filter(t => t !== 'message' && t !== 'error' && t !== 'close' && t !== 'open');
160
+ }
161
+ }
162
+ exports.WebSocketParser = WebSocketParser;
163
+ function looksLikeWebSocketFile(content) {
164
+ return (content.includes('WebSocketServer') ||
165
+ content.includes('new WebSocket.Server') ||
166
+ (content.includes("'ws'") && content.includes(".on('message'")) ||
167
+ (content.includes('"ws"') && content.includes('.on("message"')));
168
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-manifest",
3
- "version": "3.2.0",
3
+ "version": "3.3.0",
4
4
  "description": "Universal agent manifest compiler — generates agent.json for any web app so AI agents can discover and interact with it",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -100,7 +100,7 @@
100
100
  },
101
101
  "type": {
102
102
  "type": "string",
103
- "enum": ["api", "contract", "function"]
103
+ "enum": ["api", "contract", "function", "socket"]
104
104
  },
105
105
  "location": { "type": "string" },
106
106
  "method": {