@terminus-ai/cli 0.0.2 → 0.0.3
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/README.md +1 -1
- package/bin/devserver.mjs +1 -17
- package/bin/open.mjs +61 -0
- package/bin/servicedev.mjs +2 -1
- package/bin/terminus.js +2 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -767,7 +767,7 @@ Bare `terminus` (or `terminus help`) prints its version and the everyday command
|
|
|
767
767
|
with what it does on one line (`<word>` is a placeholder, `[ ]` is optional):
|
|
768
768
|
|
|
769
769
|
```text
|
|
770
|
-
Terminus v0.0.
|
|
770
|
+
Terminus v0.0.3, created by Terminus Intelligence
|
|
771
771
|
|
|
772
772
|
Account:
|
|
773
773
|
terminus login Open your browser and sign in
|
package/bin/devserver.mjs
CHANGED
|
@@ -28,7 +28,6 @@
|
|
|
28
28
|
* visitor chose, and only an agent that offers a choice has one.
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
-
import { execFile } from "node:child_process";
|
|
32
31
|
import { randomBytes } from "node:crypto";
|
|
33
32
|
import { watch } from "node:fs";
|
|
34
33
|
import { mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
|
|
@@ -37,6 +36,7 @@ import path from "node:path";
|
|
|
37
36
|
import { fileURLToPath } from "node:url";
|
|
38
37
|
|
|
39
38
|
import { DEV_DIRECTORY, ensureDevDirectory, TERMINUS_DIRECTORY } from "./files.mjs";
|
|
39
|
+
import { openWithPlatform } from "./open.mjs";
|
|
40
40
|
|
|
41
41
|
import {
|
|
42
42
|
AgentDevSession,
|
|
@@ -719,22 +719,6 @@ async function listLane(root, skip) {
|
|
|
719
719
|
return entries;
|
|
720
720
|
}
|
|
721
721
|
|
|
722
|
-
export async function openWithPlatform(target) {
|
|
723
|
-
const command =
|
|
724
|
-
process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
725
|
-
const args = process.platform === "win32" ? ["/c", "start", "", target] : [target];
|
|
726
|
-
return new Promise((resolve) => {
|
|
727
|
-
try {
|
|
728
|
-
const child = execFile(command, args, { detached: true, stdio: "ignore" }, (error) => {
|
|
729
|
-
resolve(!error);
|
|
730
|
-
});
|
|
731
|
-
child.unref();
|
|
732
|
-
} catch {
|
|
733
|
-
resolve(false);
|
|
734
|
-
}
|
|
735
|
-
});
|
|
736
|
-
}
|
|
737
|
-
|
|
738
722
|
// ---------------------------------------------------------------------------
|
|
739
723
|
// The server
|
|
740
724
|
// ---------------------------------------------------------------------------
|
package/bin/open.mjs
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opening a link or a file the way the person's own system does: the browser
|
|
3
|
+
* for a URL, the default app for a file. Every command that opens something
|
|
4
|
+
* comes through here — `terminus login`, `terminus dev`, `terminus service
|
|
5
|
+
* dev`, and the dev UI's Open — so the Windows rules below live once.
|
|
6
|
+
*
|
|
7
|
+
* macOS and Linux take the target as one argument to `open` / `xdg-open`,
|
|
8
|
+
* and no shell reads it. Windows opens things with `start`, a cmd.exe
|
|
9
|
+
* built-in, and cmd.exe parses the command line itself: an unquoted `&` ends
|
|
10
|
+
* the command (so `terminus login` opened its sign-in URL only up to the
|
|
11
|
+
* first `&`, and the page refused the sign-in), and runs whatever follows (a
|
|
12
|
+
* file named `notes&calc.exe` ran calc.exe). So the target goes to `start`
|
|
13
|
+
* inside double quotes, where cmd.exe reads its operators as text, with
|
|
14
|
+
* delayed expansion off, and the command line is handed over verbatim:
|
|
15
|
+
* Node's own quoting escapes quotes the way C programs read them, which
|
|
16
|
+
* cmd.exe does not. `%NAME%` still expands inside quotes, but only for a
|
|
17
|
+
* variable that is set, and a URL's `%3A%2F` names none. The failure list
|
|
18
|
+
* behind this is in test/open.test.mjs.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { execFile } from "node:child_process";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The program, arguments and spawn options that open `target` on
|
|
25
|
+
* `platform`, or null for a target that cannot be quoted for cmd.exe: a
|
|
26
|
+
* double quote or a line break would end the quoting early, and neither
|
|
27
|
+
* occurs in a Windows file name or a serialized URL.
|
|
28
|
+
*/
|
|
29
|
+
export function openCommand(target, platform = process.platform) {
|
|
30
|
+
if (platform === "darwin") return { command: "open", args: [target], options: {} };
|
|
31
|
+
if (platform !== "win32") return { command: "xdg-open", args: [target], options: {} };
|
|
32
|
+
if (/["\r\n\0]/u.test(target)) return null;
|
|
33
|
+
// /s strips exactly the outer quotes around the command; START takes its
|
|
34
|
+
// first quoted argument as the window title, so an empty one goes first.
|
|
35
|
+
return {
|
|
36
|
+
command: "cmd",
|
|
37
|
+
args: ["/d", "/v:off", "/s", "/c", `"start "" "${target}""`],
|
|
38
|
+
options: { windowsVerbatimArguments: true },
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Open `target`; resolves whether the system accepted it. */
|
|
43
|
+
export async function openWithPlatform(target) {
|
|
44
|
+
const plan = openCommand(target);
|
|
45
|
+
if (!plan) return false;
|
|
46
|
+
return new Promise((resolve) => {
|
|
47
|
+
try {
|
|
48
|
+
const child = execFile(
|
|
49
|
+
plan.command,
|
|
50
|
+
plan.args,
|
|
51
|
+
{ ...plan.options, detached: true, stdio: "ignore" },
|
|
52
|
+
(error) => {
|
|
53
|
+
resolve(!error);
|
|
54
|
+
},
|
|
55
|
+
);
|
|
56
|
+
child.unref();
|
|
57
|
+
} catch {
|
|
58
|
+
resolve(false);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
package/bin/servicedev.mjs
CHANGED
|
@@ -36,7 +36,8 @@ import {
|
|
|
36
36
|
refuseForeignHost,
|
|
37
37
|
resolveDevPortRange,
|
|
38
38
|
} from "./dev-ports.mjs";
|
|
39
|
-
import { contentTypeFor,
|
|
39
|
+
import { contentTypeFor, timingSafeTokenMatch } from "./devserver.mjs";
|
|
40
|
+
import { openWithPlatform } from "./open.mjs";
|
|
40
41
|
|
|
41
42
|
const SERVICE_DEV_PORT = 4750;
|
|
42
43
|
const PORT_ATTEMPTS = 50;
|
package/bin/terminus.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { Buffer } from "node:buffer";
|
|
4
|
-
import { execFile } from "node:child_process";
|
|
5
4
|
import { randomBytes } from "node:crypto";
|
|
6
5
|
import { mkdir, readFile, readdir, realpath, rm, stat, writeFile } from "node:fs/promises";
|
|
7
6
|
import { createServer } from "node:http";
|
|
@@ -43,6 +42,7 @@ import {
|
|
|
43
42
|
sessionPath,
|
|
44
43
|
sessionTokenIsUsable,
|
|
45
44
|
} from "./http.mjs";
|
|
45
|
+
import { openWithPlatform } from "./open.mjs";
|
|
46
46
|
import { SYNC_DIRECTORY, byKey, entryKey, localChanges, readSyncRecord, writeSyncRecord } from "./sync.mjs";
|
|
47
47
|
import { formatReleaseVersion, parseReleaseVersion } from "./versioning.mjs";
|
|
48
48
|
|
|
@@ -502,7 +502,7 @@ async function loginWithBrowser(base, flags = {}) {
|
|
|
502
502
|
console.log("Opening your browser to log in to Terminus.");
|
|
503
503
|
console.log(`If it does not open, visit:\n${loginUrl}`);
|
|
504
504
|
if (!flags.no_browser) {
|
|
505
|
-
await
|
|
505
|
+
await openWithPlatform(loginUrl);
|
|
506
506
|
}
|
|
507
507
|
|
|
508
508
|
const callbackResult = await callback.wait();
|
|
@@ -739,22 +739,6 @@ async function startLoginCallbackServer(expectedState, brandOrigin) {
|
|
|
739
739
|
};
|
|
740
740
|
}
|
|
741
741
|
|
|
742
|
-
async function openBrowser(url) {
|
|
743
|
-
const command =
|
|
744
|
-
process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
745
|
-
const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
|
|
746
|
-
return new Promise((resolve) => {
|
|
747
|
-
try {
|
|
748
|
-
const child = execFile(command, args, { detached: true, stdio: "ignore" }, (error) => {
|
|
749
|
-
resolve(!error);
|
|
750
|
-
});
|
|
751
|
-
child.unref();
|
|
752
|
-
} catch {
|
|
753
|
-
resolve(false);
|
|
754
|
-
}
|
|
755
|
-
});
|
|
756
|
-
}
|
|
757
|
-
|
|
758
742
|
/** A login with the profile of the account it signs in as. */
|
|
759
743
|
async function loginWithCurrentProfile(api, login, currentProfile = null) {
|
|
760
744
|
const profile = currentProfile ?? await api.me();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@terminus-ai/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Terminus CLI (`terminus`): search and use skills, and develop, run, and publish apps, services, and agents on the Terminus platform.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|