agent-dir 0.0.0-stage → 0.1.2

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.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +282 -2
  3. package/dist/bin/agent-dir.d.ts +3 -0
  4. package/dist/bin/agent-dir.d.ts.map +1 -0
  5. package/dist/bin/agent-dir.js +201 -0
  6. package/dist/bin/agent-dir.js.map +1 -0
  7. package/dist/src/auth.d.ts +3 -0
  8. package/dist/src/auth.d.ts.map +1 -0
  9. package/dist/src/auth.js +18 -0
  10. package/dist/src/auth.js.map +1 -0
  11. package/dist/src/config.d.ts +6 -0
  12. package/dist/src/config.d.ts.map +1 -0
  13. package/dist/src/config.js +80 -0
  14. package/dist/src/config.js.map +1 -0
  15. package/dist/src/logging.d.ts +16 -0
  16. package/dist/src/logging.d.ts.map +1 -0
  17. package/dist/src/logging.js +243 -0
  18. package/dist/src/logging.js.map +1 -0
  19. package/dist/src/mcp.d.ts +9 -0
  20. package/dist/src/mcp.d.ts.map +1 -0
  21. package/dist/src/mcp.js +866 -0
  22. package/dist/src/mcp.js.map +1 -0
  23. package/dist/src/server.d.ts +11 -0
  24. package/dist/src/server.d.ts.map +1 -0
  25. package/dist/src/server.js +562 -0
  26. package/dist/src/server.js.map +1 -0
  27. package/dist/src/tools/code.d.ts +27 -0
  28. package/dist/src/tools/code.d.ts.map +1 -0
  29. package/dist/src/tools/code.js +147 -0
  30. package/dist/src/tools/code.js.map +1 -0
  31. package/dist/src/tools/commands.d.ts +8 -0
  32. package/dist/src/tools/commands.d.ts.map +1 -0
  33. package/dist/src/tools/commands.js +61 -0
  34. package/dist/src/tools/commands.js.map +1 -0
  35. package/dist/src/tools/diagnostics.d.ts +9 -0
  36. package/dist/src/tools/diagnostics.d.ts.map +1 -0
  37. package/dist/src/tools/diagnostics.js +83 -0
  38. package/dist/src/tools/diagnostics.js.map +1 -0
  39. package/dist/src/tools/files.d.ts +39 -0
  40. package/dist/src/tools/files.d.ts.map +1 -0
  41. package/dist/src/tools/files.js +142 -0
  42. package/dist/src/tools/files.js.map +1 -0
  43. package/dist/src/tools/git.d.ts +15 -0
  44. package/dist/src/tools/git.d.ts.map +1 -0
  45. package/dist/src/tools/git.js +104 -0
  46. package/dist/src/tools/git.js.map +1 -0
  47. package/dist/src/tools/metadata.d.ts +20 -0
  48. package/dist/src/tools/metadata.d.ts.map +1 -0
  49. package/dist/src/tools/metadata.js +101 -0
  50. package/dist/src/tools/metadata.js.map +1 -0
  51. package/dist/src/tools/npm.d.ts +3 -0
  52. package/dist/src/tools/npm.d.ts.map +1 -0
  53. package/dist/src/tools/npm.js +76 -0
  54. package/dist/src/tools/npm.js.map +1 -0
  55. package/dist/src/tools/skills.d.ts +33 -0
  56. package/dist/src/tools/skills.d.ts.map +1 -0
  57. package/dist/src/tools/skills.js +240 -0
  58. package/dist/src/tools/skills.js.map +1 -0
  59. package/dist/src/tunnel.d.ts +3 -0
  60. package/dist/src/tunnel.d.ts.map +1 -0
  61. package/dist/src/tunnel.js +114 -0
  62. package/dist/src/tunnel.js.map +1 -0
  63. package/dist/src/types.d.ts +45 -0
  64. package/dist/src/types.d.ts.map +1 -0
  65. package/dist/src/types.js +2 -0
  66. package/dist/src/types.js.map +1 -0
  67. package/package.json +51 -4
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 agent-dir contributors
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 CHANGED
@@ -1,3 +1,283 @@
1
- # Temporary Holding Version
1
+ <div align="center">
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ <img src="assets/agent-dir-banner.svg" alt="AGENT-DIR — Expose a local project to AI agents through authenticated MCP." width="100%">
4
+
5
+ </div>
6
+
7
+ > **`agent-dir` turns a trusted local project directory into a controlled, authenticated MCP endpoint for AI agents.**
8
+
9
+ `agent-dir` is a cross-platform TypeScript CLI that exposes a local project to an AI agent through an authenticated MCP server. It provides controlled file access, targeted file patches, and explicitly allowlisted development commands, with optional tunneling through [Wormhole](https://wormhole.bar/).
10
+
11
+ > **Security:** this is a remote-control development tool. Only expose directories you trust, keep the authentication token private, and allow only commands you actually need.
12
+
13
+ ## Requirements
14
+
15
+ - Node.js 24 LTS or newer
16
+ - npm
17
+ - Wormhole CLI if remote access is needed
18
+
19
+ Node.js 24 is the supported LTS baseline. The project currently tracks TypeScript 7 and Biome 2.5.
20
+
21
+ ## Quick start
22
+
23
+ ```bash
24
+ npm install -g agent-dir
25
+ agent-dir .
26
+ ```
27
+
28
+ Or run it without a global install:
29
+
30
+ ```bash
31
+ npx agent-dir .
32
+ ```
33
+
34
+ For remote MCP access with Wormhole:
35
+
36
+ ```bash
37
+ agent-dir . --tunnel wormhole --subdomain my-project-x7k4m2
38
+ ```
39
+
40
+ ### Wormhole domains
41
+
42
+ When using a custom Wormhole subdomain, choose a distinctive name such as `my-project-x7k4m2`. Avoid generic names such as `project`, `test`, `dev`, or `scriptr` to reduce collisions and make the public endpoint less predictable.
43
+
44
+ The Wormhole URL is only the transport endpoint. `agent-dir` authentication is enforced by the local HTTP server; Wormhole does not provide the Bearer-token authentication described below.
45
+
46
+ > **Wormhole subdomain limit:** Wormhole limits how many subdomains a user can have registered/active at once. If you see an error such as `Subdomain limit reached (max 3 per user)`, the tunnel is being rejected by Wormhole, not by `agent-dir`. Release an existing Wormhole subdomain or use `--random` to let Wormhole choose a temporary random URL.
47
+ >
48
+ > A subdomain can remain registered while another `wormhole` process is still running, so stop unused Wormhole tunnels before creating another one. If a configured subdomain is unavailable, `agent-dir` will report the Wormhole registration failure instead of silently starting without a tunnel.
49
+
50
+ ## Profiles
51
+
52
+ Profiles save settings you use repeatedly: project directory, tunnel, Wormhole subdomain, port, npm scripts, and allowed non-npm commands.
53
+
54
+ ```bash
55
+ agent-dir config add my-project \
56
+ --directory ~/src/my-project \
57
+ --tunnel wormhole \
58
+ --subdomain my-project-x7k4m2 \
59
+ --npm typecheck,lint,format,test,build \
60
+ --command grep,find,rg,git
61
+ ```
62
+
63
+ Then:
64
+
65
+ ```bash
66
+ agent-dir my-project
67
+ ```
68
+
69
+ Manage profiles with:
70
+
71
+ ```bash
72
+ agent-dir config list
73
+ agent-dir config show my-project
74
+ agent-dir config remove my-project
75
+ ```
76
+
77
+ Profiles are stored per-user at `~/.config/agent-dir/config.json`, not in the project repository. The config directory and file are written with user-only permissions. Command-line options can override saved values for one run.
78
+
79
+ ## MCP transport and compatibility
80
+
81
+ The HTTP MCP endpoint is `POST /mcp`. The implementation supports two protocol compatibility paths:
82
+
83
+ ### Modern stateless MCP
84
+
85
+ The native protocol path uses MCP `2026-07-28`. Requests carry the protocol version and client capabilities in `params._meta`. The server does not require an initialize handshake or `Mcp-Session-Id` for this path.
86
+
87
+ Standard Streamable HTTP requests do **not** need the implementation-specific `MCP-Protocol-Version`, `Mcp-Method`, or `Mcp-Name` headers. If a client sends those optional headers, `agent-dir` validates them against the JSON-RPC request and metadata instead of requiring them.
88
+
89
+ The modern implementation includes:
90
+
91
+ - `server/discover`
92
+ - cursor pagination for list-style methods
93
+ - `subscriptions/listen` for tool, prompt, and resource change events
94
+ - resource subscriptions and filesystem change notifications
95
+ - cache metadata
96
+ - structured tool results with `resultType`
97
+ - `outputSchema` for tools
98
+ - the stable `io.modelcontextprotocol/skills` extension
99
+
100
+ ### Legacy MCP compatibility
101
+
102
+ Clients using the MCP `2025-11-25` initialize-based lifecycle are also supported. A legacy client can:
103
+
104
+ 1. send `initialize` with `params.protocolVersion: "2025-11-25"`, `capabilities`, and `clientInfo`;
105
+ 2. negotiate `2025-11-25`;
106
+ 3. send subsequent requests with `MCP-Protocol-Version: 2025-11-25` without the modern `params._meta` object.
107
+
108
+ This compatibility path is intentionally narrow. It does not weaken the modern protocol validation, and conflicting protocol headers are rejected.
109
+
110
+ The compatibility layer exists for clients such as MCP integrations that still perform the standard `initialize` handshake instead of using the native stateless lifecycle.
111
+
112
+ ### Authentication and protocol troubleshooting
113
+
114
+ Authentication is independent of protocol negotiation. A valid Bearer token is still required before MCP handling:
115
+
116
+ ```http
117
+ Authorization: Bearer <token>
118
+ ```
119
+
120
+ For clients that cannot send an Authorization header, the server also accepts:
121
+
122
+ ```text
123
+ https://your-subdomain.wormhole.bar/mcp?token=<token>
124
+ ```
125
+
126
+ If a client reports that the server needs sign-in, inspect the server's request log before changing credentials. A `400` from MCP can be a protocol compatibility error rather than an authentication failure. Request logs now include the MCP error message and, for JSON-RPC failures, safe diagnostic context such as the method, request id, parameter names, metadata presence, protocol version, and protocol header. Parameter values are not logged.
127
+
128
+ The server log distinguishes protocol/header validation from MCP handler errors. This makes transient client interoperability failures diagnosable without exposing request payloads or secrets.
129
+
130
+ ## MCP tools
131
+
132
+ | Tool | Purpose |
133
+ |---|---|
134
+ | `list_files` | Recursive project discovery |
135
+ | `list_dirs` | Direct directory discovery for one or more directories |
136
+ | `read_range` | Read a bounded line range from one UTF-8 file |
137
+ | `read_files` | Read one or more UTF-8 files in one call |
138
+ | `write_files` | Create or replace one or more files in one call |
139
+ | `patch_files` | Apply targeted text replacements to one or more files |
140
+ | `delete_files` | Delete one or more files in one call |
141
+ | `search_files` / `find_files` | Search file contents or find paths by glob |
142
+ | `search_code` | Search source-like files |
143
+ | `find_symbol` / `find_definition` | Locate likely symbol definitions |
144
+ | `find_references` | Locate symbol references |
145
+ | `find_imports` / `find_exports` | Inspect source dependencies and exports |
146
+ | `git_status` / `git_diff` / `git_log` | Git inspection |
147
+ | `git_stage` / `git_unstage` | Stage or unstage paths |
148
+ | `git_commit` | Commit staged changes |
149
+ | `git_restore` | Restore paths, discarding unstaged changes |
150
+ | `git_push` | Push the current branch to a remote |
151
+ | `project_overview` | Project structure, languages, package managers, and Git state |
152
+ | `package_info` / `file_info` | Project and filesystem metadata |
153
+ | `diagnostics` | Project-independent diagnostics; does not run tests, lint, or typecheck |
154
+ | `run_npm_batch` | Run one or more explicitly allowlisted npm scripts sequentially |
155
+ | `run_command_batch` | Run one or more explicitly allowlisted executables sequentially without a shell |
156
+
157
+ Batch operations execute sequentially and stop on the first failed command. Tool calls return modern `structuredContent` alongside a serialized text representation, and tools that return structured data advertise an `outputSchema`. List-style protocol methods use opaque cursors when more than 50 entries are available.
158
+
159
+ Modern `subscriptions/listen` replaces the legacy GET/SSE notification model. Clients can subscribe to tool, prompt, resource-list, and resource-specific change events; filesystem mutations publish resource-change events to active subscribers.
160
+
161
+ ### Command permissions
162
+
163
+ npm scripts must be explicitly enabled:
164
+
165
+ ```text
166
+ --npm typecheck,lint,format,test,build
167
+ ```
168
+
169
+ Normal executables use a separate allowlist:
170
+
171
+ ```text
172
+ --command grep,find,rg,git
173
+ ```
174
+
175
+ Commands are launched with `shell: false`; the MCP client supplies the executable and arguments separately. An executable that is not in the allowlist is rejected.
176
+
177
+ Avoid allowing `sh`, `bash`, `zsh`, `cmd`, `node`, or `python` unless you intentionally want to grant a much broader execution capability.
178
+
179
+ ## Agent Skills
180
+
181
+ The server implements the stable MCP Skills extension (`io.modelcontextprotocol/skills`) over the standard Resources primitive. It discovers project-local `SKILL.md` files under:
182
+
183
+ ```text
184
+ skills/
185
+ .agents/skills/
186
+ .claude/skills/
187
+ .github/skills/
188
+ ```
189
+
190
+ Skills are exposed through `skills/list`, `skills/get`, `resources/list`, and `resources/read`. Skill entries contain parsed frontmatter plus SHA-256 digests and byte sizes for every served file. Skill manifests enforce the 512-resource and 16 MiB limits. Binary supporting files are returned as MCP blobs. `resources/directory/read` lists direct children of a skill resource directory. The extension advertises `directoryRead: true`.
191
+
192
+ This repository now includes a maintainer-facing compatibility skill at `skills/agent-dir-maintainer/SKILL.md`. It documents the modern and legacy MCP paths, troubleshooting signals, and release/test expectations for agents working on this project.
193
+
194
+ ## Authentication
195
+
196
+ By default, `agent-dir` generates a random Bearer token when the server starts. The token protects both the MCP endpoint and the HTTP file API.
197
+
198
+ Clients should authenticate with:
199
+
200
+ ```http
201
+ Authorization: Bearer <token>
202
+ ```
203
+
204
+ The CLI also supports explicitly configured profile tokens and the `--token` option. There is no `--no-auth` option; authentication cannot be disabled through the CLI. Keep the token secret and do not commit it to a repository or publish it alongside a tunnel URL.
205
+
206
+ For clients that cannot send an `Authorization` header, the HTTP server also accepts the token as a query parameter:
207
+
208
+ ```text
209
+ https://your-subdomain.wormhole.bar/mcp?token=<token>
210
+ ```
211
+
212
+ Query-string tokens may be exposed in URL logs and should be treated as less secure than the Authorization header.
213
+
214
+ ## REST API
215
+
216
+ The MCP server is the primary interface, but the HTTP server also exposes:
217
+
218
+ ```text
219
+ GET /__tree
220
+ GET /path/to/file
221
+ PUT /path/to/file
222
+ DELETE /path/to/file
223
+ POST /mcp
224
+ ```
225
+
226
+ All HTTP endpoints are authenticated by default.
227
+
228
+ ## Contributing
229
+
230
+ Contributions are welcome. See [CONTRIBUTING.md](.github/CONTRIBUTING.md) for development setup, testing requirements, MCP compatibility guidance, and pull-request expectations.
231
+
232
+ Use the GitHub issue templates for bug reports, feature requests, and usage questions. Security vulnerabilities should be reported privately through the process in [SECURITY.md](SECURITY.md), not through a public issue.
233
+
234
+ See [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) for community participation guidelines.
235
+
236
+ ## Development
237
+
238
+ The application source and tests are fully TypeScript. JavaScript is generated into `dist/` for execution and publishing. The published package contains only the built CLI/runtime, README, and license; development sources and tests are excluded from the npm tarball.
239
+
240
+ ```bash
241
+ npm run build
242
+ npm run typecheck
243
+ npm test
244
+ npm run format
245
+ npm run lint
246
+ npm run check
247
+ ```
248
+
249
+ `npm run check` runs Biome plus TypeScript. Before publishing:
250
+
251
+ ```bash
252
+ npm run check
253
+ npm test
254
+ npm pack --dry-run
255
+ ```
256
+
257
+ Review the `npm pack --dry-run` file list before publishing to confirm no local configuration, credentials, source-only files, or development artifacts are included.
258
+
259
+ ## Toolchain
260
+
261
+ - **Node.js:** 24 LTS baseline
262
+ - **TypeScript:** 7.x
263
+ - **Biome:** 2.5.x
264
+ - **Module system:** native Node ESM with `NodeNext`
265
+ - **Formatting/linting:** Biome with strict recommended rules and import organization
266
+
267
+ The TypeScript configuration uses strict checking, exact optional properties, unchecked indexed access, isolated modules, explicit Node typings, and consistent module resolution.
268
+
269
+ ## Security model
270
+
271
+ File access is rooted at the shared directory and resolves existing paths through their real filesystem targets, preventing symlinks from escaping the exposed root. HTTP request bodies are limited to 10 MiB. npm scripts and external executables use explicit allowlists, and external commands are not passed through a shell.
272
+
273
+ Because file writes, deletion, command execution, and Git write operations can modify a project or remote repository, expose only directories and capabilities you intend an AI agent to control. Git write tools are intentionally explicit: staging, unstaging, committing, restoring, and pushing are separate operations. `git_restore` discards unstaged changes, and `git_push` can modify a remote repository. If you do not want Git mutation, do not use the Git write tools and do not allow `git` through the generic command allowlist.
274
+
275
+ The diagnostics tool is deliberately project-independent. It checks conditions such as invalid JSON, broken symlinks, and unresolved merge-conflict markers instead of assuming a particular test runner, linter, compiler, or package ecosystem. Never share directories containing credentials, SSH keys, private certificates, production secrets, or unrelated personal data.
276
+
277
+ ## Credits
278
+
279
+ Remote tunneling support is provided through [Wormhole](https://wormhole.bar/), a project of the Wormhole team. `agent-dir` invokes the Wormhole CLI and does not provide the tunneling service itself.
280
+
281
+ ## License
282
+
283
+ MIT
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=agent-dir.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-dir.d.ts","sourceRoot":"","sources":["../../bin/agent-dir.ts"],"names":[],"mappings":""}
@@ -0,0 +1,201 @@
1
+ #!/usr/bin/env node
2
+ import { randomBytes } from "node:crypto";
3
+ import { resolve } from "node:path";
4
+ import { parseArgs } from "node:util";
5
+ import { configPath, loadConfig, mergeProfile, saveConfig } from "../src/config.js";
6
+ import { printBanner, printHelp, printRequestHeader } from "../src/logging.js";
7
+ import { startServer } from "../src/server.js";
8
+ import { startTunnel } from "../src/tunnel.js";
9
+ function fail(message) {
10
+ console.error(`Error: ${message}`);
11
+ process.exit(1);
12
+ }
13
+ function parseList(value) {
14
+ if (value === undefined)
15
+ return undefined;
16
+ return value
17
+ .split(",")
18
+ .map((item) => item.trim())
19
+ .filter(Boolean);
20
+ }
21
+ function parsePort(value, fallback) {
22
+ const port = Number(value ?? fallback);
23
+ if (!Number.isInteger(port) || port < 1 || port > 65_535) {
24
+ fail("port must be an integer between 1 and 65535.");
25
+ }
26
+ return port;
27
+ }
28
+ const { values, positionals } = parseArgs({
29
+ options: {
30
+ help: { type: "boolean", short: "h" },
31
+ directory: { type: "string", short: "d" },
32
+ port: { type: "string", short: "p" },
33
+ tunnel: { type: "string", short: "t" },
34
+ subdomain: { type: "string", short: "s" },
35
+ npm: { type: "string" },
36
+ command: { type: "string" },
37
+ token: { type: "string" },
38
+ "no-tunnel": { type: "boolean" },
39
+ random: { type: "boolean" },
40
+ },
41
+ allowPositionals: true,
42
+ strict: true,
43
+ });
44
+ if (values.help) {
45
+ printHelp();
46
+ process.exit(0);
47
+ }
48
+ const config = await loadConfig();
49
+ const command = positionals[0];
50
+ if (command === "config") {
51
+ const action = positionals[1];
52
+ if (action === "list") {
53
+ const names = Object.keys(config.profiles);
54
+ console.log(names.length ? names.join("\n") : "No profiles configured.");
55
+ process.exit(0);
56
+ }
57
+ if (action === "show") {
58
+ const name = positionals[2];
59
+ if (!name || !config.profiles[name])
60
+ fail(`Profile not found: ${name}`);
61
+ const profile = structuredClone(config.profiles[name]);
62
+ if (profile.token)
63
+ profile.token = "<configured>";
64
+ console.log(JSON.stringify(profile, null, 2));
65
+ process.exit(0);
66
+ }
67
+ if (action === "remove") {
68
+ const name = positionals[2];
69
+ if (!name || !config.profiles[name])
70
+ fail(`Profile not found: ${name}`);
71
+ delete config.profiles[name];
72
+ await saveConfig(config);
73
+ console.log(`✓ Removed profile '${name}'.`);
74
+ process.exit(0);
75
+ }
76
+ if (action === "token") {
77
+ const name = positionals[2];
78
+ if (!name || !config.profiles[name])
79
+ fail(`Profile not found: ${name}`);
80
+ config.profiles[name].token = randomBytes(24).toString("hex");
81
+ await saveConfig(config);
82
+ console.log(`✓ Rotated token for '${name}'.`);
83
+ console.log(` Config: ${configPath()}`);
84
+ process.exit(0);
85
+ }
86
+ if (action === "add") {
87
+ const name = positionals[2];
88
+ if (!name)
89
+ fail("Usage: agent-dir config add <name> [options]");
90
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(name))
91
+ fail("Profile names may contain letters, numbers, dots, underscores, and hyphens.");
92
+ const tunnel = values.tunnel ?? "none";
93
+ if (tunnel !== "none" && tunnel !== "wormhole")
94
+ fail(`Unsupported tunnel provider: ${tunnel}`);
95
+ const profile = {
96
+ directory: resolve(values.directory ?? "."),
97
+ port: parsePort(values.port, 3002),
98
+ tunnel,
99
+ token: values.token ?? randomBytes(24).toString("hex"),
100
+ };
101
+ if (values.subdomain)
102
+ profile.subdomain = values.subdomain;
103
+ const npm = parseList(values.npm);
104
+ if (npm !== undefined)
105
+ profile.npm = { allowedScripts: npm };
106
+ const commands = parseList(values.command);
107
+ if (commands !== undefined)
108
+ profile.commands = commands;
109
+ if (profile.tunnel === "wormhole" && !profile.subdomain && !values.random) {
110
+ fail("Wormhole profiles require --subdomain <name>, or use --random.");
111
+ }
112
+ config.profiles[name] = profile;
113
+ await saveConfig(config);
114
+ console.log(`✓ Saved profile '${name}'.`);
115
+ console.log(` Config: ${configPath()}`);
116
+ process.exit(0);
117
+ }
118
+ fail("Usage: agent-dir config {add|list|show|remove|token}");
119
+ }
120
+ const profile = command ? config.profiles[command] : undefined;
121
+ if (command && command !== "config" && !profile && command.startsWith("-")) {
122
+ fail(`Unknown command: ${command}`);
123
+ }
124
+ const positionalDirectory = profile ? positionals[1] : positionals[0];
125
+ const directory = resolve(values.directory ?? profile?.directory ?? positionalDirectory ?? ".");
126
+ const port = parsePort(values.port, profile?.port ?? 3002);
127
+ const tunnelValue = values["no-tunnel"] ? "none" : (values.tunnel ?? profile?.tunnel ?? "none");
128
+ if (tunnelValue !== "none" && tunnelValue !== "wormhole") {
129
+ fail(`Unsupported tunnel provider: ${tunnelValue}`);
130
+ }
131
+ const tunnel = tunnelValue;
132
+ const randomTunnel = values.random === true;
133
+ const subdomain = randomTunnel ? undefined : (values.subdomain ?? profile?.subdomain);
134
+ if (tunnel === "wormhole" && !subdomain && !randomTunnel) {
135
+ fail("Wormhole requires --subdomain <name>, or use --random.");
136
+ }
137
+ if (randomTunnel && tunnel === "none") {
138
+ fail("--random requires --tunnel wormhole.");
139
+ }
140
+ const token = values.token ?? profile?.token ?? randomBytes(24).toString("hex");
141
+ const npm = parseList(values.npm);
142
+ const commands = parseList(values.command);
143
+ const overrides = {};
144
+ if (npm !== undefined)
145
+ overrides.npm = { allowedScripts: npm };
146
+ if (commands !== undefined)
147
+ overrides.commands = commands;
148
+ const commandConfig = mergeProfile(profile ?? { directory, port, tunnel }, overrides);
149
+ const bannerOptions = {
150
+ root: directory,
151
+ port,
152
+ tunnel,
153
+ token,
154
+ };
155
+ const npmScripts = commandConfig.npm?.allowedScripts;
156
+ const allowedCommands = commandConfig.commands;
157
+ if (profile && command)
158
+ bannerOptions.profileName = command;
159
+ if (subdomain)
160
+ bannerOptions.subdomain = subdomain;
161
+ if (npmScripts)
162
+ bannerOptions.npmScripts = npmScripts;
163
+ if (allowedCommands)
164
+ bannerOptions.commands = allowedCommands;
165
+ printBanner(bannerOptions);
166
+ const server = await startServer({ root: directory, port, token, commandConfig });
167
+ let tunnelResult;
168
+ console.log(" ✓ SERVER ONLINE");
169
+ console.log(` Local target : http://127.0.0.1:${port}`);
170
+ console.log(" Auth : Bearer token");
171
+ console.log(` Token : ${token}`);
172
+ if (tunnel !== "none") {
173
+ try {
174
+ tunnelResult = await startTunnel({
175
+ provider: "wormhole",
176
+ port,
177
+ random: randomTunnel,
178
+ ...(subdomain && !randomTunnel ? { subdomain } : {}),
179
+ });
180
+ }
181
+ catch (error) {
182
+ console.error(` ✖ TUNNEL ERROR ${error instanceof Error ? error.message : String(error)}`);
183
+ await server.close();
184
+ process.exit(1);
185
+ }
186
+ }
187
+ printRequestHeader();
188
+ let shuttingDown = false;
189
+ const shutdown = async () => {
190
+ if (shuttingDown)
191
+ return;
192
+ shuttingDown = true;
193
+ console.log("\n Stopping agent-dir...");
194
+ if (tunnelResult?.child && !tunnelResult.child.killed)
195
+ tunnelResult.child.kill("SIGTERM");
196
+ await server.close();
197
+ process.exit(0);
198
+ };
199
+ process.on("SIGINT", shutdown);
200
+ process.on("SIGTERM", shutdown);
201
+ //# sourceMappingURL=agent-dir.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-dir.js","sourceRoot":"","sources":["../../bin/agent-dir.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACpF,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,SAAS,IAAI,CAAC,OAAe;IAC3B,OAAO,CAAC,KAAK,CAAC,UAAU,OAAO,EAAE,CAAC,CAAC;IACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,SAAS,SAAS,CAAC,KAAyB;IAC1C,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,OAAO,KAAK;SACT,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,OAAO,CAAC,CAAC;AACrB,CAAC;AAED,SAAS,SAAS,CAAC,KAAyB,EAAE,QAAgB;IAC5D,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,IAAI,QAAQ,CAAC,CAAC;IACvC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,MAAM,EAAE,CAAC;QACzD,IAAI,CAAC,8CAA8C,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;IACxC,OAAO,EAAE;QACP,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;QACrC,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE;QACzC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE;QACpC,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE;QACtC,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE;QACzC,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACvB,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC3B,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACzB,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;QAChC,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;KAC5B;IACD,gBAAgB,EAAE,IAAI;IACtB,MAAM,EAAE,IAAI;CACb,CAAC,CAAC;AAEH,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;IAChB,SAAS,EAAE,CAAC;IACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;AAClC,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;AAE/B,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;IACzB,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IAE9B,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC;QACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,IAAI,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAC;QACxE,MAAM,OAAO,GAAG,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QACvD,IAAI,OAAO,CAAC,KAAK;YAAE,OAAO,CAAC,KAAK,GAAG,cAAc,CAAC;QAClD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,IAAI,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAC;QACxE,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,UAAU,CAAC,MAAM,CAAC,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,IAAI,CAAC,CAAC;QAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,IAAI,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAC;QACxE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC9D,MAAM,UAAU,CAAC,MAAM,CAAC,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,IAAI,CAAC,CAAC;QAC9C,OAAO,CAAC,GAAG,CAAC,aAAa,UAAU,EAAE,EAAE,CAAC,CAAC;QACzC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;QACrB,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,CAAC,IAAI;YAAE,IAAI,CAAC,8CAA8C,CAAC,CAAC;QAChE,IAAI,CAAC,8BAA8B,CAAC,IAAI,CAAC,IAAI,CAAC;YAC5C,IAAI,CAAC,6EAA6E,CAAC,CAAC;QAEtF,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC;QACvC,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,UAAU;YAAE,IAAI,CAAC,gCAAgC,MAAM,EAAE,CAAC,CAAC;QAE/F,MAAM,OAAO,GAAY;YACvB,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,GAAG,CAAC;YAC3C,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC;YAClC,MAAM;YACN,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;SACvD,CAAC;QAEF,IAAI,MAAM,CAAC,SAAS;YAAE,OAAO,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QAC3D,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,CAAC,GAAG,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC;QAC7D,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC3C,IAAI,QAAQ,KAAK,SAAS;YAAE,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAExD,IAAI,OAAO,CAAC,MAAM,KAAK,UAAU,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YAC1E,IAAI,CAAC,gEAAgE,CAAC,CAAC;QACzE,CAAC;QAED,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;QAChC,MAAM,UAAU,CAAC,MAAM,CAAC,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,IAAI,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,aAAa,UAAU,EAAE,EAAE,CAAC,CAAC;QACzC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC,sDAAsD,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC/D,IAAI,OAAO,IAAI,OAAO,KAAK,QAAQ,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;IAC3E,IAAI,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,mBAAmB,GAAG,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACtE,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,OAAO,EAAE,SAAS,IAAI,mBAAmB,IAAI,GAAG,CAAC,CAAC;AAChG,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,IAAI,IAAI,CAAC,CAAC;AAC3D,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,IAAI,OAAO,EAAE,MAAM,IAAI,MAAM,CAAC,CAAC;AAChG,IAAI,WAAW,KAAK,MAAM,IAAI,WAAW,KAAK,UAAU,EAAE,CAAC;IACzD,IAAI,CAAC,gCAAgC,WAAW,EAAE,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,MAAM,GAAsB,WAAW,CAAC;AAC9C,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,KAAK,IAAI,CAAC;AAC5C,MAAM,SAAS,GAAG,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,IAAI,OAAO,EAAE,SAAS,CAAC,CAAC;AACtF,IAAI,MAAM,KAAK,UAAU,IAAI,CAAC,SAAS,IAAI,CAAC,YAAY,EAAE,CAAC;IACzD,IAAI,CAAC,wDAAwD,CAAC,CAAC;AACjE,CAAC;AACD,IAAI,YAAY,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;IACtC,IAAI,CAAC,sCAAsC,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,OAAO,EAAE,KAAK,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAChF,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAClC,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AAC3C,MAAM,SAAS,GAAkB,EAAE,CAAC;AACpC,IAAI,GAAG,KAAK,SAAS;IAAE,SAAS,CAAC,GAAG,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC;AAC/D,IAAI,QAAQ,KAAK,SAAS;IAAE,SAAS,CAAC,QAAQ,GAAG,QAAQ,CAAC;AAC1D,MAAM,aAAa,GAAG,YAAY,CAAC,OAAO,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,SAAS,CAAC,CAAC;AAEtF,MAAM,aAAa,GAAsC;IACvD,IAAI,EAAE,SAAS;IACf,IAAI;IACJ,MAAM;IACN,KAAK;CACN,CAAC;AAEF,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,EAAE,cAAc,CAAC;AACrD,MAAM,eAAe,GAAG,aAAa,CAAC,QAAQ,CAAC;AAE/C,IAAI,OAAO,IAAI,OAAO;IAAE,aAAa,CAAC,WAAW,GAAG,OAAO,CAAC;AAC5D,IAAI,SAAS;IAAE,aAAa,CAAC,SAAS,GAAG,SAAS,CAAC;AACnD,IAAI,UAAU;IAAE,aAAa,CAAC,UAAU,GAAG,UAAU,CAAC;AACtD,IAAI,eAAe;IAAE,aAAa,CAAC,QAAQ,GAAG,eAAe,CAAC;AAE9D,WAAW,CAAC,aAAa,CAAC,CAAC;AAE3B,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC;AAClF,IAAI,YAAsC,CAAC;AAC3C,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;AACjC,OAAO,CAAC,GAAG,CAAC,uCAAuC,IAAI,EAAE,CAAC,CAAC;AAC3D,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;AAC/C,OAAO,CAAC,GAAG,CAAC,sBAAsB,KAAK,EAAE,CAAC,CAAC;AAE3C,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;IACtB,IAAI,CAAC;QACH,YAAY,GAAG,MAAM,WAAW,CAAC;YAC/B,QAAQ,EAAE,UAAU;YACpB,IAAI;YACJ,MAAM,EAAE,YAAY;YACpB,GAAG,CAAC,SAAS,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACrD,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,qBAAqB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC7F,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,kBAAkB,EAAE,CAAC;AAErB,IAAI,YAAY,GAAG,KAAK,CAAC;AAEzB,MAAM,QAAQ,GAAG,KAAK,IAAmB,EAAE;IACzC,IAAI,YAAY;QAAE,OAAO;IACzB,YAAY,GAAG,IAAI,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IACzC,IAAI,YAAY,EAAE,KAAK,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM;QAAE,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC1F,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC;AAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function authenticate(request: Request, token: string): boolean;
2
+ export declare function unauthorized(): Response;
3
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAMrE;AAED,wBAAgB,YAAY,IAAI,QAAQ,CASvC"}
@@ -0,0 +1,18 @@
1
+ export function authenticate(request, token) {
2
+ const authorization = request.headers.get("authorization");
3
+ if (authorization === `Bearer ${token}`)
4
+ return true;
5
+ const url = new URL(request.url);
6
+ return url.searchParams.get("token") === token;
7
+ }
8
+ export function unauthorized() {
9
+ return new Response(JSON.stringify({ error: "Unauthorized" }), {
10
+ status: 401,
11
+ headers: {
12
+ "content-type": "application/json; charset=utf-8",
13
+ "www-authenticate": "Bearer",
14
+ "cache-control": "no-store",
15
+ },
16
+ });
17
+ }
18
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,YAAY,CAAC,OAAgB,EAAE,KAAa;IAC1D,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAC3D,IAAI,aAAa,KAAK,UAAU,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAErD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACjC,OAAO,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,EAAE;QAC7D,MAAM,EAAE,GAAG;QACX,OAAO,EAAE;YACP,cAAc,EAAE,iCAAiC;YACjD,kBAAkB,EAAE,QAAQ;YAC5B,eAAe,EAAE,UAAU;SAC5B;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { AgentConfig, CommandConfig, Profile } from "./types.js";
2
+ export declare function loadConfig(): Promise<AgentConfig>;
3
+ export declare function saveConfig(config: AgentConfig): Promise<void>;
4
+ export declare function configPath(): string;
5
+ export declare function mergeProfile(profile: Profile, overrides?: CommandConfig): CommandConfig;
6
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAUtE,wBAAsB,UAAU,IAAI,OAAO,CAAC,WAAW,CAAC,CASvD;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAOnE;AAED,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,GAAE,aAAkB,GAAG,aAAa,CAM3F"}
@@ -0,0 +1,80 @@
1
+ import { chmod, mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { dirname, join } from "node:path";
4
+ const CONFIG_DIR = join(homedir(), ".config", "agent-dir");
5
+ const CONFIG_FILE = join(CONFIG_DIR, "config.json");
6
+ const DEFAULT_CONFIG = { version: 1, profiles: {} };
7
+ export async function loadConfig() {
8
+ try {
9
+ const parsed = JSON.parse(await readFile(CONFIG_FILE, "utf8"));
10
+ if (!isAgentConfig(parsed))
11
+ throw new Error("Invalid configuration format.");
12
+ return parsed;
13
+ }
14
+ catch (error) {
15
+ if (error.code === "ENOENT")
16
+ return structuredClone(DEFAULT_CONFIG);
17
+ throw new Error(`Unable to read config ${CONFIG_FILE}: ${error.message}`);
18
+ }
19
+ }
20
+ export async function saveConfig(config) {
21
+ await mkdir(dirname(CONFIG_FILE), { recursive: true, mode: 0o700 });
22
+ await writeFile(CONFIG_FILE, `${JSON.stringify(config, null, 2)}\n`, {
23
+ encoding: "utf8",
24
+ mode: 0o600,
25
+ });
26
+ await chmod(CONFIG_FILE, 0o600);
27
+ }
28
+ export function configPath() {
29
+ return CONFIG_FILE;
30
+ }
31
+ export function mergeProfile(profile, overrides = {}) {
32
+ return {
33
+ ...profile,
34
+ ...overrides,
35
+ npm: { ...(profile.npm ?? { allowedScripts: [] }), ...(overrides.npm ?? {}) },
36
+ };
37
+ }
38
+ function isAgentConfig(value) {
39
+ if (!value || typeof value !== "object")
40
+ return false;
41
+ const config = value;
42
+ if (config.version !== 1 || !config.profiles || typeof config.profiles !== "object")
43
+ return false;
44
+ for (const [name, profile] of Object.entries(config.profiles)) {
45
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(name) || !isProfile(profile))
46
+ return false;
47
+ }
48
+ return true;
49
+ }
50
+ function isProfile(value) {
51
+ if (!value || typeof value !== "object")
52
+ return false;
53
+ const profile = value;
54
+ const port = profile.port;
55
+ if (typeof profile.directory !== "string" || typeof port !== "number" || !Number.isInteger(port))
56
+ return false;
57
+ if (port < 1 || port > 65_535)
58
+ return false;
59
+ if (profile.tunnel !== "none" && profile.tunnel !== "wormhole")
60
+ return false;
61
+ if (profile.subdomain !== undefined && typeof profile.subdomain !== "string")
62
+ return false;
63
+ if (profile.token !== undefined && typeof profile.token !== "string")
64
+ return false;
65
+ if (profile.npm !== undefined) {
66
+ if (!profile.npm || typeof profile.npm !== "object")
67
+ return false;
68
+ const npm = profile.npm;
69
+ if (!Array.isArray(npm.allowedScripts) ||
70
+ npm.allowedScripts.some((item) => typeof item !== "string"))
71
+ return false;
72
+ }
73
+ if (profile.commands !== undefined) {
74
+ if (!Array.isArray(profile.commands) ||
75
+ profile.commands.some((item) => typeof item !== "string"))
76
+ return false;
77
+ }
78
+ return true;
79
+ }
80
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"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"}