@fnet/cli 0.133.0 → 0.133.1
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/dist/fbin/index.js +14 -1
- package/dist/fnet/index.0jcm9pn5.js +1 -0
- package/dist/fnet/index.2084z2ed.js +2 -0
- package/dist/fnet/index.33f1ggpr.js +1 -0
- package/dist/fnet/index.3exge2js.js +1 -0
- package/dist/fnet/index.3kfx538h.js +1 -0
- package/dist/fnet/index.490y87nc.js +1 -0
- package/dist/fnet/index.4g9yezkq.js +1 -0
- package/dist/fnet/index.4jkat7r4.js +1 -0
- package/dist/fnet/index.7crx8ky1.js +1 -0
- package/dist/fnet/index.7vw06nrn.js +1 -0
- package/dist/fnet/index.9567fa9x.js +1 -0
- package/dist/fnet/index.gh75wt1m.js +1 -0
- package/dist/fnet/index.hzsfswvp.js +1 -0
- package/dist/fnet/index.jgpc3grc.js +1 -0
- package/dist/fnet/index.js +19 -1
- package/dist/fnet/index.p0zb7e1b.js +1 -0
- package/dist/fnet/index.r19p3bpa.js +2 -0
- package/dist/fnet/index.r82rtnmz.js +1 -0
- package/dist/fnet/index.s662t98v.js +1 -0
- package/dist/fnet/index.w74dpnpn.js +1 -0
- package/dist/fnet/index.xeaw5xa9.js +1 -0
- package/dist/fnet/index.zm4kesg6.js +1 -0
- package/dist/fnode/index.05n3mvs9.js +2 -0
- package/dist/fnode/index.2hc9tbyx.js +1 -0
- package/dist/fnode/index.2pnjg6dc.js +1 -0
- package/dist/fnode/index.9qgtmxq3.js +2 -0
- package/dist/fnode/index.b1q7y05p.js +1 -0
- package/dist/fnode/index.bhapgrs7.js +1 -0
- package/dist/fnode/index.cvxrf34y.js +2 -0
- package/dist/fnode/index.dp9wyahp.js +1 -0
- package/dist/fnode/index.eqxmcpdc.js +1 -0
- package/dist/fnode/index.f2tb0x3t.js +1 -0
- package/dist/fnode/index.fbzv6wwf.js +1 -0
- package/dist/fnode/index.gazd9raq.js +1 -0
- package/dist/fnode/index.hv4s25f0.js +3 -0
- package/dist/fnode/index.j5z7dtsx.js +1 -0
- package/dist/fnode/index.js +9 -1
- package/dist/fnode/index.kb4e4bxf.js +1 -0
- package/dist/fnode/index.qn0schqp.js +1 -0
- package/dist/fnode/index.rht29phd.js +1 -0
- package/dist/fnode/index.rzsfmek6.js +3 -0
- package/dist/fnode/index.s0nk6cv8.js +4 -0
- package/dist/fnode/index.s66v6wt4.js +1 -0
- package/dist/fnode/index.sv7v0y60.js +1 -0
- package/dist/fnode/index.tgkhgnrp.js +1 -0
- package/dist/fnode/index.vq706f75.js +1 -0
- package/dist/fnode/index.y8pvdcny.js +1 -0
- package/dist/fnode/index.z4vz93ww.js +1 -0
- package/dist/frun/index.js +1 -1
- package/dist/fservice/index.js +18 -1
- package/dist/fservice/index.q01yvaz0.js +2 -0
- package/package.json +21 -18
- package/readme.md +62 -15
- package/template/fnet/core/object.js +10 -10
- package/template/fnet/node/package.json.njk +6 -3
- package/template/fnet/node/src/cli/index.js.njk +5 -315
- package/template/fnet/node/src/cli/index.js.v1.njk +318 -0
- package/template/fnet/node/src/cli/v2/core/args-parser.njk +10 -0
- package/template/fnet/node/src/cli/v2/core/imports.njk +31 -0
- package/template/fnet/node/src/cli/v2/core/run-wrapper.njk +25 -0
- package/template/fnet/node/src/cli/v2/index.js.njk +184 -0
- package/template/fnet/node/src/cli/v2/modes/default/extend.njk +11 -0
- package/template/fnet/node/src/cli/v2/modes/default/standard.njk +20 -0
- package/template/fnet/node/src/cli/v2/modes/http/builtin.njk +66 -0
- package/template/fnet/node/src/cli/v2/modes/http/imports.njk +9 -0
- package/template/fnet/node/src/cli/v2/modes/http/index.njk +12 -0
- package/template/fnet/node/src/cli/v2/modes/mcp/imports.njk +33 -0
- package/template/fnet/node/src/cli/v2/modes/mcp/index.njk +30 -0
- package/template/fnet/node/src/cli/v2/modes/mcp/server-setup.njk +15 -0
- package/template/fnet/node/src/cli/v2/modes/mcp/tool-handlers.njk +46 -0
- package/template/fnet/node/src/cli/v2/modes/mcp/transport-http.njk +222 -0
- package/template/fnet/node/src/cli/v2/modes/mcp/transport-stdio.njk +9 -0
- package/template/fnet/node/src/cli/v2/modes/pipeline/imports.njk +9 -0
- package/template/fnet/node/src/cli/v2/modes/pipeline/index.njk +113 -0
- package/template/fnet/node/src/cli/v2/modes/webhook/imports.njk +9 -0
- package/template/fnet/node/src/cli/v2/modes/webhook/index.njk +127 -0
- package/template/fnet/node/src/cli/v2/modes/websocket/imports.njk +15 -0
- package/template/fnet/node/src/cli/v2/modes/websocket/index.njk +104 -0
- package/template/fnet/node/src/default/blocks/assign.js.njk +10 -48
- package/template/fnet/node/src/default/blocks/call.js.njk +110 -156
- package/template/fnet/node/src/default/blocks/for.js.njk +58 -74
- package/template/fnet/node/src/default/blocks/form.js.njk +21 -59
- package/template/fnet/node/src/default/blocks/http.js.njk +135 -0
- package/template/fnet/node/src/default/blocks/modules.js.njk +10 -52
- package/template/fnet/node/src/default/blocks/new.js.njk +40 -85
- package/template/fnet/node/src/default/blocks/next.js.njk +10 -32
- package/template/fnet/node/src/default/blocks/output.js.njk +10 -48
- package/template/fnet/node/src/default/blocks/parallel.js.njk +64 -0
- package/template/fnet/node/src/default/blocks/pipeline.js.njk +109 -0
- package/template/fnet/node/src/default/blocks/raise.js.njk +9 -25
- package/template/fnet/node/src/default/blocks/retry.js.njk +70 -0
- package/template/fnet/node/src/default/blocks/return.js.njk +13 -25
- package/template/fnet/node/src/default/blocks/schedule.js.njk +66 -0
- package/template/fnet/node/src/default/blocks/signal.js.njk +10 -32
- package/template/fnet/node/src/default/blocks/steps.js.njk +32 -48
- package/template/fnet/node/src/default/blocks/switch.js.njk +37 -67
- package/template/fnet/node/src/default/blocks/tryexcept.js.njk +58 -52
- package/template/fnet/node/src/default/blocks/wait.js.njk +10 -30
- package/template/fnet/node/src/default/input.args.js.njk +5 -2
- package/template/fnet/node/src/default/macros/block-body-header.js.njk +1 -1
- package/template/fnet/node/src/default/macros/block-header.js.njk +0 -3
- package/template/fnet/node/src/default/macros/block-next.js.njk +1 -1
- package/template/fnet/node/src/default/macros/block-run-footer.js.njk +1 -1
- package/template/fnet/node/src/default/macros/block-run-header.js.njk +14 -2
- package/template/fnet/node/src/default/macros/page.js.njk +1 -1
- package/template/fnet/node/src/default/types/block.js.njk +133 -0
- package/template/fnet/node/src/default/workflow.js.njk +8 -6
- package/template/fnode/node/package.json.njk +5 -4
- package/template/fnode/node/src/cli/index.js.njk +3 -397
- package/template/fnode/node/src/cli/index.js.v1.njk +464 -0
- package/template/fnode/node/src/cli/v2/core/args-parser.njk +10 -0
- package/template/fnode/node/src/cli/v2/core/imports.njk +29 -0
- package/template/fnode/node/src/cli/v2/core/run-wrapper.njk +25 -0
- package/template/fnode/node/src/cli/v2/index.js.njk +184 -0
- package/template/fnode/node/src/cli/v2/modes/default/extend.njk +11 -0
- package/template/fnode/node/src/cli/v2/modes/default/standard.njk +19 -0
- package/template/fnode/node/src/cli/v2/modes/http/builtin.njk +61 -0
- package/template/fnode/node/src/cli/v2/modes/http/imports.njk +9 -0
- package/template/fnode/node/src/cli/v2/modes/http/index.njk +12 -0
- package/template/fnode/node/src/cli/v2/modes/mcp/imports.njk +33 -0
- package/template/fnode/node/src/cli/v2/modes/mcp/index.njk +30 -0
- package/template/fnode/node/src/cli/v2/modes/mcp/server-setup.njk +15 -0
- package/template/fnode/node/src/cli/v2/modes/mcp/tool-handlers.njk +41 -0
- package/template/fnode/node/src/cli/v2/modes/mcp/transport-http.njk +212 -0
- package/template/fnode/node/src/cli/v2/modes/mcp/transport-stdio.njk +9 -0
- package/template/fnode/node/src/cli/v2/modes/pipeline/imports.njk +9 -0
- package/template/fnode/node/src/cli/v2/modes/pipeline/index.njk +103 -0
- package/template/fnode/node/src/cli/v2/modes/webhook/imports.njk +9 -0
- package/template/fnode/node/src/cli/v2/modes/webhook/index.njk +122 -0
- package/template/fnode/node/src/cli/v2/modes/websocket/imports.njk +15 -0
- package/template/fnode/node/src/cli/v2/modes/websocket/index.njk +99 -0
- package/template/fnode/node/src/default/input.args.js.njk +6 -2
- package/dist/fnet/index.-SGbq2cI.js +0 -1
- package/dist/fnet/index.B5XE4ChJ.js +0 -1
- package/dist/fnet/index.Bft2w7m3.js +0 -1
- package/dist/fnet/index.BuYxdKtK.js +0 -1
- package/dist/fnet/index.C0YpfQ5j.js +0 -1
- package/dist/fnet/index.C2S9JYhS.js +0 -1
- package/dist/fnet/index.C7saWH6d.js +0 -1
- package/dist/fnet/index.CDct_kkF.js +0 -1
- package/dist/fnet/index.CMC8mlye.js +0 -1
- package/dist/fnet/index.CmMM-Ek9.js +0 -1
- package/dist/fnet/index.CuMyez3E.js +0 -1
- package/dist/fnet/index.CzAV0S36.js +0 -1
- package/dist/fnet/index.D2N9YZmA.js +0 -1
- package/dist/fnet/index.D3p7pncT.js +0 -1
- package/dist/fnet/index.DG8TqL-1.js +0 -1
- package/dist/fnet/index.DI3yyTtl.js +0 -1
- package/dist/fnet/index.DOYkqsYT.js +0 -1
- package/dist/fnet/index.DWpw12No.js +0 -1
- package/dist/fnet/index.DrwlOzAe.js +0 -1
- package/dist/fnet/index.Q-CYRcna.js +0 -1
- package/dist/fnet/index.W6RYgypK.js +0 -1
- package/dist/fnet/index.xd8c7XMr.js +0 -1
- package/dist/fnode/index.-SGbq2cI.js +0 -1
- package/dist/fnode/index.B5XE4ChJ.js +0 -1
- package/dist/fnode/index.B8gal9up.js +0 -1
- package/dist/fnode/index.BU1440aO.js +0 -1
- package/dist/fnode/index.BcGYSPne.js +0 -1
- package/dist/fnode/index.Bft2w7m3.js +0 -1
- package/dist/fnode/index.BuYxdKtK.js +0 -1
- package/dist/fnode/index.C2S9JYhS.js +0 -1
- package/dist/fnode/index.C7saWH6d.js +0 -1
- package/dist/fnode/index.CDct_kkF.js +0 -1
- package/dist/fnode/index.CMC8mlye.js +0 -1
- package/dist/fnode/index.CmMM-Ek9.js +0 -1
- package/dist/fnode/index.CuMyez3E.js +0 -1
- package/dist/fnode/index.CzAV0S36.js +0 -1
- package/dist/fnode/index.D2N9YZmA.js +0 -1
- package/dist/fnode/index.D3p7pncT.js +0 -1
- package/dist/fnode/index.DG8TqL-1.js +0 -1
- package/dist/fnode/index.DI3yyTtl.js +0 -1
- package/dist/fnode/index.DWpw12No.js +0 -1
- package/dist/fnode/index.DrwlOzAe.js +0 -1
- package/dist/fnode/index.N_a5FdgA.js +0 -1
- package/dist/fnode/index.Q-CYRcna.js +0 -1
- package/dist/fnode/index.UNoFg95r.js +0 -1
- package/dist/fnode/index.W6RYgypK.js +0 -1
- package/dist/fnode/index.xd8c7XMr.js +0 -1
- package/template/fnet/core/print.js +0 -1
- package/template/fnet/node/src/default/macros/workflow-header.js.njk +0 -7
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
{# ============================================================================
|
|
2
|
+
CLI TEMPLATE V2 - MODULAR ARCHITECTURE
|
|
3
|
+
============================================================================
|
|
4
|
+
|
|
5
|
+
This template uses a modular, registry-based approach for maximum
|
|
6
|
+
extensibility. New modes, transports, and output formats can be added
|
|
7
|
+
without modifying the core template structure.
|
|
8
|
+
|
|
9
|
+
Architecture:
|
|
10
|
+
- core/ : Base imports, argument parsing, error handling
|
|
11
|
+
- modes/ : CLI execution modes (default, mcp, http, pipeline, etc.)
|
|
12
|
+
- output/ : Output formatters (json, yaml, table, etc.)
|
|
13
|
+
|
|
14
|
+
Each mode is self-contained and can be enabled/disabled via feature flags.
|
|
15
|
+
|
|
16
|
+
Supports:
|
|
17
|
+
- ESM and CJS formats
|
|
18
|
+
- Standard and Extend modes
|
|
19
|
+
- Multiple CLI modes (default, mcp, http)
|
|
20
|
+
|
|
21
|
+
============================================================================ #}
|
|
22
|
+
|
|
23
|
+
{% if atom.doc.features.cli.enabled===true %}
|
|
24
|
+
|
|
25
|
+
{# --------------------------------------------------------------------------
|
|
26
|
+
CORE IMPORTS
|
|
27
|
+
-------------------------------------------------------------------------- #}
|
|
28
|
+
{% include "./core/imports.njk" %}
|
|
29
|
+
|
|
30
|
+
{# --------------------------------------------------------------------------
|
|
31
|
+
SHARED IMPORTS
|
|
32
|
+
--------------------------------------------------------------------------
|
|
33
|
+
Shared dependencies used by multiple modes
|
|
34
|
+
Prevents duplicate imports when multiple modes are enabled
|
|
35
|
+
-------------------------------------------------------------------------- #}
|
|
36
|
+
{% if atom.doc.features.cli.http.enabled===true or atom.doc.features.cli.webhook.enabled===true %}
|
|
37
|
+
// Shared: http module (used by HTTP and Webhook modes)
|
|
38
|
+
{% if atom.doc.features.project.format==='esm' %}
|
|
39
|
+
import http from 'http';
|
|
40
|
+
{% elif atom.doc.features.project.format==='cjs' %}
|
|
41
|
+
const http = require('http');
|
|
42
|
+
{% endif %}
|
|
43
|
+
{% endif %}
|
|
44
|
+
|
|
45
|
+
{% if atom.doc.features.cli.mcp.enabled === true or atom.doc.features.cli.webhook.enabled===true %}
|
|
46
|
+
// Shared: crypto module (used by MCP and Webhook modes)
|
|
47
|
+
{% if atom.doc.features.project.format==='esm' %}
|
|
48
|
+
import crypto from 'crypto';
|
|
49
|
+
{% elif atom.doc.features.project.format==='cjs' %}
|
|
50
|
+
const crypto = require('crypto');
|
|
51
|
+
{% endif %}
|
|
52
|
+
{% endif %}
|
|
53
|
+
|
|
54
|
+
{# --------------------------------------------------------------------------
|
|
55
|
+
MODE-SPECIFIC IMPORTS
|
|
56
|
+
--------------------------------------------------------------------------
|
|
57
|
+
Import dependencies for ALL enabled CLI modes
|
|
58
|
+
Multiple modes can be enabled simultaneously
|
|
59
|
+
-------------------------------------------------------------------------- #}
|
|
60
|
+
{% if atom.doc.features.cli.mcp.enabled === true %}
|
|
61
|
+
{% include "./modes/mcp/imports.njk" %}
|
|
62
|
+
{% endif %}
|
|
63
|
+
|
|
64
|
+
{% if atom.doc.features.cli.http.enabled===true %}
|
|
65
|
+
{% include "./modes/http/imports.njk" %}
|
|
66
|
+
{% endif %}
|
|
67
|
+
|
|
68
|
+
{% if atom.doc.features.cli.pipeline.enabled===true %}
|
|
69
|
+
{% include "./modes/pipeline/imports.njk" %}
|
|
70
|
+
{% endif %}
|
|
71
|
+
|
|
72
|
+
{% if atom.doc.features.cli.websocket.enabled===true %}
|
|
73
|
+
{% include "./modes/websocket/imports.njk" %}
|
|
74
|
+
{% endif %}
|
|
75
|
+
|
|
76
|
+
{% if atom.doc.features.cli.webhook.enabled===true %}
|
|
77
|
+
{% include "./modes/webhook/imports.njk" %}
|
|
78
|
+
{% endif %}
|
|
79
|
+
|
|
80
|
+
{# --------------------------------------------------------------------------
|
|
81
|
+
ARGUMENT PARSER
|
|
82
|
+
-------------------------------------------------------------------------- #}
|
|
83
|
+
{% include "./core/args-parser.njk" %}
|
|
84
|
+
|
|
85
|
+
{# --------------------------------------------------------------------------
|
|
86
|
+
MAIN RUN FUNCTION
|
|
87
|
+
--------------------------------------------------------------------------
|
|
88
|
+
Mode registry: Each mode is self-contained and handles its own logic
|
|
89
|
+
-------------------------------------------------------------------------- #}
|
|
90
|
+
const run = async () => {
|
|
91
|
+
const args = parseArgs();
|
|
92
|
+
const cliMode = args['cli-mode'] || args.cli_mode || 'default';
|
|
93
|
+
|
|
94
|
+
{# --------------------------------------------------------------------------
|
|
95
|
+
DEFAULT MODE
|
|
96
|
+
--------------------------------------------------------------------------
|
|
97
|
+
Standard or extended mode based on CLI configuration
|
|
98
|
+
-------------------------------------------------------------------------- #}
|
|
99
|
+
{% if atom.doc.features.cli.extend===true %}
|
|
100
|
+
{% include "./modes/default/extend.njk" %}
|
|
101
|
+
{% else %}
|
|
102
|
+
{% include "./modes/default/standard.njk" %}
|
|
103
|
+
{% endif %}
|
|
104
|
+
|
|
105
|
+
{# --------------------------------------------------------------------------
|
|
106
|
+
MCP MODE
|
|
107
|
+
--------------------------------------------------------------------------
|
|
108
|
+
Model Context Protocol server with multiple transport options
|
|
109
|
+
-------------------------------------------------------------------------- #}
|
|
110
|
+
{% if atom.doc.features.cli.mcp.enabled === true %}
|
|
111
|
+
{% include "./modes/mcp/index.njk" %}
|
|
112
|
+
{% endif %}
|
|
113
|
+
|
|
114
|
+
{# --------------------------------------------------------------------------
|
|
115
|
+
HTTP MODE
|
|
116
|
+
--------------------------------------------------------------------------
|
|
117
|
+
REST API server using built-in http module
|
|
118
|
+
-------------------------------------------------------------------------- #}
|
|
119
|
+
{% if atom.doc.features.cli.http.enabled===true %}
|
|
120
|
+
{% include "./modes/http/index.njk" %}
|
|
121
|
+
{% endif %}
|
|
122
|
+
|
|
123
|
+
{# --------------------------------------------------------------------------
|
|
124
|
+
PIPELINE MODE
|
|
125
|
+
--------------------------------------------------------------------------
|
|
126
|
+
Unix pipeline integration via stdin/stdout
|
|
127
|
+
-------------------------------------------------------------------------- #}
|
|
128
|
+
{% if atom.doc.features.cli.pipeline.enabled===true %}
|
|
129
|
+
{% include "./modes/pipeline/index.njk" %}
|
|
130
|
+
{% endif %}
|
|
131
|
+
|
|
132
|
+
{# --------------------------------------------------------------------------
|
|
133
|
+
WEBSOCKET MODE
|
|
134
|
+
--------------------------------------------------------------------------
|
|
135
|
+
Real-time bidirectional communication
|
|
136
|
+
-------------------------------------------------------------------------- #}
|
|
137
|
+
{% if atom.doc.features.cli.websocket.enabled===true %}
|
|
138
|
+
{% include "./modes/websocket/index.njk" %}
|
|
139
|
+
{% endif %}
|
|
140
|
+
|
|
141
|
+
{# --------------------------------------------------------------------------
|
|
142
|
+
WEBHOOK MODE
|
|
143
|
+
--------------------------------------------------------------------------
|
|
144
|
+
Event-driven HTTP with HMAC signature verification
|
|
145
|
+
-------------------------------------------------------------------------- #}
|
|
146
|
+
{% if atom.doc.features.cli.webhook.enabled===true %}
|
|
147
|
+
{% include "./modes/webhook/index.njk" %}
|
|
148
|
+
{% endif %}
|
|
149
|
+
|
|
150
|
+
{# --------------------------------------------------------------------------
|
|
151
|
+
FUTURE MODES
|
|
152
|
+
--------------------------------------------------------------------------
|
|
153
|
+
Add new modes here by simply including their index.njk
|
|
154
|
+
|
|
155
|
+
Examples:
|
|
156
|
+
- gRPC mode for high-performance RPC
|
|
157
|
+
- GraphQL mode for flexible APIs
|
|
158
|
+
- SSE mode for server-sent events
|
|
159
|
+
-------------------------------------------------------------------------- #}
|
|
160
|
+
|
|
161
|
+
{# {% if atom.doc.features.cli.webhook.enabled===true %}
|
|
162
|
+
{% include "./modes/webhook/index.njk" %}
|
|
163
|
+
{% endif %} #}
|
|
164
|
+
|
|
165
|
+
{# {% if atom.doc.features.cli.grpc.enabled===true %}
|
|
166
|
+
{% include "./modes/grpc/index.njk" %}
|
|
167
|
+
{% endif %} #}
|
|
168
|
+
|
|
169
|
+
{# --------------------------------------------------------------------------
|
|
170
|
+
UNKNOWN MODE HANDLER
|
|
171
|
+
-------------------------------------------------------------------------- #}
|
|
172
|
+
console.error(`Unknown CLI mode: ${cliMode}`);
|
|
173
|
+
console.error(`Available modes: default{% if atom.doc.features.cli.mcp.enabled === true %}, mcp{% endif %}{% if atom.doc.features.cli.http.enabled===true %}, http{% endif %}{% if atom.doc.features.cli.pipeline.enabled===true %}, pipeline{% endif %}{% if atom.doc.features.cli.websocket.enabled===true %}, websocket{% endif %}{% if atom.doc.features.cli.webhook.enabled===true %}, webhook{% endif %}`);
|
|
174
|
+
process.exit(1);
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
{# --------------------------------------------------------------------------
|
|
178
|
+
ERROR HANDLER & RUN
|
|
179
|
+
-------------------------------------------------------------------------- #}
|
|
180
|
+
{% include "./core/run-wrapper.njk" %}
|
|
181
|
+
|
|
182
|
+
{% endif %}
|
|
183
|
+
{# End of cli.enabled check #}
|
|
184
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{# ============================================================================
|
|
2
|
+
DEFAULT MODE - EXTEND
|
|
3
|
+
============================================================================
|
|
4
|
+
Extended CLI mode that returns result directly (for CLI wrapper usage)
|
|
5
|
+
============================================================================ #}
|
|
6
|
+
|
|
7
|
+
if (cliMode === 'default') {
|
|
8
|
+
// Default mode code
|
|
9
|
+
return await Node(await argv());
|
|
10
|
+
}
|
|
11
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{# ============================================================================
|
|
2
|
+
DEFAULT MODE - STANDARD
|
|
3
|
+
============================================================================
|
|
4
|
+
Standard CLI mode that executes the Node function and prints result
|
|
5
|
+
============================================================================ #}
|
|
6
|
+
|
|
7
|
+
if (cliMode === 'default') {
|
|
8
|
+
// Default mode code
|
|
9
|
+
const result = await Node(await argv());
|
|
10
|
+
|
|
11
|
+
if (typeof result !== 'undefined') {
|
|
12
|
+
const stdout_format = args['stdout-format'] || args.stdout_format || null;
|
|
13
|
+
|
|
14
|
+
if (stdout_format === 'json') console.log(JSON.stringify(result, null, 2));
|
|
15
|
+
else console.log(result);
|
|
16
|
+
}
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{# ============================================================================
|
|
2
|
+
HTTP MODE - BUILT-IN (Native Node.js HTTP)
|
|
3
|
+
============================================================================
|
|
4
|
+
Simple REST API server using Node.js built-in http module
|
|
5
|
+
No external dependencies required
|
|
6
|
+
============================================================================ #}
|
|
7
|
+
|
|
8
|
+
const server = http.createServer(async (req, res) => {
|
|
9
|
+
// CORS headers
|
|
10
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
11
|
+
res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
|
|
12
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
13
|
+
|
|
14
|
+
// Handle OPTIONS preflight
|
|
15
|
+
if (req.method === 'OPTIONS') {
|
|
16
|
+
res.writeHead(200);
|
|
17
|
+
res.end();
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Only accept POST requests
|
|
22
|
+
if (req.method !== 'POST') {
|
|
23
|
+
res.writeHead(405, { 'Content-Type': 'application/json' });
|
|
24
|
+
res.end(JSON.stringify({ error: 'Method not allowed' }));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Check path
|
|
29
|
+
const path = '/{{atom.doc.features.cli.http.path or atom.doc.name}}';
|
|
30
|
+
if (req.url !== path) {
|
|
31
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
32
|
+
res.end(JSON.stringify({ error: 'Not found' }));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Parse request body
|
|
37
|
+
let body = '';
|
|
38
|
+
req.on('data', chunk => {
|
|
39
|
+
body += chunk.toString();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
req.on('end', async () => {
|
|
43
|
+
try {
|
|
44
|
+
const data = JSON.parse(body);
|
|
45
|
+
const result = await Node(data);
|
|
46
|
+
|
|
47
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
48
|
+
res.end(JSON.stringify(result));
|
|
49
|
+
} catch (error) {
|
|
50
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
51
|
+
res.end(JSON.stringify({ error: error.message }));
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const port = args['cli-port'] || args.cli_port || 3000;
|
|
57
|
+
server.listen(port, () => {
|
|
58
|
+
console.log(`HTTP server started on port ${port} (native http)`);
|
|
59
|
+
});
|
|
60
|
+
return;
|
|
61
|
+
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{# ============================================================================
|
|
2
|
+
HTTP MODE - IMPORTS
|
|
3
|
+
============================================================================
|
|
4
|
+
No mode-specific imports needed
|
|
5
|
+
http module is imported in shared imports section
|
|
6
|
+
============================================================================ #}
|
|
7
|
+
|
|
8
|
+
{# http module imported in shared section #}
|
|
9
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{# ============================================================================
|
|
2
|
+
HTTP MODE - MAIN
|
|
3
|
+
============================================================================
|
|
4
|
+
HTTP REST API mode using Node.js built-in http module
|
|
5
|
+
Zero dependencies, simple and fast
|
|
6
|
+
============================================================================ #}
|
|
7
|
+
|
|
8
|
+
if (cliMode === 'http') {
|
|
9
|
+
// HTTP mode code
|
|
10
|
+
{% include "./builtin.njk" %}
|
|
11
|
+
}
|
|
12
|
+
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{# ============================================================================
|
|
2
|
+
MCP MODE - IMPORTS
|
|
3
|
+
============================================================================
|
|
4
|
+
MCP SDK dependencies for Model Context Protocol support
|
|
5
|
+
Supports both ESM and CJS formats
|
|
6
|
+
============================================================================ #}
|
|
7
|
+
|
|
8
|
+
{% if atom.doc.features.project.format==='esm' %}
|
|
9
|
+
{# ESM Format #}
|
|
10
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
11
|
+
import { ListToolsRequestSchema, CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
12
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
13
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
14
|
+
import express from "express";
|
|
15
|
+
{% if atom.doc.features.cli.mcp.ws===true %}
|
|
16
|
+
import expressWs from "express-ws";
|
|
17
|
+
{% endif %}
|
|
18
|
+
{# crypto imported in shared section #}
|
|
19
|
+
|
|
20
|
+
{% elif atom.doc.features.project.format==='cjs' %}
|
|
21
|
+
{# CJS Format #}
|
|
22
|
+
const { Server } = require("@modelcontextprotocol/sdk/server/index.js");
|
|
23
|
+
const { ListToolsRequestSchema, CallToolRequestSchema } = require("@modelcontextprotocol/sdk/types.js");
|
|
24
|
+
const { StdioServerTransport } = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
25
|
+
const { StreamableHTTPServerTransport } = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
26
|
+
const express = require("express");
|
|
27
|
+
{% if atom.doc.features.cli.mcp.ws===true %}
|
|
28
|
+
const expressWs = require("express-ws");
|
|
29
|
+
{% endif %}
|
|
30
|
+
{# crypto imported in shared section #}
|
|
31
|
+
|
|
32
|
+
{% endif %}
|
|
33
|
+
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{# ============================================================================
|
|
2
|
+
MCP MODE - MAIN
|
|
3
|
+
============================================================================
|
|
4
|
+
Model Context Protocol mode orchestrator
|
|
5
|
+
Supports multiple transports: STDIO, HTTP (future: WebSocket, SSE, gRPC)
|
|
6
|
+
============================================================================ #}
|
|
7
|
+
|
|
8
|
+
if (cliMode === 'mcp') {
|
|
9
|
+
// MCP mode code
|
|
10
|
+
{% include "./server-setup.njk" %}
|
|
11
|
+
{% include "./tool-handlers.njk" %}
|
|
12
|
+
|
|
13
|
+
// Get transport type from arguments
|
|
14
|
+
const transportType = args['mcp-transport'] || args.mcp_transport || 'stdio';
|
|
15
|
+
let transport;
|
|
16
|
+
|
|
17
|
+
if (transportType === 'stdio') {
|
|
18
|
+
{% include "./transport-stdio.njk" %}
|
|
19
|
+
} else if (transportType === 'http') {
|
|
20
|
+
{% include "./transport-http.njk" %}
|
|
21
|
+
} else {
|
|
22
|
+
console.error(`Unknown MCP transport type: ${transportType}`);
|
|
23
|
+
console.error(`Supported types: stdio, http`);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
await server.connect(transport);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{# ============================================================================
|
|
2
|
+
MCP MODE - SERVER SETUP
|
|
3
|
+
============================================================================
|
|
4
|
+
Initialize MCP server with capabilities
|
|
5
|
+
============================================================================ #}
|
|
6
|
+
|
|
7
|
+
const server = new Server({
|
|
8
|
+
name: "{{atom.doc.features.cli.mcp.name or atom.doc.name}}",
|
|
9
|
+
version: "{{atom.doc.version or '0.0.1'}}"
|
|
10
|
+
}, {
|
|
11
|
+
capabilities: {
|
|
12
|
+
tools: {}
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{# ============================================================================
|
|
2
|
+
MCP MODE - TOOL HANDLERS
|
|
3
|
+
============================================================================
|
|
4
|
+
Register MCP tool handlers for listing and executing tools
|
|
5
|
+
============================================================================ #}
|
|
6
|
+
|
|
7
|
+
// Define available tools
|
|
8
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
9
|
+
return {
|
|
10
|
+
tools: [{
|
|
11
|
+
name: "{{atom.doc.features.cli.mcp.tool.name or atom.doc.name}}",
|
|
12
|
+
description: `{{atom.doc.features.cli.mcp.tool.description or atom.doc.description}}`,
|
|
13
|
+
inputSchema: inputSchema
|
|
14
|
+
}]
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// Handle tool execution
|
|
19
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
20
|
+
if (request.params.name === "{{atom.doc.features.cli.mcp.tool.name or atom.doc.name}}") {
|
|
21
|
+
try {
|
|
22
|
+
const result = await Node(request.params.arguments);
|
|
23
|
+
return {
|
|
24
|
+
content: [{
|
|
25
|
+
type: "text",
|
|
26
|
+
text: JSON.stringify(result)
|
|
27
|
+
}]
|
|
28
|
+
};
|
|
29
|
+
} catch (error) {
|
|
30
|
+
return {
|
|
31
|
+
content: [{
|
|
32
|
+
type: "text",
|
|
33
|
+
text: `Error: ${error.message}`
|
|
34
|
+
}],
|
|
35
|
+
isError: true
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
throw new Error("Tool not found");
|
|
40
|
+
});
|
|
41
|
+
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
{# ============================================================================
|
|
2
|
+
MCP MODE - HTTP TRANSPORT
|
|
3
|
+
============================================================================
|
|
4
|
+
Streamable HTTP transport for MCP protocol with session management
|
|
5
|
+
Official transport as of MCP 2025-03-26
|
|
6
|
+
============================================================================ #}
|
|
7
|
+
|
|
8
|
+
// Use Streamable HTTP transport (official transport as of MCP 2025-03-26)
|
|
9
|
+
const app = express();
|
|
10
|
+
{% if atom.doc.features.cli.mcp.ws===true %}
|
|
11
|
+
// Enable WebSocket support
|
|
12
|
+
expressWs(app);
|
|
13
|
+
{% endif %}
|
|
14
|
+
app.use(express.json());
|
|
15
|
+
|
|
16
|
+
const port = args['cli-port'] || args.cli_port || 3000;
|
|
17
|
+
const host = args['cli-host'] || args.cli_host || '0.0.0.0';
|
|
18
|
+
const basePath = '{{atom.doc.features.cli.mcp.path or 'mcp'}}';
|
|
19
|
+
const mcpEndpoint = `/${basePath}`; // MCP protocol endpoint
|
|
20
|
+
const verbose = args['cli-verbose'] || args.cli_verbose || false;
|
|
21
|
+
|
|
22
|
+
// Optional endpoints (enabled via config)
|
|
23
|
+
const httpEnabled = {{atom.doc.features.cli.mcp.http or false}};
|
|
24
|
+
const wsEnabled = {{atom.doc.features.cli.mcp.ws or false}};
|
|
25
|
+
const httpEndpoint = `/${basePath}/input`; // HTTP input endpoint
|
|
26
|
+
const wsEndpoint = `/${basePath}/ws`; // WebSocket endpoint
|
|
27
|
+
|
|
28
|
+
// Verbose logging helper
|
|
29
|
+
const log = (...args) => {
|
|
30
|
+
if (verbose) {
|
|
31
|
+
console.log('[MCP]', new Date().toISOString(), ...args);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// Map to store transports by session ID
|
|
36
|
+
const transports = {};
|
|
37
|
+
|
|
38
|
+
// Handle POST requests for client-to-server communication
|
|
39
|
+
app.post(mcpEndpoint, async (req, res) => {
|
|
40
|
+
// Check for existing session ID
|
|
41
|
+
const sessionId = req.get('Mcp-Session-Id');
|
|
42
|
+
|
|
43
|
+
log('POST request received');
|
|
44
|
+
log('Session ID:', sessionId || 'none');
|
|
45
|
+
log('Request body:', JSON.stringify(req.body, null, 2));
|
|
46
|
+
|
|
47
|
+
let transport;
|
|
48
|
+
|
|
49
|
+
if (sessionId && transports[sessionId]) {
|
|
50
|
+
// Reuse existing transport
|
|
51
|
+
log('Reusing existing transport for session:', sessionId);
|
|
52
|
+
transport = transports[sessionId];
|
|
53
|
+
} else if (!sessionId && req.body && (req.body.method === 'initialize' ||
|
|
54
|
+
(Array.isArray(req.body) && req.body.some(item => item.method === 'initialize')))) {
|
|
55
|
+
// New initialization request
|
|
56
|
+
log('Creating new transport for initialization');
|
|
57
|
+
transport = new StreamableHTTPServerTransport({
|
|
58
|
+
sessionIdGenerator: () => {
|
|
59
|
+
// Generate cryptographically secure session ID
|
|
60
|
+
return crypto.randomBytes(16).toString('hex');
|
|
61
|
+
},
|
|
62
|
+
onsessioninitialized: (sessionId) => {
|
|
63
|
+
// Store the transport by session ID
|
|
64
|
+
log('Session initialized:', sessionId);
|
|
65
|
+
transports[sessionId] = transport;
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Clean up transport when closed
|
|
70
|
+
transport.onclose = () => {
|
|
71
|
+
if (transport.sessionId) {
|
|
72
|
+
log('Transport closed, cleaning up session:', transport.sessionId);
|
|
73
|
+
delete transports[transport.sessionId];
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// Connect to the MCP server
|
|
78
|
+
await server.connect(transport);
|
|
79
|
+
log('Server connected to transport');
|
|
80
|
+
} else {
|
|
81
|
+
// Invalid request
|
|
82
|
+
log('Invalid request - no valid session ID');
|
|
83
|
+
return res.status(400).json({
|
|
84
|
+
jsonrpc: '2.0',
|
|
85
|
+
error: {
|
|
86
|
+
code: -32000,
|
|
87
|
+
message: 'Bad Request: No valid session ID provided'
|
|
88
|
+
},
|
|
89
|
+
id: null
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Handle the request
|
|
94
|
+
log('Handling request with transport');
|
|
95
|
+
await transport.handleRequest(req, res, req.body);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Reusable handler for GET and DELETE requests
|
|
99
|
+
const handleSessionRequest = async (req, res) => {
|
|
100
|
+
const sessionId = req.get('Mcp-Session-Id');
|
|
101
|
+
log(`${req.method} request received for session:`, sessionId || 'none');
|
|
102
|
+
|
|
103
|
+
if (!sessionId || !transports[sessionId]) {
|
|
104
|
+
log('Invalid or missing session ID');
|
|
105
|
+
return res.status(400).send('Invalid or missing session ID');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const transport = transports[sessionId];
|
|
109
|
+
log('Handling request with existing transport');
|
|
110
|
+
await transport.handleRequest(req, res);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
// Handle GET requests for server-to-client notifications via SSE
|
|
114
|
+
app.get(mcpEndpoint, handleSessionRequest);
|
|
115
|
+
|
|
116
|
+
// Handle DELETE requests for session termination
|
|
117
|
+
app.delete(mcpEndpoint, handleSessionRequest);
|
|
118
|
+
|
|
119
|
+
{% if atom.doc.features.cli.mcp.http===true %}
|
|
120
|
+
// HTTP input endpoint (enabled via config: cli.mcp.http: true)
|
|
121
|
+
app.post(httpEndpoint, async (req, res) => {
|
|
122
|
+
log('HTTP input request received');
|
|
123
|
+
log('Request body:', JSON.stringify(req.body, null, 2));
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
// Call the Node function directly with the request body
|
|
127
|
+
const result = await Node(req.body);
|
|
128
|
+
|
|
129
|
+
log('HTTP input processed successfully');
|
|
130
|
+
log('Result:', JSON.stringify(result, null, 2));
|
|
131
|
+
|
|
132
|
+
// Return the result as JSON
|
|
133
|
+
res.json(result);
|
|
134
|
+
} catch (error) {
|
|
135
|
+
log('HTTP input processing error:', error.message);
|
|
136
|
+
|
|
137
|
+
// Return error response
|
|
138
|
+
res.status(500).json({
|
|
139
|
+
error: error.message,
|
|
140
|
+
stack: verbose ? error.stack : undefined
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
{% endif %}
|
|
145
|
+
|
|
146
|
+
{% if atom.doc.features.cli.mcp.ws===true %}
|
|
147
|
+
// WebSocket endpoint (enabled via config: cli.mcp.ws: true)
|
|
148
|
+
// Map to store WebSocket clients
|
|
149
|
+
const wsClients = new Set();
|
|
150
|
+
|
|
151
|
+
app.ws(wsEndpoint, (ws, req) => {
|
|
152
|
+
log('WebSocket connection established');
|
|
153
|
+
wsClients.add(ws);
|
|
154
|
+
|
|
155
|
+
// Handle incoming messages
|
|
156
|
+
ws.on('message', async (message) => {
|
|
157
|
+
log('WebSocket message received:', message);
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
// Parse JSON message
|
|
161
|
+
const data = JSON.parse(message);
|
|
162
|
+
|
|
163
|
+
// Call the Node function
|
|
164
|
+
const result = await Node(data);
|
|
165
|
+
|
|
166
|
+
log('WebSocket message processed successfully');
|
|
167
|
+
log('Result:', JSON.stringify(result, null, 2));
|
|
168
|
+
|
|
169
|
+
// Send result back to client
|
|
170
|
+
ws.send(JSON.stringify(result));
|
|
171
|
+
} catch (error) {
|
|
172
|
+
log('WebSocket message processing error:', error.message);
|
|
173
|
+
|
|
174
|
+
// Send error response
|
|
175
|
+
ws.send(JSON.stringify({
|
|
176
|
+
error: error.message,
|
|
177
|
+
stack: verbose ? error.stack : undefined
|
|
178
|
+
}));
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Handle connection close
|
|
183
|
+
ws.on('close', () => {
|
|
184
|
+
log('WebSocket connection closed');
|
|
185
|
+
wsClients.delete(ws);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// Handle errors
|
|
189
|
+
ws.on('error', (error) => {
|
|
190
|
+
log('WebSocket error:', error.message);
|
|
191
|
+
wsClients.delete(ws);
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
{% endif %}
|
|
195
|
+
|
|
196
|
+
app.listen(port, host, () => {
|
|
197
|
+
console.log(`MCP server started with Streamable HTTP transport`);
|
|
198
|
+
console.log(`MCP endpoint: http://${host}:${port}${mcpEndpoint}`);
|
|
199
|
+
{% if atom.doc.features.cli.mcp.http===true %}
|
|
200
|
+
console.log(`HTTP endpoint: http://${host}:${port}${httpEndpoint}`);
|
|
201
|
+
{% endif %}
|
|
202
|
+
{% if atom.doc.features.cli.mcp.ws===true %}
|
|
203
|
+
console.log(`WebSocket endpoint: ws://${host}:${port}${wsEndpoint}`);
|
|
204
|
+
{% endif %}
|
|
205
|
+
console.log(`Listening on ${host}:${port}`);
|
|
206
|
+
if (verbose) {
|
|
207
|
+
console.log(`Verbose logging enabled`);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
return;
|
|
212
|
+
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{# ============================================================================
|
|
2
|
+
MCP MODE - STDIO TRANSPORT
|
|
3
|
+
============================================================================
|
|
4
|
+
Standard input/output transport for MCP protocol
|
|
5
|
+
============================================================================ #}
|
|
6
|
+
|
|
7
|
+
// Use stdio transport
|
|
8
|
+
transport = new StdioServerTransport();
|
|
9
|
+
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{# ============================================================================
|
|
2
|
+
PIPELINE MODE - IMPORTS
|
|
3
|
+
============================================================================
|
|
4
|
+
No external dependencies needed - uses native Node.js streams
|
|
5
|
+
stdin/stdout are available globally
|
|
6
|
+
============================================================================ #}
|
|
7
|
+
|
|
8
|
+
{# No imports needed for pipeline mode - stdin/stdout are native #}
|
|
9
|
+
|