@oxprotocol/cli 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.
Files changed (104) hide show
  1. package/LICENSE +189 -0
  2. package/README.md +73 -0
  3. package/dist/cli.d.ts +15 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +109 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/create.d.ts +6 -0
  8. package/dist/commands/create.d.ts.map +1 -0
  9. package/dist/commands/create.js +212 -0
  10. package/dist/commands/create.js.map +1 -0
  11. package/dist/commands/dev.d.ts +2 -0
  12. package/dist/commands/dev.d.ts.map +1 -0
  13. package/dist/commands/dev.js +191 -0
  14. package/dist/commands/dev.js.map +1 -0
  15. package/dist/commands/doctor.d.ts +16 -0
  16. package/dist/commands/doctor.d.ts.map +1 -0
  17. package/dist/commands/doctor.js +197 -0
  18. package/dist/commands/doctor.js.map +1 -0
  19. package/dist/commands/install-url.d.ts +20 -0
  20. package/dist/commands/install-url.d.ts.map +1 -0
  21. package/dist/commands/install-url.js +236 -0
  22. package/dist/commands/install-url.js.map +1 -0
  23. package/dist/commands/install.d.ts +13 -0
  24. package/dist/commands/install.d.ts.map +1 -0
  25. package/dist/commands/install.js +411 -0
  26. package/dist/commands/install.js.map +1 -0
  27. package/dist/commands/keygen.d.ts +13 -0
  28. package/dist/commands/keygen.d.ts.map +1 -0
  29. package/dist/commands/keygen.js +40 -0
  30. package/dist/commands/keygen.js.map +1 -0
  31. package/dist/commands/login.d.ts +21 -0
  32. package/dist/commands/login.d.ts.map +1 -0
  33. package/dist/commands/login.js +224 -0
  34. package/dist/commands/login.js.map +1 -0
  35. package/dist/commands/logout.d.ts +17 -0
  36. package/dist/commands/logout.d.ts.map +1 -0
  37. package/dist/commands/logout.js +70 -0
  38. package/dist/commands/logout.js.map +1 -0
  39. package/dist/commands/pack.d.ts +12 -0
  40. package/dist/commands/pack.d.ts.map +1 -0
  41. package/dist/commands/pack.js +94 -0
  42. package/dist/commands/pack.js.map +1 -0
  43. package/dist/commands/protocol-register.d.ts +29 -0
  44. package/dist/commands/protocol-register.d.ts.map +1 -0
  45. package/dist/commands/protocol-register.js +231 -0
  46. package/dist/commands/protocol-register.js.map +1 -0
  47. package/dist/commands/publish.d.ts +17 -0
  48. package/dist/commands/publish.d.ts.map +1 -0
  49. package/dist/commands/publish.js +188 -0
  50. package/dist/commands/publish.js.map +1 -0
  51. package/dist/commands/token.d.ts +17 -0
  52. package/dist/commands/token.d.ts.map +1 -0
  53. package/dist/commands/token.js +110 -0
  54. package/dist/commands/token.js.map +1 -0
  55. package/dist/commands/whoami.d.ts +13 -0
  56. package/dist/commands/whoami.d.ts.map +1 -0
  57. package/dist/commands/whoami.js +77 -0
  58. package/dist/commands/whoami.js.map +1 -0
  59. package/dist/index.d.ts +26 -0
  60. package/dist/index.d.ts.map +1 -0
  61. package/dist/index.js +22 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/lib/broadcast.d.ts +41 -0
  64. package/dist/lib/broadcast.d.ts.map +1 -0
  65. package/dist/lib/broadcast.js +45 -0
  66. package/dist/lib/broadcast.js.map +1 -0
  67. package/dist/lib/host-adapter.d.ts +72 -0
  68. package/dist/lib/host-adapter.d.ts.map +1 -0
  69. package/dist/lib/host-adapter.js +193 -0
  70. package/dist/lib/host-adapter.js.map +1 -0
  71. package/dist/lib/host-detect.d.ts +60 -0
  72. package/dist/lib/host-detect.d.ts.map +1 -0
  73. package/dist/lib/host-detect.js +479 -0
  74. package/dist/lib/host-detect.js.map +1 -0
  75. package/dist/lib/oxp-url.d.ts +34 -0
  76. package/dist/lib/oxp-url.d.ts.map +1 -0
  77. package/dist/lib/oxp-url.js +74 -0
  78. package/dist/lib/oxp-url.js.map +1 -0
  79. package/dist/lib/vsx-install.d.ts +41 -0
  80. package/dist/lib/vsx-install.d.ts.map +1 -0
  81. package/dist/lib/vsx-install.js +74 -0
  82. package/dist/lib/vsx-install.js.map +1 -0
  83. package/dist/util.d.ts +10 -0
  84. package/dist/util.d.ts.map +1 -0
  85. package/dist/util.js +64 -0
  86. package/dist/util.js.map +1 -0
  87. package/package.json +48 -0
  88. package/templates/hello-code/README.md +39 -0
  89. package/templates/hello-code/oxp.json +14 -0
  90. package/templates/hello-code/package.json +18 -0
  91. package/templates/hello-code/src/extension.ts +17 -0
  92. package/templates/hello-code/tsconfig.json +20 -0
  93. package/templates/hello-html/README.md +18 -0
  94. package/templates/hello-html/oxp.json +14 -0
  95. package/templates/hello-html/ui/index.html +43 -0
  96. package/templates/hello-rust/Cargo.toml +19 -0
  97. package/templates/hello-rust/README.md +50 -0
  98. package/templates/hello-rust/oxp.json +22 -0
  99. package/templates/hello-rust/src/lib.rs +111 -0
  100. package/templates/hello-rust/wit/deps/oxp-host/oxp-host.wit +136 -0
  101. package/templates/hello-rust/wit/extension.wit +71 -0
  102. package/templates/hello-tree/README.md +15 -0
  103. package/templates/hello-tree/oxp.json +14 -0
  104. package/templates/hello-tree/ui/tree.json +27 -0
