@masculinecache/warp-axi 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +45 -2
- package/dist/bin/warp-axi.d.ts +2 -0
- package/dist/bin/warp-axi.js +16 -0
- package/dist/src/args.d.ts +6 -0
- package/dist/src/args.js +56 -0
- package/dist/src/cli.d.ts +22 -0
- package/dist/src/cli.js +68 -0
- package/dist/src/commands/connect.d.ts +3 -0
- package/dist/src/commands/connect.js +50 -0
- package/dist/src/commands/debug.d.ts +2 -0
- package/dist/src/commands/debug.js +83 -0
- package/dist/src/commands/registration.d.ts +2 -0
- package/dist/src/commands/registration.js +111 -0
- package/dist/src/commands/settings.d.ts +2 -0
- package/dist/src/commands/settings.js +65 -0
- package/dist/src/commands/status.d.ts +2 -0
- package/dist/src/commands/status.js +89 -0
- package/dist/src/commands/target.d.ts +2 -0
- package/dist/src/commands/target.js +83 -0
- package/dist/src/commands/tunnel.d.ts +2 -0
- package/dist/src/commands/tunnel.js +112 -0
- package/dist/src/commands/vnet.d.ts +2 -0
- package/dist/src/commands/vnet.js +106 -0
- package/dist/src/errors.d.ts +2 -0
- package/dist/src/errors.js +2 -0
- package/dist/src/format.d.ts +8 -0
- package/dist/src/format.js +16 -0
- package/dist/src/list.d.ts +11 -0
- package/dist/src/list.js +17 -0
- package/dist/src/stdin.d.ts +2 -0
- package/dist/src/stdin.js +12 -0
- package/dist/src/toon.d.ts +24 -0
- package/dist/src/toon.js +140 -0
- package/dist/src/util.d.ts +2 -0
- package/dist/src/util.js +17 -0
- package/dist/src/version.d.ts +1 -0
- package/dist/src/version.js +22 -0
- package/dist/src/warp.d.ts +19 -0
- package/dist/src/warp.js +131 -0
- package/package.json +54 -4
- package/skills/warp-axi/SKILL.md +74 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 masculinecache
|
|
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,46 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @masculinecache/warp-axi
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Agent-ergonomic TOON wrapper for the Cloudflare WARP CLI (`warp-cli`).
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @masculinecache/warp-axi
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
warp-axi status # Connection status
|
|
15
|
+
warp-axi status --detail # Detailed status with account info
|
|
16
|
+
warp-axi connect # Connect to WARP
|
|
17
|
+
warp-axi disconnect # Disconnect from WARP
|
|
18
|
+
warp-axi registration show # Show registration state
|
|
19
|
+
warp-axi registration new --org X # Register with organization
|
|
20
|
+
warp-axi tunnel dump # Split tunnel routes
|
|
21
|
+
warp-axi tunnel stats # Tunnel statistics
|
|
22
|
+
warp-axi settings # Client settings
|
|
23
|
+
warp-axi debug network # Network diagnostics
|
|
24
|
+
warp-axi vnet list # Virtual networks
|
|
25
|
+
warp-axi target list # Infrastructure targets
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Exit codes
|
|
29
|
+
|
|
30
|
+
| Code | Meaning |
|
|
31
|
+
|------|---------|
|
|
32
|
+
| 0 | Success |
|
|
33
|
+
| 1 | General error |
|
|
34
|
+
| 2 | WARP not installed |
|
|
35
|
+
|
|
36
|
+
## MDM headless enrollment
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
warp-axi registration new --org <team> --token <service-token>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Service tokens are created in Zero Trust → Settings → Devices → Service Tokens.
|
|
43
|
+
|
|
44
|
+
## License
|
|
45
|
+
|
|
46
|
+
MIT
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { run } from "../src/cli.js";
|
|
3
|
+
import { exitCodeForError } from "../src/errors.js";
|
|
4
|
+
const argv = process.argv.slice(2);
|
|
5
|
+
const cwd = process.cwd();
|
|
6
|
+
run(argv, undefined, cwd)
|
|
7
|
+
.then(({ stdout, exitCode }) => {
|
|
8
|
+
if (stdout)
|
|
9
|
+
process.stdout.write(stdout + "\n");
|
|
10
|
+
process.exitCode = exitCode;
|
|
11
|
+
})
|
|
12
|
+
.catch((err) => {
|
|
13
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
14
|
+
process.stderr.write(`warp-axi: ${message}\n`);
|
|
15
|
+
process.exitCode = exitCodeForError(err);
|
|
16
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function takeFlag(args: string[], flag: string): string | undefined;
|
|
2
|
+
export declare function takeBoolFlag(args: string[], flag: string): boolean;
|
|
3
|
+
export declare function takeAllFlags(args: string[], flags: string[]): string[];
|
|
4
|
+
export declare function hasFlag(args: string[], flag: string): boolean;
|
|
5
|
+
export declare function getFlag(args: string[], name: string): string | undefined;
|
|
6
|
+
export declare function getPositional(args: string[], startIdx: number): string | undefined;
|
package/dist/src/args.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export function takeFlag(args, flag) {
|
|
2
|
+
const eqFlag = `--${flag}=`;
|
|
3
|
+
const idx = args.findIndex((a) => a === `--${flag}` || a.startsWith(eqFlag));
|
|
4
|
+
if (idx === -1)
|
|
5
|
+
return undefined;
|
|
6
|
+
const arg = args[idx];
|
|
7
|
+
if (arg.startsWith(eqFlag)) {
|
|
8
|
+
args.splice(idx, 1);
|
|
9
|
+
return arg.slice(eqFlag.length);
|
|
10
|
+
}
|
|
11
|
+
const value = args[idx + 1];
|
|
12
|
+
if (value === undefined || value.startsWith("--")) {
|
|
13
|
+
args.splice(idx, 1);
|
|
14
|
+
return "";
|
|
15
|
+
}
|
|
16
|
+
args.splice(idx, 2);
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
export function takeBoolFlag(args, flag) {
|
|
20
|
+
const idx = args.indexOf(`--${flag}`);
|
|
21
|
+
if (idx === -1)
|
|
22
|
+
return false;
|
|
23
|
+
args.splice(idx, 1);
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
export function takeAllFlags(args, flags) {
|
|
27
|
+
const taken = [];
|
|
28
|
+
for (const flag of flags) {
|
|
29
|
+
const idx = args.indexOf(`--${flag}`);
|
|
30
|
+
if (idx !== -1) {
|
|
31
|
+
taken.push(flag);
|
|
32
|
+
args.splice(idx, 1);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return taken;
|
|
36
|
+
}
|
|
37
|
+
export function hasFlag(args, flag) {
|
|
38
|
+
return args.includes(`--${flag}`);
|
|
39
|
+
}
|
|
40
|
+
export function getFlag(args, name) {
|
|
41
|
+
const eqFlag = `--${name}=`;
|
|
42
|
+
const idx = args.findIndex((a) => a === `--${name}` || a.startsWith(eqFlag));
|
|
43
|
+
if (idx === -1)
|
|
44
|
+
return undefined;
|
|
45
|
+
const arg = args[idx];
|
|
46
|
+
if (arg.startsWith(eqFlag))
|
|
47
|
+
return arg.slice(eqFlag.length);
|
|
48
|
+
return args[idx + 1];
|
|
49
|
+
}
|
|
50
|
+
export function getPositional(args, startIdx) {
|
|
51
|
+
for (let i = startIdx; i < args.length; i++) {
|
|
52
|
+
if (!args[i].startsWith("--"))
|
|
53
|
+
return args[i];
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { WarpRunner, callWarp, callWarpLenient } from "./warp.js";
|
|
2
|
+
import { AxiError, exitCodeForError } from "./errors.js";
|
|
3
|
+
export interface CommandContext {
|
|
4
|
+
runner: WarpRunner;
|
|
5
|
+
cwd?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface CommandArea {
|
|
8
|
+
name: string;
|
|
9
|
+
aliases?: string[];
|
|
10
|
+
description: string;
|
|
11
|
+
help: string[];
|
|
12
|
+
run(ctx: CommandContext, args: string[]): Promise<{
|
|
13
|
+
stdout: string;
|
|
14
|
+
exitCode: number;
|
|
15
|
+
}>;
|
|
16
|
+
}
|
|
17
|
+
declare const areas: CommandArea[];
|
|
18
|
+
export declare function run(argv: string[], runner?: WarpRunner, cwd?: string): Promise<{
|
|
19
|
+
stdout: string;
|
|
20
|
+
exitCode: number;
|
|
21
|
+
}>;
|
|
22
|
+
export { areas, AxiError, exitCodeForError, callWarp, callWarpLenient };
|
package/dist/src/cli.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { realRunner, callWarp, callWarpLenient } from "./warp.js";
|
|
2
|
+
import { AxiError, exitCodeForError } from "./errors.js";
|
|
3
|
+
import { wantsHelp } from "./util.js";
|
|
4
|
+
import { readPackageVersion } from "./version.js";
|
|
5
|
+
import { statusArea } from "./commands/status.js";
|
|
6
|
+
import { registrationArea } from "./commands/registration.js";
|
|
7
|
+
import { connectArea, disconnectArea } from "./commands/connect.js";
|
|
8
|
+
import { tunnelArea } from "./commands/tunnel.js";
|
|
9
|
+
import { settingsArea } from "./commands/settings.js";
|
|
10
|
+
import { debugArea } from "./commands/debug.js";
|
|
11
|
+
import { vnetArea } from "./commands/vnet.js";
|
|
12
|
+
import { targetArea } from "./commands/target.js";
|
|
13
|
+
const areas = [
|
|
14
|
+
statusArea,
|
|
15
|
+
registrationArea,
|
|
16
|
+
connectArea,
|
|
17
|
+
disconnectArea,
|
|
18
|
+
tunnelArea,
|
|
19
|
+
settingsArea,
|
|
20
|
+
debugArea,
|
|
21
|
+
vnetArea,
|
|
22
|
+
targetArea,
|
|
23
|
+
];
|
|
24
|
+
function resolveArea(name) {
|
|
25
|
+
return areas.find((a) => a.name === name || (a.aliases && a.aliases.includes(name)));
|
|
26
|
+
}
|
|
27
|
+
function renderTopLevelHelp() {
|
|
28
|
+
const lines = [
|
|
29
|
+
`bin: warp-axi`,
|
|
30
|
+
`description: Agent-ergonomic wrapper for Cloudflare WARP CLI (warp-cli)`,
|
|
31
|
+
``,
|
|
32
|
+
];
|
|
33
|
+
areas.forEach((a, i) => {
|
|
34
|
+
lines.push(`help[${i}]:`);
|
|
35
|
+
lines.push(` ${a.name.padEnd(14)}${a.description}`);
|
|
36
|
+
});
|
|
37
|
+
lines.push(``, `help[${areas.length}]:`, ` --help Show this help`, ` --version Show version`);
|
|
38
|
+
return lines.join("\n");
|
|
39
|
+
}
|
|
40
|
+
export async function run(argv, runner, cwd) {
|
|
41
|
+
const ctx = { runner: runner ?? realRunner(), cwd };
|
|
42
|
+
if (argv.length === 0) {
|
|
43
|
+
return { stdout: renderTopLevelHelp(), exitCode: 0 };
|
|
44
|
+
}
|
|
45
|
+
if (argv.length === 1 && wantsHelp(argv)) {
|
|
46
|
+
return { stdout: renderTopLevelHelp(), exitCode: 0 };
|
|
47
|
+
}
|
|
48
|
+
const [first, ...rest] = argv;
|
|
49
|
+
if (first === "--version" || first === "-V") {
|
|
50
|
+
const version = await readPackageVersion();
|
|
51
|
+
return { stdout: version, exitCode: 0 };
|
|
52
|
+
}
|
|
53
|
+
const area = resolveArea(first);
|
|
54
|
+
if (!area) {
|
|
55
|
+
return {
|
|
56
|
+
stdout: `warp-axi: unknown command '${first}'. Run 'warp-axi --help' for available commands.`,
|
|
57
|
+
exitCode: 1,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (rest.length > 0 && wantsHelp(rest)) {
|
|
61
|
+
return {
|
|
62
|
+
stdout: [`bin: warp-axi ${area.name}`, `description: ${area.description}`, ``, ...area.help].join("\n"),
|
|
63
|
+
exitCode: 0,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return area.run(ctx, rest);
|
|
67
|
+
}
|
|
68
|
+
export { areas, AxiError, exitCodeForError, callWarp, callWarpLenient };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { callWarp } from "../warp.js";
|
|
2
|
+
import { takeBoolFlag } from "../args.js";
|
|
3
|
+
import { wantsHelp, validateFlags } from "../util.js";
|
|
4
|
+
import { renderDetail, renderHelp, field, custom } from "../toon.js";
|
|
5
|
+
const CONN_SCHEMA = {
|
|
6
|
+
status: field("status"),
|
|
7
|
+
protocol: field("protocol"),
|
|
8
|
+
clientIp: custom((item) => {
|
|
9
|
+
const ip = item.warp_enabled ?? item.client_ip;
|
|
10
|
+
return ip ? String(ip) : undefined;
|
|
11
|
+
}),
|
|
12
|
+
serverIp: custom((item) => {
|
|
13
|
+
const ip = item.server_ip ?? item.endpoint;
|
|
14
|
+
return ip ? String(ip) : undefined;
|
|
15
|
+
}),
|
|
16
|
+
};
|
|
17
|
+
export const connectArea = {
|
|
18
|
+
name: "connect",
|
|
19
|
+
description: "Connect to WARP",
|
|
20
|
+
help: [
|
|
21
|
+
"usage: warp-axi connect [--json]",
|
|
22
|
+
"",
|
|
23
|
+
"Establish a WARP connection.",
|
|
24
|
+
],
|
|
25
|
+
async run(ctx, args) {
|
|
26
|
+
if (wantsHelp(args))
|
|
27
|
+
return { stdout: renderHelp(this.help), exitCode: 0 };
|
|
28
|
+
const useJson = takeBoolFlag(args, "--json");
|
|
29
|
+
validateFlags(args, ["--json"], "connect");
|
|
30
|
+
await callWarp(ctx.runner, ["connect"]);
|
|
31
|
+
return { stdout: renderDetail("connect", { status: "connecting" }, CONN_SCHEMA), exitCode: 0 };
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
export const disconnectArea = {
|
|
35
|
+
name: "disconnect",
|
|
36
|
+
description: "Disconnect from WARP",
|
|
37
|
+
help: [
|
|
38
|
+
"usage: warp-axi disconnect [--json]",
|
|
39
|
+
"",
|
|
40
|
+
"Disconnect the WARP connection.",
|
|
41
|
+
],
|
|
42
|
+
async run(ctx, args) {
|
|
43
|
+
if (wantsHelp(args))
|
|
44
|
+
return { stdout: renderHelp(this.help), exitCode: 0 };
|
|
45
|
+
const useJson = takeBoolFlag(args, "--json");
|
|
46
|
+
validateFlags(args, ["--json"], "disconnect");
|
|
47
|
+
await callWarp(ctx.runner, ["disconnect"]);
|
|
48
|
+
return { stdout: renderDetail("disconnect", { status: "disconnected" }, CONN_SCHEMA), exitCode: 0 };
|
|
49
|
+
},
|
|
50
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { callWarpLenient } from "../warp.js";
|
|
2
|
+
import { hasFlag } from "../args.js";
|
|
3
|
+
import { renderDetail, renderError, renderOutput, field } from "../toon.js";
|
|
4
|
+
const debugSubcommands = ["network", "posture", "connectivity-check"];
|
|
5
|
+
const networkSchema = {
|
|
6
|
+
status: field("status"),
|
|
7
|
+
local_ip: field("local_ip"),
|
|
8
|
+
gateway_ip: field("gateway_ip"),
|
|
9
|
+
dns_server: field("dns_server"),
|
|
10
|
+
interface: field("interface"),
|
|
11
|
+
};
|
|
12
|
+
const postureSchema = {
|
|
13
|
+
status: field("status"),
|
|
14
|
+
compliance_state: field("compliance_state"),
|
|
15
|
+
serial_number: field("serial_number"),
|
|
16
|
+
device_id: field("device_id"),
|
|
17
|
+
};
|
|
18
|
+
const connectivitySchema = {
|
|
19
|
+
result: field("result"),
|
|
20
|
+
summary: field("summary"),
|
|
21
|
+
};
|
|
22
|
+
const fallbackSchema = {
|
|
23
|
+
status: field("status"),
|
|
24
|
+
};
|
|
25
|
+
function renderDebugHelp() {
|
|
26
|
+
return [
|
|
27
|
+
"usage: warp-axi debug <subcommand> [flags]",
|
|
28
|
+
"",
|
|
29
|
+
"Subcommands:",
|
|
30
|
+
" network Network debug info",
|
|
31
|
+
" posture Device posture state",
|
|
32
|
+
" connectivity-check Test connectivity to Cloudflare",
|
|
33
|
+
"",
|
|
34
|
+
"Flags:",
|
|
35
|
+
" --json Raw JSON output",
|
|
36
|
+
" --help Show this help",
|
|
37
|
+
];
|
|
38
|
+
}
|
|
39
|
+
export const debugArea = {
|
|
40
|
+
name: "debug",
|
|
41
|
+
description: "Network, posture, and connectivity diagnostics",
|
|
42
|
+
help: renderDebugHelp(),
|
|
43
|
+
async run(ctx, args) {
|
|
44
|
+
if (args.length === 0) {
|
|
45
|
+
return { stdout: renderDebugHelp().join("\n"), exitCode: 0 };
|
|
46
|
+
}
|
|
47
|
+
const [sub, ...rest] = args;
|
|
48
|
+
if (!debugSubcommands.includes(sub)) {
|
|
49
|
+
return {
|
|
50
|
+
stdout: renderError(`unknown debug subcommand '${sub}'`, "VALIDATION_ERROR", [
|
|
51
|
+
`Available: ${debugSubcommands.join(", ")}`,
|
|
52
|
+
]),
|
|
53
|
+
exitCode: 1,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const useJson = hasFlag(rest, "--json");
|
|
57
|
+
const warpArgs = ["debug", sub];
|
|
58
|
+
if (useJson)
|
|
59
|
+
warpArgs.push("--json");
|
|
60
|
+
try {
|
|
61
|
+
const result = await callWarpLenient(ctx.runner, warpArgs);
|
|
62
|
+
if (useJson) {
|
|
63
|
+
return { stdout: result.stdout.trim(), exitCode: 0 };
|
|
64
|
+
}
|
|
65
|
+
let schema = fallbackSchema;
|
|
66
|
+
if (sub === "network")
|
|
67
|
+
schema = networkSchema;
|
|
68
|
+
else if (sub === "posture")
|
|
69
|
+
schema = postureSchema;
|
|
70
|
+
else if (sub === "connectivity-check")
|
|
71
|
+
schema = connectivitySchema;
|
|
72
|
+
const label = `debug-${sub}`;
|
|
73
|
+
return {
|
|
74
|
+
stdout: renderOutput([renderDetail(label, { status: result.stdout.trim() }, schema)]),
|
|
75
|
+
exitCode: 0,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
80
|
+
return { stdout: renderError(message, "UNKNOWN"), exitCode: 1 };
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { callWarp, callWarpLenient } from "../warp.js";
|
|
2
|
+
import { takeFlag, takeBoolFlag } from "../args.js";
|
|
3
|
+
import { wantsHelp, validateFlags } from "../util.js";
|
|
4
|
+
import { renderDetail, renderHelp, renderError } from "../toon.js";
|
|
5
|
+
import { field, custom } from "../toon.js";
|
|
6
|
+
const REG_SCHEMA = {
|
|
7
|
+
organization: custom((item) => {
|
|
8
|
+
const org = item.organization;
|
|
9
|
+
return org ? String(org) : "(none)";
|
|
10
|
+
}),
|
|
11
|
+
enrollmentType: field("type"),
|
|
12
|
+
deviceUid: field("uid"),
|
|
13
|
+
accountId: field("account_id"),
|
|
14
|
+
enabled: field("enabled"),
|
|
15
|
+
};
|
|
16
|
+
function parseRegJson(text) {
|
|
17
|
+
try {
|
|
18
|
+
return JSON.parse(text);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return { raw: text.trim() };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export const registrationArea = {
|
|
25
|
+
name: "registration",
|
|
26
|
+
aliases: ["reg"],
|
|
27
|
+
description: "Show, create, or delete WARP Zero Trust registration",
|
|
28
|
+
help: [
|
|
29
|
+
"Usage: warp-axi registration <subcommand> [options]",
|
|
30
|
+
"",
|
|
31
|
+
"Subcommands:",
|
|
32
|
+
" show Show current registration details",
|
|
33
|
+
" new Register with a Zero Trust organization",
|
|
34
|
+
" delete Delete current registration",
|
|
35
|
+
"",
|
|
36
|
+
"new flags:",
|
|
37
|
+
" --org <name> Organization name (required)",
|
|
38
|
+
" --token <token> MDM service token for headless enrollment",
|
|
39
|
+
" --json Use structured output",
|
|
40
|
+
],
|
|
41
|
+
async run(ctx, args) {
|
|
42
|
+
if (wantsHelp(args))
|
|
43
|
+
return { stdout: renderHelp(this.help), exitCode: 0 };
|
|
44
|
+
const sub = args.shift();
|
|
45
|
+
switch (sub) {
|
|
46
|
+
case "show":
|
|
47
|
+
return regShow(ctx, args);
|
|
48
|
+
case "new":
|
|
49
|
+
return regNew(ctx, args);
|
|
50
|
+
case "delete":
|
|
51
|
+
return regDelete(ctx, args);
|
|
52
|
+
default:
|
|
53
|
+
return { stdout: renderHelp(this.help), exitCode: 0 };
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
async function regShow(ctx, args) {
|
|
58
|
+
const useJson = takeBoolFlag(args, "--json");
|
|
59
|
+
validateFlags(args, ["--json"], "registration show");
|
|
60
|
+
const warpArgs = ["registration", "show"];
|
|
61
|
+
if (useJson)
|
|
62
|
+
warpArgs.push("--json");
|
|
63
|
+
const result = await callWarpLenient(ctx.runner, warpArgs);
|
|
64
|
+
if (result.exitCode !== 0 && !result.stdout) {
|
|
65
|
+
return {
|
|
66
|
+
stdout: renderDetail("registration", { status: "not registered" }, REG_SCHEMA),
|
|
67
|
+
exitCode: 0,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const parsed = useJson ? parseRegJson(result.stdout) : parseRegText(result.stdout);
|
|
71
|
+
return { stdout: renderDetail("registration", parsed, REG_SCHEMA), exitCode: 0 };
|
|
72
|
+
}
|
|
73
|
+
async function regNew(ctx, args) {
|
|
74
|
+
const org = takeFlag(args, "org");
|
|
75
|
+
const token = takeFlag(args, "token");
|
|
76
|
+
const useJson = takeBoolFlag(args, "--json");
|
|
77
|
+
validateFlags(args, ["--org", "--token", "--json"], "registration new");
|
|
78
|
+
if (!org) {
|
|
79
|
+
return {
|
|
80
|
+
stdout: renderError("--org is required", "VALIDATION_ERROR", [
|
|
81
|
+
"Usage: warp-axi registration new --org <name>",
|
|
82
|
+
"Optionally add --token <mdm-token> for headless enrollment",
|
|
83
|
+
]),
|
|
84
|
+
exitCode: 1,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const warpArgs = ["registration", "new", "--organization", org];
|
|
88
|
+
if (token) {
|
|
89
|
+
warpArgs.push("--service-token", token);
|
|
90
|
+
}
|
|
91
|
+
const result = await callWarp(ctx.runner, warpArgs);
|
|
92
|
+
return { stdout: renderDetail("registration", { status: "registered", organization: org }, REG_SCHEMA), exitCode: 0 };
|
|
93
|
+
}
|
|
94
|
+
async function regDelete(ctx, args) {
|
|
95
|
+
const useJson = takeBoolFlag(args, "--json");
|
|
96
|
+
validateFlags(args, ["--json"], "registration delete");
|
|
97
|
+
const warpArgs = ["registration", "delete"];
|
|
98
|
+
await callWarp(ctx.runner, warpArgs);
|
|
99
|
+
return { stdout: renderDetail("registration", { status: "deleted" }, REG_SCHEMA), exitCode: 0 };
|
|
100
|
+
}
|
|
101
|
+
function parseRegText(text) {
|
|
102
|
+
const result = {};
|
|
103
|
+
for (const line of text.split("\n")) {
|
|
104
|
+
const m = line.match(/^\s*(.+?):\s+(.+)$/);
|
|
105
|
+
if (m) {
|
|
106
|
+
const key = m[1].trim().toLowerCase().replace(/\s+/g, "_");
|
|
107
|
+
result[key] = m[2].trim();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { callWarpLenient } from "../warp.js";
|
|
2
|
+
import { takeBoolFlag } from "../args.js";
|
|
3
|
+
import { wantsHelp, validateFlags } from "../util.js";
|
|
4
|
+
import { renderDetail, renderHelp, field, custom } from "../toon.js";
|
|
5
|
+
const SETTINGS_SCHEMA = {
|
|
6
|
+
mode: field("mode"),
|
|
7
|
+
excludeRoutes: custom((item) => {
|
|
8
|
+
const exclude = item.exclude_routes ?? item.exclude;
|
|
9
|
+
if (Array.isArray(exclude))
|
|
10
|
+
return exclude.join(", ");
|
|
11
|
+
return exclude ? String(exclude) : undefined;
|
|
12
|
+
}),
|
|
13
|
+
includeRoutes: custom((item) => {
|
|
14
|
+
const include = item.include_routes ?? item.include;
|
|
15
|
+
if (Array.isArray(include))
|
|
16
|
+
return include.join(", ");
|
|
17
|
+
return include ? String(include) : undefined;
|
|
18
|
+
}),
|
|
19
|
+
dns: field("dns"),
|
|
20
|
+
proxy: field("proxy"),
|
|
21
|
+
};
|
|
22
|
+
function parseSettingsJson(text) {
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(text);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return parseSettingsText(text);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function parseSettingsText(text) {
|
|
31
|
+
const result = {};
|
|
32
|
+
for (const line of text.split("\n")) {
|
|
33
|
+
const m = line.match(/^\s*(.+?):\s+(.+)$/);
|
|
34
|
+
if (m) {
|
|
35
|
+
const key = m[1].trim().toLowerCase().replace(/\s+/g, "_");
|
|
36
|
+
result[key] = m[2].trim();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
export const settingsArea = {
|
|
42
|
+
name: "settings",
|
|
43
|
+
aliases: ["config"],
|
|
44
|
+
description: "Show WARP client settings and configuration",
|
|
45
|
+
help: [
|
|
46
|
+
"usage: warp-axi settings [--json]",
|
|
47
|
+
"",
|
|
48
|
+
"Show current WARP client settings.",
|
|
49
|
+
"",
|
|
50
|
+
"Flags:",
|
|
51
|
+
" --json Use warp-cli --json for structured output",
|
|
52
|
+
],
|
|
53
|
+
async run(ctx, args) {
|
|
54
|
+
if (wantsHelp(args))
|
|
55
|
+
return { stdout: renderHelp(this.help), exitCode: 0 };
|
|
56
|
+
const useJson = takeBoolFlag(args, "--json");
|
|
57
|
+
validateFlags(args, ["--json"], "settings");
|
|
58
|
+
const warpArgs = ["settings"];
|
|
59
|
+
if (useJson)
|
|
60
|
+
warpArgs.push("--json");
|
|
61
|
+
const result = await callWarpLenient(ctx.runner, warpArgs);
|
|
62
|
+
const parsed = useJson ? parseSettingsJson(result.stdout) : parseSettingsText(result.stdout);
|
|
63
|
+
return { stdout: renderDetail("settings", parsed, SETTINGS_SCHEMA), exitCode: 0 };
|
|
64
|
+
},
|
|
65
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { callWarpLenient } from "../warp.js";
|
|
2
|
+
import { takeBoolFlag } from "../args.js";
|
|
3
|
+
import { wantsHelp, validateFlags } from "../util.js";
|
|
4
|
+
import { renderDetail, renderHelp, field, custom } from "../toon.js";
|
|
5
|
+
const STATUS_SCHEMA = {
|
|
6
|
+
status: field("status"),
|
|
7
|
+
registration: custom((item) => {
|
|
8
|
+
const raw = item.registration;
|
|
9
|
+
return raw ? "registered" : "unregistered";
|
|
10
|
+
}),
|
|
11
|
+
accountId: field("account_id"),
|
|
12
|
+
};
|
|
13
|
+
const STATUS_DETAIL_SCHEMA = {
|
|
14
|
+
status: field("status"),
|
|
15
|
+
organization: custom((item) => {
|
|
16
|
+
const raw = item.registration;
|
|
17
|
+
if (!raw)
|
|
18
|
+
return "unregistered";
|
|
19
|
+
return raw.organization ? String(raw.organization) : "registered";
|
|
20
|
+
}),
|
|
21
|
+
accountId: field("account_id"),
|
|
22
|
+
enrollmentType: custom((item) => {
|
|
23
|
+
const raw = item.registration;
|
|
24
|
+
if (!raw)
|
|
25
|
+
return undefined;
|
|
26
|
+
return raw.type ? String(raw.type) : undefined;
|
|
27
|
+
}),
|
|
28
|
+
deviceUid: custom((item) => {
|
|
29
|
+
const raw = item.registration;
|
|
30
|
+
if (!raw)
|
|
31
|
+
return undefined;
|
|
32
|
+
return raw.uid ? String(raw.uid) : undefined;
|
|
33
|
+
}),
|
|
34
|
+
protocol: field("protocol"),
|
|
35
|
+
vnet: field("vnet"),
|
|
36
|
+
};
|
|
37
|
+
function parseStatusJson(text) {
|
|
38
|
+
try {
|
|
39
|
+
return JSON.parse(text);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return { status: text.trim() };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function parseStatusText(text) {
|
|
46
|
+
const result = {};
|
|
47
|
+
for (const line of text.split("\n")) {
|
|
48
|
+
const m = line.match(/^\s*(.+?):\s+(.+)$/);
|
|
49
|
+
if (m) {
|
|
50
|
+
const key = m[1].trim().toLowerCase().replace(/\s+/g, "_");
|
|
51
|
+
result[key] = m[2].trim();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (!result.status) {
|
|
55
|
+
result.status = text.includes("Connected") ? "Connected" : text.includes("Disconnected") ? "Disconnected" : "Unknown";
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
export const statusArea = {
|
|
60
|
+
name: "status",
|
|
61
|
+
aliases: ["info"],
|
|
62
|
+
description: "Show WARP connection status and registration info",
|
|
63
|
+
help: [
|
|
64
|
+
"usage: warp-axi status [--json] [--detail]",
|
|
65
|
+
"",
|
|
66
|
+
"Show current WARP connection status.",
|
|
67
|
+
"",
|
|
68
|
+
"Flags:",
|
|
69
|
+
" --json Use warp-cli --json for structured output",
|
|
70
|
+
" --detail Show full registration details (org, device UID, protocol)",
|
|
71
|
+
],
|
|
72
|
+
async run(ctx, args) {
|
|
73
|
+
if (wantsHelp(args))
|
|
74
|
+
return { stdout: renderHelp(this.help), exitCode: 0 };
|
|
75
|
+
const useJson = takeBoolFlag(args, "--json");
|
|
76
|
+
const detail = takeBoolFlag(args, "--detail");
|
|
77
|
+
validateFlags(args, ["--json", "--detail"], "status");
|
|
78
|
+
const warpArgs = ["status"];
|
|
79
|
+
if (useJson)
|
|
80
|
+
warpArgs.push("--json");
|
|
81
|
+
const result = await callWarpLenient(ctx.runner, warpArgs);
|
|
82
|
+
const parsed = useJson
|
|
83
|
+
? parseStatusJson(result.stdout)
|
|
84
|
+
: parseStatusText(result.stdout);
|
|
85
|
+
const schema = detail ? STATUS_DETAIL_SCHEMA : STATUS_SCHEMA;
|
|
86
|
+
const output = renderDetail("status", parsed, schema);
|
|
87
|
+
return { stdout: output, exitCode: 0 };
|
|
88
|
+
},
|
|
89
|
+
};
|