@@ -0,0 +1,77 @@
1
+ /**
2
+ * `oxp whoami [--json]` — print the identity behind the local credentials.
3
+ *
4
+ * Hits GET /api/v1/auth/whoami with the stored bearer token and prints
5
+ * handle, email, scopes, and expiry. Prints nothing sensitive (the token
6
+ * itself is never echoed back).
7
+ *
8
+ * Exit codes:
9
+ * 0 authenticated
10
+ * 1 not logged in / token invalid / network error
11
+ */
12
+ import { fail, info, readCredentials, registryUrl } from "../util.js";
13
+ export async function whoami(args) {
14
+ const json = args.includes("--json");
15
+ const token = await readCredentials();
16
+ if (!token) {
17
+ if (json) {
18
+ process.stdout.write(JSON.stringify({ ok: false, error: "not_logged_in" }) + "\n");
19
+ return 1;
20
+ }
21
+ fail("not logged in. run `oxp login` first");
22
+ }
23
+ const url = `${registryUrl()}/api/v1/auth/whoami`;
24
+ let res;
25
+ try {
26
+ res = await fetch(url, {
27
+ headers: { authorization: `Bearer ${token}` },
28
+ });
29
+ }
30
+ catch (err) {
31
+ if (json) {
32
+ process.stdout.write(JSON.stringify({
33
+ ok: false,
34
+ error: "network_error",
35
+ message: err.message,
36
+ }) + "\n");
37
+ return 1;
38
+ }
39
+ fail(`network error: ${err.message}`);
40
+ }
41
+ if (res.status === 401) {
42
+ if (json) {
43
+ process.stdout.write(JSON.stringify({ ok: false, error: "invalid_token" }) + "\n");
44
+ return 1;
45
+ }
46
+ fail("local credentials are invalid or expired. run `oxp login` again");
47
+ }
48
+ if (!res.ok) {
49
+ const text = await res.text().catch(() => "");
50
+ if (json) {
51
+ process.stdout.write(JSON.stringify({
52
+ ok: false,
53
+ error: "http_error",
54
+ status: res.status,
55
+ body: text,
56
+ }) + "\n");
57
+ return 1;
58
+ }
59
+ fail(`whoami failed (${res.status}): ${text}`);
60
+ }
61
+ const body = (await res.json());
62
+ if (json) {
63
+ process.stdout.write(JSON.stringify(body) + "\n");
64
+ return 0;
65
+ }
66
+ const who = body.handle ? `@${body.handle}` : "(no handle)";
67
+ info(`Signed in as ${who}`);
68
+ info(` email: ${body.email}`);
69
+ info(` token: ${body.token.name} (${body.token.id.slice(0, 8)}…)`);
70
+ info(` scopes: ${body.token.scopes.join(", ") || "(none)"}`);
71
+ info(` expires: ${body.token.expiresAt ?? "never"}`);
72
+ if (body.token.lastUsedAt) {
73
+ info(` last used: ${body.token.lastUsedAt}`);
74
+ }
75
+ return 0;
76
+ }
77
+ //# sourceMappingURL=whoami.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Programmatic entry point for `@oxprotocol/cli`. Exposes individual subcommand
3
+ * functions so wrapper packages (e.g. `create-oxp`, integrations, IDE
4
+ * extensions) can invoke them without spawning a subprocess.
5
+ *
6
+ * The CLI binary in `cli.ts` parses argv and dispatches to these same
7
+ * functions — keeping this module thin avoids drift.
8
+ */
9
+ export { create } from "./commands/create.js";
10
+ export { pack } from "./commands/pack.js";
11
+ export { dev } from "./commands/dev.js";
12
+ export { login } from "./commands/login.js";
13
+ export { publish } from "./commands/publish.js";
14
+ export { install } from "./commands/install.js";
15
+ export { keygen } from "./commands/keygen.js";
16
+ export { token } from "./commands/token.js";
17
+ export { protocolRegister } from "./commands/protocol-register.js";
18
+ export { detectHosts, detectHost } from "./lib/host-detect.js";
19
+ export type { DetectedHost } from "./lib/host-detect.js";
20
+ export { ensureAdapter, ensureAdapters } from "./lib/host-adapter.js";
21
+ export type { AdapterStatus } from "./lib/host-adapter.js";
22
+ export { broadcast, notifyInboxPath } from "./lib/broadcast.js";
23
+ export type { NotifyEvent } from "./lib/broadcast.js";
24
+ export { parseOxpUrl, buildInstallUrl, OxpUrlError } from "./lib/oxp-url.js";
25
+ export type { ParsedOxpUrl, InstallUrl } from "./lib/oxp-url.js";
26
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAEnE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC/D,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACtE,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAChE,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC7E,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Programmatic entry point for `@oxprotocol/cli`. Exposes individual subcommand
3
+ * functions so wrapper packages (e.g. `create-oxp`, integrations, IDE
4
+ * extensions) can invoke them without spawning a subprocess.
5
+ *
6
+ * The CLI binary in `cli.ts` parses argv and dispatches to these same
7
+ * functions — keeping this module thin avoids drift.
8
+ */
9
+ export { create } from "./commands/create.js";
10
+ export { pack } from "./commands/pack.js";
11
+ export { dev } from "./commands/dev.js";
12
+ export { login } from "./commands/login.js";
13
+ export { publish } from "./commands/publish.js";
14
+ export { install } from "./commands/install.js";
15
+ export { keygen } from "./commands/keygen.js";
16
+ export { token } from "./commands/token.js";
17
+ export { protocolRegister } from "./commands/protocol-register.js";
18
+ export { detectHosts, detectHost } from "./lib/host-detect.js";
19
+ export { ensureAdapter, ensureAdapters } from "./lib/host-adapter.js";
20
+ export { broadcast, notifyInboxPath } from "./lib/broadcast.js";
21
+ export { parseOxpUrl, buildInstallUrl, OxpUrlError } from "./lib/oxp-url.js";
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAEnE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAE/D,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEtE,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAEhE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Cross-process broadcast — tell every running OXP host that the
3
+ * shared store has changed so they can hot-reload without a restart.
4
+ *
5
+ * Mechanism (intentionally minimal, no daemon):
6
+ *
7
+ * 1. CLI writes a one-line JSON event to `~/.oxp/notify/inbox.jsonl`
8
+ * (append-only). Each line carries `{ts, kind, id, version}`.
9
+ * 2. Hosts watch that file with `fs.watch` and replay events newer
10
+ * than the last position they recorded in their globalState.
11
+ *
12
+ * This avoids the complexity of a real socket server while still giving
13
+ * the "magical" UX where the extension appears in a running VS Code the
14
+ * moment `oxp install` finishes. When we ship `oxpd` the same file
15
+ * becomes a write-through audit log behind the daemon.
16
+ *
17
+ * The notify file is a best-effort signal: if it can't be written we
18
+ * silently skip — the host will still pick up the install on next
19
+ * launch by reading `installed.json`.
20
+ */
21
+ export interface NotifyEvent {
22
+ /** ISO timestamp the event was recorded. */
23
+ ts: string;
24
+ /** What changed. `installed` is emitted by `oxp install`. */
25
+ kind: "installed" | "uninstalled" | "updated";
26
+ /** Extension id that changed (`@publisher/slug`). */
27
+ id: string;
28
+ /** Version that is now active in the shared store. */
29
+ version: string;
30
+ /** Optional human note for debugging. */
31
+ note?: string;
32
+ }
33
+ /**
34
+ * Append a notify event to the shared inbox. Never throws — the worst
35
+ * case is a missed in-process refresh, which the host recovers from on
36
+ * its next manual reload.
37
+ */
38
+ export declare function broadcast(event: Omit<NotifyEvent, "ts">): Promise<void>;
39
+ /** Path of the shared inbox — exported so hosts can `fs.watch` it. */
40
+ export declare function notifyInboxPath(): string;
41
+ //# sourceMappingURL=broadcast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broadcast.d.ts","sourceRoot":"","sources":["../../src/lib/broadcast.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAOH,MAAM,WAAW,WAAW;IAC1B,4CAA4C;IAC5C,EAAE,EAAE,MAAM,CAAC;IACX,6DAA6D;IAC7D,IAAI,EAAE,WAAW,GAAG,aAAa,GAAG,SAAS,CAAC;IAC9C,qDAAqD;IACrD,EAAE,EAAE,MAAM,CAAC;IACX,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAW7E;AAED,sEAAsE;AACtE,wBAAgB,eAAe,IAAI,MAAM,CAExC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Cross-process broadcast — tell every running OXP host that the
3
+ * shared store has changed so they can hot-reload without a restart.
4
+ *
5
+ * Mechanism (intentionally minimal, no daemon):
6
+ *
7
+ * 1. CLI writes a one-line JSON event to `~/.oxp/notify/inbox.jsonl`
8
+ * (append-only). Each line carries `{ts, kind, id, version}`.
9
+ * 2. Hosts watch that file with `fs.watch` and replay events newer
10
+ * than the last position they recorded in their globalState.
11
+ *
12
+ * This avoids the complexity of a real socket server while still giving
13
+ * the "magical" UX where the extension appears in a running VS Code the
14
+ * moment `oxp install` finishes. When we ship `oxpd` the same file
15
+ * becomes a write-through audit log behind the daemon.
16
+ *
17
+ * The notify file is a best-effort signal: if it can't be written we
18
+ * silently skip — the host will still pick up the install on next
19
+ * launch by reading `installed.json`.
20
+ */
21
+ import { promises as fs } from "node:fs";
22
+ import { join } from "node:path";
23
+ import { oxpHome } from "../util.js";
24
+ /**
25
+ * Append a notify event to the shared inbox. Never throws — the worst
26
+ * case is a missed in-process refresh, which the host recovers from on
27
+ * its next manual reload.
28
+ */
29
+ export async function broadcast(event) {
30
+ const dir = join(oxpHome(), "notify");
31
+ const file = join(dir, "inbox.jsonl");
32
+ const line = JSON.stringify({ ts: new Date().toISOString(), ...event }) + "\n";
33
+ try {
34
+ await fs.mkdir(dir, { recursive: true, mode: 0o700 });
35
+ await fs.appendFile(file, line, { mode: 0o600 });
36
+ }
37
+ catch {
38
+ // best-effort
39
+ }
40
+ }
41
+ /** Path of the shared inbox — exported so hosts can `fs.watch` it. */
42
+ export function notifyInboxPath() {
43
+ return join(oxpHome(), "notify", "inbox.jsonl");
44
+ }
45
+ //# sourceMappingURL=broadcast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broadcast.js","sourceRoot":"","sources":["../../src/lib/broadcast.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAerC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,KAA8B;IAC5D,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;IACtC,MAAM,IAAI,GACR,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,GAAG,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IACpE,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACtD,MAAM,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,cAAc;IAChB,CAAC;AACH,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,eAAe;IAC7B,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;AAClD,CAAC"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Host adapter management — ensure each detected IDE has the OXP host
3
+ * adapter (the small extension that wires the IDE to the shared
4
+ * `~/.oxp/host-store/`).
5
+ *
6
+ * For VS Code-family IDEs (VS Code, Cursor, Windsurf, VSCodium, Insiders)
7
+ * the adapter is a single VSIX published to OpenVSX as
8
+ * `oxprotocol.oxp-vscode`. The same VSIX works in every fork because
9
+ * they all share the VS Code extension API surface.
10
+ *
11
+ * If the adapter VSIX hasn't been published yet (early-launch state),
12
+ * `ensureAdapter` returns `{ status: "unavailable" }` instead of failing
13
+ * — the install still proceeds, the user just won't see the extension
14
+ * appear inside that IDE until the adapter ships. This keeps the smart
15
+ * install flow forward-compatible.
16
+ *
17
+ * Auto-install is **silent** when:
18
+ * - the IDE has a CLI launcher available, AND
19
+ * - the adapter is not already present, AND
20
+ * - the user has not passed `--no-adapter`.
21
+ *
22
+ * The CLI never edits the IDE's user settings, never spawns a UI, and
23
+ * never blocks waiting on a marketplace prompt — `<cli>
24
+ * --install-extension <id>` is a one-shot command that exits 0 on
25
+ * success.
26
+ */
27
+ import type { DetectedHost } from "./host-detect.js";
28
+ /** Marketplace id of the VS Code-family host adapter. */
29
+ export declare const VSCODE_ADAPTER_ID = "oxprotocol.oxp-vscode";
30
+ /** JetBrains marketplace plugin id of the OXP host adapter. */
31
+ export declare const JETBRAINS_ADAPTER_ID = "sh.oxp.jetbrains";
32
+ /** Neovim plugin spec (lazy.nvim/packer source) for the OXP host adapter. */
33
+ export declare const NEOVIM_ADAPTER_REPO = "oxprotocol/oxp.nvim";
34
+ export type AdapterStatus =
35
+ /** Adapter is already installed in this host. */
36
+ {
37
+ status: "present";
38
+ host: DetectedHost;
39
+ }
40
+ /** Adapter was just installed by us. */
41
+ | {
42
+ status: "installed";
43
+ host: DetectedHost;
44
+ }
45
+ /** No adapter exists for this host family yet. */
46
+ | {
47
+ status: "unsupported";
48
+ host: DetectedHost;
49
+ }
50
+ /** Adapter would be installable but the VSIX isn't published yet. */
51
+ | {
52
+ status: "unavailable";
53
+ host: DetectedHost;
54
+ reason: string;
55
+ }
56
+ /** Install was attempted and failed (best-effort; non-fatal). */
57
+ | {
58
+ status: "failed";
59
+ host: DetectedHost;
60
+ error: string;
61
+ };
62
+ export interface EnsureOptions {
63
+ /** When true, skip auto-install and only report status. */
64
+ reportOnly?: boolean;
65
+ }
66
+ /**
67
+ * Make sure each host in the list has the OXP adapter installed.
68
+ * Returns a parallel array of statuses; never throws.
69
+ */
70
+ export declare function ensureAdapters(hosts: DetectedHost[], opts?: EnsureOptions): Promise<AdapterStatus[]>;
71
+ export declare function ensureAdapter(host: DetectedHost, opts?: EnsureOptions): Promise<AdapterStatus>;
72
+ //# sourceMappingURL=host-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-adapter.d.ts","sourceRoot":"","sources":["../../src/lib/host-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIrD,yDAAyD;AACzD,eAAO,MAAM,iBAAiB,0BAA0B,CAAC;AAEzD,+DAA+D;AAC/D,eAAO,MAAM,oBAAoB,qBAAqB,CAAC;AAEvD,6EAA6E;AAC7E,eAAO,MAAM,mBAAmB,wBAAwB,CAAC;AAQzD,MAAM,MAAM,aAAa;AACvB,iDAAiD;AAC/C;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,YAAY,CAAA;CAAE;AAC3C,wCAAwC;GACtC;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,YAAY,CAAA;CAAE;AAC7C,kDAAkD;GAChD;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,YAAY,CAAA;CAAE;AAC/C,qEAAqE;GACnE;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AAC/D,iEAAiE;GAC/D;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5D,MAAM,WAAW,aAAa;IAC5B,2DAA2D;IAC3D,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,YAAY,EAAE,EACrB,IAAI,GAAE,aAAkB,GACvB,OAAO,CAAC,aAAa,EAAE,CAAC,CAI1B;AAED,wBAAsB,aAAa,CACjC,IAAI,EAAE,YAAY,EAClB,IAAI,GAAE,aAAkB,GACvB,OAAO,CAAC,aAAa,CAAC,CAoDxB"}
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Host adapter management — ensure each detected IDE has the OXP host
3
+ * adapter (the small extension that wires the IDE to the shared
4
+ * `~/.oxp/host-store/`).
5
+ *
6
+ * For VS Code-family IDEs (VS Code, Cursor, Windsurf, VSCodium, Insiders)
7
+ * the adapter is a single VSIX published to OpenVSX as
8
+ * `oxprotocol.oxp-vscode`. The same VSIX works in every fork because
9
+ * they all share the VS Code extension API surface.
10
+ *
11
+ * If the adapter VSIX hasn't been published yet (early-launch state),
12
+ * `ensureAdapter` returns `{ status: "unavailable" }` instead of failing
13
+ * — the install still proceeds, the user just won't see the extension
14
+ * appear inside that IDE until the adapter ships. This keeps the smart
15
+ * install flow forward-compatible.
16
+ *
17
+ * Auto-install is **silent** when:
18
+ * - the IDE has a CLI launcher available, AND
19
+ * - the adapter is not already present, AND
20
+ * - the user has not passed `--no-adapter`.
21
+ *
22
+ * The CLI never edits the IDE's user settings, never spawns a UI, and
23
+ * never blocks waiting on a marketplace prompt — `<cli>
24
+ * --install-extension <id>` is a one-shot command that exits 0 on
25
+ * success.
26
+ */
27
+ import { promises as fs } from "node:fs";
28
+ import { execFile } from "node:child_process";
29
+ import { promisify } from "node:util";
30
+ const exec = promisify(execFile);
31
+ /** Marketplace id of the VS Code-family host adapter. */
32
+ export const VSCODE_ADAPTER_ID = "oxprotocol.oxp-vscode";
33
+ /** JetBrains marketplace plugin id of the OXP host adapter. */
34
+ export const JETBRAINS_ADAPTER_ID = "sh.oxp.jetbrains";
35
+ /** Neovim plugin spec (lazy.nvim/packer source) for the OXP host adapter. */
36
+ export const NEOVIM_ADAPTER_REPO = "oxprotocol/oxp.nvim";
37
+ /** When true, auto-install will attempt to fetch the adapter from OpenVSX. */
38
+ const ADAPTER_PUBLISHED = false; // flip when oxp-vscode VSIX is on OpenVSX
39
+ /** When true, auto-install will fetch the JetBrains plugin from JetBrains Marketplace. */
40
+ const JETBRAINS_ADAPTER_PUBLISHED = false; // flip when sh.oxp.jetbrains is published
41
+ /**
42
+ * Make sure each host in the list has the OXP adapter installed.
43
+ * Returns a parallel array of statuses; never throws.
44
+ */
45
+ export async function ensureAdapters(hosts, opts = {}) {
46
+ // Run in parallel — every probe / install is independent and bounded
47
+ // by its own exec timeout.
48
+ return Promise.all(hosts.map((h) => ensureAdapter(h, opts)));
49
+ }
50
+ export async function ensureAdapter(host, opts = {}) {
51
+ if (host.family === "jetbrains") {
52
+ return ensureJetBrainsAdapter(host, opts);
53
+ }
54
+ if (host.id === "neovim") {
55
+ return ensureNeovimAdapter(host);
56
+ }
57
+ if (host.family !== "vscode") {
58
+ return { status: "unsupported", host };
59
+ }
60
+ // Probe the extensions directory directly — it's the cheapest signal
61
+ // and avoids spawning the IDE's CLI (which can be slow on cold start).
62
+ if (host.extensionsDir && (await hasAdapterOnDisk(host.extensionsDir))) {
63
+ return { status: "present", host };
64
+ }
65
+ // Some hosts (VSCodium, fresh installs) only expose the CLI listing.
66
+ if (host.cliPath && (await hasAdapterViaCli(host.cliPath))) {
67
+ return { status: "present", host };
68
+ }
69
+ if (!ADAPTER_PUBLISHED) {
70
+ return {
71
+ status: "unavailable",
72
+ host,
73
+ reason: "host adapter VSIX not published yet",
74
+ };
75
+ }
76
+ if (opts.reportOnly || !host.cliPath) {
77
+ return {
78
+ status: "unavailable",
79
+ host,
80
+ reason: !host.cliPath ? "IDE CLI not on PATH" : "skipped (--report-only)",
81
+ };
82
+ }
83
+ try {
84
+ await exec(host.cliPath, ["--install-extension", VSCODE_ADAPTER_ID, "--force"], { timeout: 60_000 });
85
+ return { status: "installed", host };
86
+ }
87
+ catch (err) {
88
+ return {
89
+ status: "failed",
90
+ host,
91
+ error: err.message.split("\n")[0] ?? "install failed",
92
+ };
93
+ }
94
+ }
95
+ /* -------------------------------------------------------------------------- */
96
+ /* Probes */
97
+ /* -------------------------------------------------------------------------- */
98
+ async function hasAdapterOnDisk(extensionsDir) {
99
+ try {
100
+ const entries = await fs.readdir(extensionsDir);
101
+ return entries.some((name) => name.toLowerCase().startsWith(`${VSCODE_ADAPTER_ID.toLowerCase()}-`));
102
+ }
103
+ catch {
104
+ return false;
105
+ }
106
+ }
107
+ async function hasAdapterViaCli(cliPath) {
108
+ try {
109
+ const { stdout } = await exec(cliPath, ["--list-extensions"], {
110
+ timeout: 5_000,
111
+ });
112
+ return stdout
113
+ .split(/\r?\n/)
114
+ .map((s) => s.trim().toLowerCase())
115
+ .includes(VSCODE_ADAPTER_ID.toLowerCase());
116
+ }
117
+ catch {
118
+ return false;
119
+ }
120
+ }
121
+ /* -------------------------------------------------------------------------- */
122
+ /* JetBrains adapter */
123
+ /* -------------------------------------------------------------------------- */
124
+ /**
125
+ * For JetBrains we cannot silently install plugins from a CLI in the same
126
+ * way as VS Code (the IDE has no `--install-plugin` flag in stable
127
+ * channels). Instead we probe `<userDataDir>/plugins/oxp-jetbrains/` for
128
+ * the marker the host plugin drops on first run, and otherwise return
129
+ * `unavailable` with a clear human-readable next step.
130
+ */
131
+ async function ensureJetBrainsAdapter(host, _opts) {
132
+ if (host.extensionsDir) {
133
+ try {
134
+ const entries = await fs.readdir(host.extensionsDir);
135
+ const present = entries.some((n) => {
136
+ const lower = n.toLowerCase();
137
+ return (lower.startsWith("oxp-jetbrains") ||
138
+ lower.startsWith("oxp.jetbrains") ||
139
+ lower === "oxp");
140
+ });
141
+ if (present)
142
+ return { status: "present", host };
143
+ }
144
+ catch {
145
+ // No plugins dir yet — fall through to "unavailable".
146
+ }
147
+ }
148
+ if (!JETBRAINS_ADAPTER_PUBLISHED) {
149
+ return {
150
+ status: "unavailable",
151
+ host,
152
+ reason: "JetBrains plugin not published yet",
153
+ };
154
+ }
155
+ return {
156
+ status: "unavailable",
157
+ host,
158
+ reason: `install via Settings → Plugins → search "${JETBRAINS_ADAPTER_ID}"`,
159
+ };
160
+ }
161
+ /* -------------------------------------------------------------------------- */
162
+ /* Neovim adapter */
163
+ /* -------------------------------------------------------------------------- */
164
+ /**
165
+ * Neovim plugins are git-managed by the user's plugin manager (lazy.nvim,
166
+ * packer, vim-plug). We never write to the user's nvim config — instead we
167
+ * probe the standard data dir for a clone of `oxp.nvim` and otherwise
168
+ * report a one-line install snippet via `unavailable`.
169
+ */
170
+ async function ensureNeovimAdapter(host) {
171
+ if (host.extensionsDir) {
172
+ const present = (await pathExists(`${host.extensionsDir}/lazy/oxp.nvim`)) ||
173
+ (await pathExists(`${host.extensionsDir}/site/pack/oxp/start/oxp.nvim`)) ||
174
+ (await pathExists(`${host.extensionsDir}/plugged/oxp.nvim`));
175
+ if (present)
176
+ return { status: "present", host };
177
+ }
178
+ return {
179
+ status: "unavailable",
180
+ host,
181
+ reason: `add "${NEOVIM_ADAPTER_REPO}" to your plugin manager`,
182
+ };
183
+ }
184
+ async function pathExists(p) {
185
+ try {
186
+ await fs.stat(p);
187
+ return true;
188
+ }
189
+ catch {
190
+ return false;
191
+ }
192
+ }
193
+ //# sourceMappingURL=host-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-adapter.js","sourceRoot":"","sources":["../../src/lib/host-adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Host detection — discover IDEs installed on the user's machine.
3
+ *
4
+ * The OXP install flow needs to know which editors are present so it can
5
+ * (a) ensure the OXP host adapter is installed for each one, and
6
+ * (b) report which environments the freshly-installed extension is now
7
+ * available in.
8
+ *
9
+ * Detection is **silent** and **best-effort**: a missing IDE is not an
10
+ * error, and we never spawn a long-running probe. We look for the
11
+ * canonical CLI binary on PATH and the canonical user-data / extensions
12
+ * directories for each platform. If both exist we consider the IDE
13
+ * installed; if only one is present the host is reported with
14
+ * `partial: true` so the caller can decide whether to skip it.
15
+ *
16
+ * Supported families today:
17
+ * - VS Code, Cursor, Windsurf, VSCodium, VS Code Insiders
18
+ * (all share the same extension format → adapter VSIX is reusable)
19
+ *
20
+ * JetBrains, Zed, Theia, Gitpod, Coder are placeholders — detection is
21
+ * stubbed so the surface stays stable as we add real probes.
22
+ */
23
+ import type { HostId } from "@oxprotocol/types";
24
+ export interface DetectedHost {
25
+ /** Canonical id from `@oxprotocol/types`. */
26
+ id: HostId;
27
+ /** Human-friendly name for CLI output. */
28
+ displayName: string;
29
+ /** Family this host belongs to (drives adapter strategy). */
30
+ family: "vscode" | "jetbrains" | "zed" | "piye" | "other";
31
+ /** Path to the IDE's command-line launcher, if found. */
32
+ cliPath?: string;
33
+ /** Path to the directory storing the user's installed extensions. */
34
+ extensionsDir?: string;
35
+ /** Path to the IDE's user-data dir (settings, globalStorage). */
36
+ userDataDir?: string;
37
+ /** True when both CLI and a user-data dir were located. */
38
+ installed: boolean;
39
+ /** True when only one of CLI / data-dir was found (still usable in some flows). */
40
+ partial: boolean;
41
+ /** True when we detected at least one running process for this IDE. */
42
+ running: boolean;
43
+ }
44
+ export interface DetectOptions {
45
+ /** Skip the `ps`/`tasklist` probe. Default: false. */
46
+ skipProcessProbe?: boolean;
47
+ }
48
+ /**
49
+ * Discover every supported IDE on the current machine. Returns only
50
+ * hosts where we found *some* evidence of installation; absent IDEs are
51
+ * silently omitted. Order is stable: VS Code family first (in the
52
+ * declaration order above), then everything else.
53
+ */
54
+ export declare function detectHosts(opts?: DetectOptions): Promise<DetectedHost[]>;
55
+ /**
56
+ * Look up a single host by id. Convenience for `oxp install --host vscode`.
57
+ * Returns undefined when not installed.
58
+ */
59
+ export declare function detectHost(id: HostId): Promise<DetectedHost | undefined>;
60
+ //# sourceMappingURL=host-detect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-detect.d.ts","sourceRoot":"","sources":["../../src/lib/host-detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAQH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAIhD,MAAM,WAAW,YAAY;IAC3B,6CAA6C;IAC7C,EAAE,EAAE,MAAM,CAAC;IACX,0CAA0C;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,MAAM,EAAE,QAAQ,GAAG,WAAW,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;IAC1D,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2DAA2D;IAC3D,SAAS,EAAE,OAAO,CAAC;IACnB,mFAAmF;IACnF,OAAO,EAAE,OAAO,CAAC;IACjB,uEAAuE;IACvE,OAAO,EAAE,OAAO,CAAC;CAClB;AAqED,MAAM,WAAW,aAAa;IAC5B,sDAAsD;IACtD,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,IAAI,GAAE,aAAkB,GACvB,OAAO,CAAC,YAAY,EAAE,CAAC,CAuBzB;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAGnC"}