openship 0.6.1 → 0.6.5

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 (59) hide show
  1. package/README.md +7 -2
  2. package/dist/{bare-IWS2QHJ3.js → bare-XQIPDO4R.js} +10 -9
  3. package/dist/{chunk-RRJJGVKE.js → chunk-3ZAGC5NT.js} +64 -17
  4. package/dist/{chunk-6ODUBKUB.js → chunk-5OUWIPOB.js} +69 -7
  5. package/dist/chunk-6HOA5JT7.js +124 -0
  6. package/dist/{chunk-TWJCLD4W.js → chunk-6JELW75A.js} +4 -4
  7. package/dist/{chunk-IOT5ZX23.js → chunk-7334NSJL.js} +399 -369
  8. package/dist/chunk-7S4USQYF.js +1753 -0
  9. package/dist/{chunk-3LDWWY7U.js → chunk-A7EWM2KA.js} +41 -7
  10. package/dist/chunk-ELGRMZOW.js +25 -0
  11. package/dist/chunk-EZPPTWJQ.js +292 -0
  12. package/dist/{chunk-IXM5245F.js → chunk-GRTXMUHA.js} +553 -538
  13. package/dist/chunk-HPXP6LXZ.js +428 -0
  14. package/dist/{chunk-OTLSJYAC.js → chunk-LEYSL46B.js} +2135 -85
  15. package/dist/{chunk-EMXI4UCU.js → chunk-LFCSC4IU.js} +29 -10
  16. package/dist/{chunk-JIMUYEKN.js → chunk-MSZUCNPV.js} +1 -1
  17. package/dist/{chunk-YIPMDGG6.js → chunk-PZRRL5PC.js} +68 -23
  18. package/dist/{chunk-2NZSUXOB.js → chunk-QLX7NBEA.js} +1208 -599
  19. package/dist/chunk-RFWJE7ZN.js +68 -0
  20. package/dist/{chunk-VDDMADOF.js → chunk-TM2IQPYU.js} +16 -2
  21. package/dist/{chunk-3FYIXVX5.js → chunk-VDESJSG6.js} +451 -106
  22. package/dist/{chunk-UC7YIEHT.js → chunk-VHMOQL5Y.js} +254 -45
  23. package/dist/{chunk-EW6KB2J7.js → chunk-VLQ3UIVO.js} +393 -53
  24. package/dist/{chunk-VZ2ZHPS2.js → chunk-WE7BXW6L.js} +3 -9
  25. package/dist/chunk-WFRXYWK2.js +444 -0
  26. package/dist/chunk-XRNRT37W.js +316 -0
  27. package/dist/{chunk-3NZICQHF.js → chunk-XVOBL7BC.js} +31 -8
  28. package/dist/cloud-3DODOWTR.js +36 -0
  29. package/dist/{detect-ALF4GXRX.js → detect-P4CIQBRH.js} +3 -3
  30. package/dist/{docker-QECQJ5P4.js → docker-3K2NEBD6.js} +15 -8
  31. package/dist/{docker-edge-executor-62N64MGS.js → docker-edge-executor-YZZ6P7IC.js} +5 -5
  32. package/dist/{edge-import-SAYTRJLO.js → edge-import-MCJNVTZ2.js} +26 -23
  33. package/dist/edge-preflight-ES6FH4JK.js +42 -0
  34. package/dist/{ensure-container-edge-CFSCPGZK.js → ensure-container-edge-YPITNH45.js} +9 -8
  35. package/dist/{executor-PT6UEJ5M.js → executor-DZGX55K2.js} +12 -5
  36. package/dist/host-channel-preflight-MUXE3KZU.js +49 -0
  37. package/dist/index.js +4089 -4538
  38. package/dist/{nginx-YOEEFBTE.js → nginx-NSAHWGJV.js} +11 -5
  39. package/dist/node-bootstrap.js +241 -0
  40. package/dist/node-entry.js +52 -1
  41. package/dist/{openresty-lua-WGBO2M3Z.js → openresty-lua-DR4D3EZ6.js} +6 -2
  42. package/dist/privilege-YTVI4SKF.js +19 -0
  43. package/dist/server/engine/samples/fail2ban/jail.d/sshd.local +4 -1
  44. package/dist/server/index.js +21391 -13110
  45. package/dist/server/migrations/0098_instance_product_mode.sql +12 -0
  46. package/dist/server/migrations/0099_mail_webmail_project.sql +24 -0
  47. package/dist/server/migrations/0100_server_ssh_private_key.sql +11 -0
  48. package/dist/server/migrations/0101_mail_resume_step.sql +12 -0
  49. package/dist/server/migrations/0102_project_workload_axes.sql +19 -0
  50. package/dist/server/migrations/0103_dns_credential.sql +41 -0
  51. package/dist/server/migrations/0104_instance_host_control.sql +15 -0
  52. package/dist/server/migrations/meta/_journal.json +49 -0
  53. package/dist/{setup-M2ZDGH3O.js → setup-WUUZURHS.js} +10 -9
  54. package/dist/up-XEO3SR6Z.js +58 -0
  55. package/package.json +4 -2
  56. package/dist/chunk-IW2UKBVF.js +0 -144
  57. package/dist/chunk-ZCFVHA25.js +0 -89
  58. package/dist/cloud-M2YLWEXO.js +0 -31
  59. /package/dist/{dist-es-JGBPABJI.js → dist-es-ZP5QDSJ3.js} +0 -0
@@ -0,0 +1,12 @@
1
+ -- Openship Mail: which product this instance presents itself as.
2
+ --
3
+ -- Nullable with NO default, deliberately. The instance_settings row exists on
4
+ -- every instance, so a NOT NULL DEFAULT 'platform' would write a concrete value
5
+ -- everywhere and permanently shadow the OPENSHIP_PRODUCT env var — the resolver
6
+ -- reads `settings.product_mode ?? env.OPENSHIP_PRODUCT`, so "unset" has to stay
7
+ -- representable. NULL means "no instance override".
8
+ --
9
+ -- Presentation scope only: this hides nav entries and rebrands the shell. It is
10
+ -- not an authorization boundary and no route reads it — webmail deploys through
11
+ -- the ordinary project pipeline, so the platform endpoints stay live in mail mode.
12
+ ALTER TABLE "instance_settings" ADD COLUMN IF NOT EXISTS "product_mode" text;
@@ -0,0 +1,24 @@
1
+ -- The webmail project serving a mail server, as a stored FK.
2
+ --
3
+ -- Webmail is now an ordinary catalog app (packages/core/src/apps/catalog/webmail.json)
4
+ -- installed through the SAME generic installer as every other app, so its slug is
5
+ -- derived from the project NAME the operator typed. The link therefore cannot be a
6
+ -- naming convention any more: the old lookup parsed `webmail-<serverId>` back out of
7
+ -- the slug, which the generic installer never produces — and which, while it existed,
8
+ -- mislinked any project a user happened to name "Webmail Prod" (slug `webmail-prod`,
9
+ -- read back as mail server "prod").
10
+ --
11
+ -- Nullable: most servers have no webmail, and an operator may run one outside
12
+ -- openship. ON DELETE SET NULL so deleting the webmail project clears the link and
13
+ -- /emails falls back to the install CTA rather than pointing at a row that is gone.
14
+ --
15
+ -- No backfill. A pre-existing webmail project still carries the retired
16
+ -- `mail-webmail` template id and the `webmail-<serverId>` slug; the mail status
17
+ -- resolver keeps that legacy slug lookup as a fallback for exactly those rows, and
18
+ -- stamps this column the first time it resolves one.
19
+ ALTER TABLE "mail_servers" ADD COLUMN IF NOT EXISTS "webmail_project_id" text;--> statement-breakpoint
20
+
21
+ DO $$ BEGIN
22
+ ALTER TABLE "mail_servers" ADD CONSTRAINT "mail_servers_webmail_project_id_project_id_fk"
23
+ FOREIGN KEY ("webmail_project_id") REFERENCES "public"."project"("id") ON DELETE set null ON UPDATE no action;
24
+ EXCEPTION WHEN duplicate_object THEN NULL; END $$;
@@ -0,0 +1,11 @@
1
+ -- Pasted / uploaded SSH private-key material, stored encrypted at rest (enc1:).
2
+ --
3
+ -- Nullable with no default. The existing `ssh_key_path` points at a key file on
4
+ -- the API host — useless on a remote / VPS instance where the operator's key
5
+ -- lives on their own machine. This column holds the key bytes themselves so the
6
+ -- dashboard can paste or upload a key from any browser; buildSshConfig() prefers
7
+ -- it (decrypted) over reading `ssh_key_path` off disk.
8
+ --
9
+ -- Write-only: never serialized back to the client, and listed in
10
+ -- ENCRYPTED_COLUMNS so it is stripped from any cross-host dump/restore.
11
+ ALTER TABLE "servers" ADD COLUMN IF NOT EXISTS "ssh_private_key" text;
@@ -0,0 +1,12 @@
1
+ -- The setup step an incomplete mail install is paused at, mirrored from the
2
+ -- on-host state file's `resumeStep` whenever the wizard halts (a failed step,
3
+ -- or a DNS/PTR hold). NULL once the install completes or before it ever halts.
4
+ --
5
+ -- Lets the /emails server list surface WHERE an incomplete install stopped
6
+ -- ("Stopped · step 6: Retrieve DKIM Keys") without the per-server SSH probe
7
+ -- this table exists to avoid — only the step id is stored; the human label is
8
+ -- derived from it against MAIL_SETUP_STEPS.
9
+ --
10
+ -- Nullable, no default, no backfill: a pre-existing incomplete install gets its
11
+ -- step stamped the next time the wizard halts (or cleared on completion).
12
+ ALTER TABLE "mail_servers" ADD COLUMN IF NOT EXISTS "resume_step" integer;
@@ -0,0 +1,19 @@
1
+ -- Deployment-class axes — deconflate the legacy `has_server` / `has_build`
2
+ -- booleans, which each mixed two independent concerns (issue #538). See
3
+ -- @repo/core deployment-class.ts.
4
+ --
5
+ -- All three are EXPLICIT OVERRIDES: NULL means "derive from the legacy flags +
6
+ -- framework + source", so every pre-existing project keeps classifying exactly
7
+ -- as before and no backfill is needed. `has_server` / `has_build` are kept and
8
+ -- written in sync, never dropped — rollback snapshots and every legacy reader
9
+ -- still depend on them.
10
+ --
11
+ -- source_kind text "git" | "image" | "upload" (git needs a clone)
12
+ -- build_kind text "dockerfile" | "buildpack" | "static" | "prebuilt"
13
+ -- workload_type text "web" | "worker" | "static" (worker = portless
14
+ -- long-running container: no port, no route)
15
+ ALTER TABLE "project" ADD COLUMN IF NOT EXISTS "source_kind" text;
16
+ --> statement-breakpoint
17
+ ALTER TABLE "project" ADD COLUMN IF NOT EXISTS "build_kind" text;
18
+ --> statement-breakpoint
19
+ ALTER TABLE "project" ADD COLUMN IF NOT EXISTS "workload_type" text;
@@ -0,0 +1,41 @@
1
+ -- DNS provider credentials — the token that lets Openship write a domain's records.
2
+ --
3
+ -- Adding a custom domain has always ended the same way: Openship computes the exact
4
+ -- A/CNAME + `_openship-challenge` TXT records and then asks the operator to go paste
5
+ -- them somewhere else. Every minute between "added" and "pasted" is a domain that
6
+ -- doesn't resolve, can't pass ACME, and looks broken. With a scoped provider token we
7
+ -- write those records ourselves and the domain verifies on its own.
8
+ --
9
+ -- The token is the sensitive part: Zone:Read + DNS:Edit can rewrite every record in
10
+ -- every zone it can see, so it is stored ONLY as an `enc1:` AES-256-GCM envelope
11
+ -- (`encryptSecretField`) and is never returned by the API — not in full, not as a
12
+ -- prefix. `status` exists so a token that gets revoked upstream becomes visible in the
13
+ -- UI instead of silently turning auto-provisioning off forever.
14
+ CREATE TABLE IF NOT EXISTS "dns_credential" (
15
+ "id" text PRIMARY KEY NOT NULL,
16
+ "organization_id" text NOT NULL REFERENCES "organization"("id") ON DELETE CASCADE,
17
+ -- Provider name ("cloudflare"). Text, not an enum: adding a provider should be a
18
+ -- registry entry, not a migration.
19
+ "provider" text NOT NULL,
20
+ -- Operator-facing label, e.g. "Cloudflare production".
21
+ "name" text NOT NULL,
22
+ "api_token_enc" text NOT NULL,
23
+ -- active | invalid. Flipped to 'invalid' by the provisioning path when the provider
24
+ -- answers 401/403, which is the only moment we learn a stored token stopped working.
25
+ "status" text NOT NULL DEFAULT 'active',
26
+ "last_verified_at" timestamp,
27
+ "created_at" timestamp NOT NULL DEFAULT now(),
28
+ "updated_at" timestamp NOT NULL DEFAULT now()
29
+ );
30
+ --> statement-breakpoint
31
+ -- Zone resolution runs on EVERY domain add and remove and asks one question: "this
32
+ -- org's active credentials". Leading org column means the plain org-wide listing rides
33
+ -- the same index as a prefix, so this is the only one the table needs.
34
+ CREATE INDEX IF NOT EXISTS "idx_dns_credential_org_status"
35
+ ON "dns_credential" ("organization_id", "status");
36
+ --> statement-breakpoint
37
+ -- One label per provider per org. A second "Cloudflare production" is a double-submit,
38
+ -- and two credentials that resolve the same zone makes "which token wrote this record"
39
+ -- unanswerable at cleanup time.
40
+ CREATE UNIQUE INDEX IF NOT EXISTS "uq_dns_credential_org_provider_name"
41
+ ON "dns_credential" ("organization_id", "provider", "name");
@@ -0,0 +1,15 @@
1
+ -- Runtime host-control toggle (#527): may OpenShip deploy to the machine it runs on?
2
+ --
3
+ -- Nullable with NO default, deliberately — the same contract as product_mode
4
+ -- (0098). The instance_settings row exists on every instance, so a NOT NULL
5
+ -- DEFAULT would write a concrete value everywhere and permanently shadow the
6
+ -- OPENSHIP_HOST_CONTROL env var (written by `openship up --no-host-control`).
7
+ -- The resolver reads `settings.host_control_enabled ?? env`, so "unset" has to
8
+ -- stay representable. NULL means "no instance override, use env".
9
+ --
10
+ -- Unlike product_mode this DOES gate privileged behavior (host-root deploys via
11
+ -- the container->host SSH channel + mounted docker socket), so the WRITE path is
12
+ -- gated to the box-owning org's owner. The precedence still lets the DB override
13
+ -- env: the operator's need is to re-enable from Settings what --no-host-control
14
+ -- turned off.
15
+ ALTER TABLE "instance_settings" ADD COLUMN IF NOT EXISTS "host_control_enabled" boolean;
@@ -687,6 +687,55 @@
687
687
  "when": 1787350907325,
688
688
  "tag": "0097_update_status_upstream_only",
689
689
  "breakpoints": true
690
+ },
691
+ {
692
+ "idx": 98,
693
+ "version": "7",
694
+ "when": 1787437307325,
695
+ "tag": "0098_instance_product_mode",
696
+ "breakpoints": true
697
+ },
698
+ {
699
+ "idx": 99,
700
+ "version": "7",
701
+ "when": 1787523707325,
702
+ "tag": "0099_mail_webmail_project",
703
+ "breakpoints": true
704
+ },
705
+ {
706
+ "idx": 100,
707
+ "version": "7",
708
+ "when": 1787610107325,
709
+ "tag": "0100_server_ssh_private_key",
710
+ "breakpoints": true
711
+ },
712
+ {
713
+ "idx": 101,
714
+ "version": "7",
715
+ "when": 1787696507325,
716
+ "tag": "0101_mail_resume_step",
717
+ "breakpoints": true
718
+ },
719
+ {
720
+ "idx": 102,
721
+ "version": "7",
722
+ "when": 1787782907325,
723
+ "tag": "0102_project_workload_axes",
724
+ "breakpoints": true
725
+ },
726
+ {
727
+ "idx": 103,
728
+ "version": "7",
729
+ "when": 1787869307325,
730
+ "tag": "0103_dns_credential",
731
+ "breakpoints": true
732
+ },
733
+ {
734
+ "idx": 104,
735
+ "version": "7",
736
+ "when": 1787955707325,
737
+ "tag": "0104_instance_host_control",
738
+ "breakpoints": true
690
739
  }
691
740
  ]
692
741
  }
@@ -4,17 +4,18 @@ import { createRequire as __ospCreateRequire } from "node:module";
4
4
  const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  SystemManager
7
- } from "./chunk-3NZICQHF.js";
8
- import "./chunk-IOT5ZX23.js";
9
- import "./chunk-IW2UKBVF.js";
10
- import "./chunk-ZCFVHA25.js";
11
- import "./chunk-EW6KB2J7.js";
7
+ } from "./chunk-XVOBL7BC.js";
8
+ import "./chunk-7334NSJL.js";
9
+ import "./chunk-VLQ3UIVO.js";
12
10
  import "./chunk-I3DPMTSF.js";
13
- import "./chunk-VZ2ZHPS2.js";
14
- import "./chunk-3LDWWY7U.js";
15
- import "./chunk-YIPMDGG6.js";
11
+ import "./chunk-RFWJE7ZN.js";
12
+ import "./chunk-WE7BXW6L.js";
13
+ import "./chunk-A7EWM2KA.js";
14
+ import "./chunk-PZRRL5PC.js";
15
+ import "./chunk-EZPPTWJQ.js";
16
+ import "./chunk-WFRXYWK2.js";
16
17
  import "./chunk-ZFJXPCQP.js";
17
- import "./chunk-OTLSJYAC.js";
18
+ import "./chunk-LEYSL46B.js";
18
19
  import "./chunk-PXKCZB2I.js";
19
20
  export {
20
21
  SystemManager
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env sh
2
+ ":" //# ; exec "$(command -v node || command -v bun)" "$0" "$@"
3
+ import { createRequire as __ospCreateRequire } from "node:module";
4
+ const require = __ospCreateRequire(import.meta.url);
5
+ import {
6
+ ensureInternalToken,
7
+ normalizeUrl,
8
+ runHeadlessProvision,
9
+ startService,
10
+ upCommand
11
+ } from "./chunk-7S4USQYF.js";
12
+ import "./chunk-6HOA5JT7.js";
13
+ import "./chunk-HPXP6LXZ.js";
14
+ import "./chunk-XRNRT37W.js";
15
+ import "./chunk-QLX7NBEA.js";
16
+ import "./chunk-QWHBRY2K.js";
17
+ import "./chunk-ELGRMZOW.js";
18
+ import "./chunk-ONKEYSMY.js";
19
+ import "./chunk-XZYFZ6A5.js";
20
+ import "./chunk-PDW4L3NV.js";
21
+ import "./chunk-DOD2BXHQ.js";
22
+ import "./chunk-42WQABXM.js";
23
+ import "./chunk-DRK3MEDS.js";
24
+ import "./chunk-3NQQXMDR.js";
25
+ import "./chunk-ZWLDLTJP.js";
26
+ import "./chunk-6JELW75A.js";
27
+ import "./chunk-3ZAGC5NT.js";
28
+ import "./chunk-WNWQBB7F.js";
29
+ import "./chunk-2GWYYHOR.js";
30
+ import "./chunk-RXQBD4ZY.js";
31
+ import "./chunk-XVOBL7BC.js";
32
+ import "./chunk-7334NSJL.js";
33
+ import "./chunk-VLQ3UIVO.js";
34
+ import "./chunk-I3DPMTSF.js";
35
+ import "./chunk-VDESJSG6.js";
36
+ import "./chunk-LFCSC4IU.js";
37
+ import "./chunk-GRTXMUHA.js";
38
+ import "./chunk-MSZUCNPV.js";
39
+ import "./chunk-TM2IQPYU.js";
40
+ import "./chunk-VHMOQL5Y.js";
41
+ import "./chunk-5OUWIPOB.js";
42
+ import "./chunk-6FH4AXVY.js";
43
+ import "./chunk-RFWJE7ZN.js";
44
+ import "./chunk-WE7BXW6L.js";
45
+ import "./chunk-A7EWM2KA.js";
46
+ import "./chunk-PZRRL5PC.js";
47
+ import "./chunk-EZPPTWJQ.js";
48
+ import "./chunk-WFRXYWK2.js";
49
+ import "./chunk-ZFJXPCQP.js";
50
+ import "./chunk-LEYSL46B.js";
51
+ import "./chunk-PXKCZB2I.js";
52
+ export {
53
+ ensureInternalToken,
54
+ normalizeUrl,
55
+ runHeadlessProvision,
56
+ startService,
57
+ upCommand
58
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openship",
3
- "version": "0.6.1",
3
+ "version": "0.6.5",
4
4
  "description": "Openship CLI - deploy, manage, and open your Openship platform from the terminal",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -20,6 +20,9 @@
20
20
  "bin": {
21
21
  "openship": "./dist/node-entry.js"
22
22
  },
23
+ "engines": {
24
+ "node": ">=22"
25
+ },
23
26
  "files": [
24
27
  "dist",
25
28
  "README.md"
@@ -42,7 +45,6 @@
42
45
  "commander": "^14.0.3",
43
46
  "dockerode": "^4.0.9",
44
47
  "open": "^10.2.0",
45
- "openship": "^0.5.0",
46
48
  "ora": "^9.3.0",
47
49
  "ssh2": "^1.17.0"
48
50
  },
@@ -1,144 +0,0 @@
1
- #!/usr/bin/env sh
2
- ":" //# ; exec "$(command -v node || command -v bun)" "$0" "$@"
3
- import { createRequire as __ospCreateRequire } from "node:module";
4
- const require = __ospCreateRequire(import.meta.url);
5
- import {
6
- formatDuration,
7
- isRemoteConnectionError,
8
- systemDebug
9
- } from "./chunk-ZCFVHA25.js";
10
- import {
11
- safeErrorMessage
12
- } from "./chunk-OTLSJYAC.js";
13
-
14
- // ../../packages/adapters/src/system/environment.ts
15
- var profileCache = /* @__PURE__ */ new WeakMap();
16
- async function execSafe(executor, command, timeout = 5e3) {
17
- const startedAt = Date.now();
18
- systemDebug("environment", `exec:start ${command}`);
19
- try {
20
- const result = await executor.exec(command, { timeout });
21
- systemDebug(
22
- "environment",
23
- `exec:ok ${command} (${formatDuration(startedAt)})`
24
- );
25
- return result;
26
- } catch (err) {
27
- if (isRemoteConnectionError(err)) {
28
- systemDebug(
29
- "environment",
30
- `exec:abort ${command} (${formatDuration(startedAt)}) ${safeErrorMessage(err)}`
31
- );
32
- throw err;
33
- }
34
- const msg = safeErrorMessage(err);
35
- systemDebug(
36
- "environment",
37
- `exec:fail ${command} (${formatDuration(startedAt)}) ${msg}`
38
- );
39
- return null;
40
- }
41
- }
42
- function parseOs(uname) {
43
- const value = uname?.trim().toLowerCase();
44
- if (value === "linux") return "linux";
45
- if (value === "darwin") return "darwin";
46
- return "unknown";
47
- }
48
- function parseArch(uname) {
49
- const value = uname?.trim().toLowerCase() ?? "";
50
- if (["x86_64", "amd64"].includes(value)) return "amd64";
51
- if (["aarch64", "arm64"].includes(value)) return "arm64";
52
- return "unknown";
53
- }
54
- function parseDistro(osRelease) {
55
- if (!osRelease) return null;
56
- const lower = osRelease.toLowerCase();
57
- const match = lower.match(/^id=(.+)$/m);
58
- const id = match?.[1]?.replaceAll('"', "").trim();
59
- switch (id) {
60
- case "ubuntu":
61
- return "ubuntu";
62
- case "debian":
63
- return "debian";
64
- case "fedora":
65
- return "fedora";
66
- case "rhel":
67
- case "rhel server":
68
- return "rhel";
69
- case "centos":
70
- return "centos";
71
- case "alpine":
72
- return "alpine";
73
- default:
74
- return "unknown";
75
- }
76
- }
77
- async function detectPackageManager(executor) {
78
- const checks = [
79
- ["apt", "command -v apt-get"],
80
- ["dnf", "command -v dnf"],
81
- ["yum", "command -v yum"],
82
- ["apk", "command -v apk"],
83
- ["brew", "command -v brew"]
84
- ];
85
- for (const [pm, command] of checks) {
86
- if (await execSafe(executor, command)) return pm;
87
- }
88
- return "none";
89
- }
90
- async function detectServiceManager(executor) {
91
- if (await execSafe(executor, "command -v systemctl")) return "systemd";
92
- if (await execSafe(executor, "command -v launchctl")) return "launchd";
93
- return "none";
94
- }
95
- async function detectPrivilege(executor) {
96
- const uid = await execSafe(executor, "id -u");
97
- const isRoot = uid?.trim() === "0";
98
- if (isRoot) return { isRoot: true, canSudo: false };
99
- const sudo = await execSafe(
100
- executor,
101
- "sudo -n true 2>/dev/null && echo yes || echo no"
102
- );
103
- return { isRoot: false, canSudo: sudo?.trim() === "yes" };
104
- }
105
- async function detectProfile(executor) {
106
- const startedAt = Date.now();
107
- systemDebug("environment", "detect:start");
108
- const unameOs = await execSafe(executor, "uname -s");
109
- const unameArch = await execSafe(executor, "uname -m");
110
- const osRelease = await execSafe(executor, "cat /etc/os-release");
111
- const packageManager = await detectPackageManager(executor);
112
- const serviceManager = await detectServiceManager(executor);
113
- const { isRoot, canSudo } = await detectPrivilege(executor);
114
- const os = parseOs(unameOs);
115
- const profile = {
116
- os,
117
- arch: parseArch(unameArch),
118
- distro: os === "linux" ? parseDistro(osRelease) : null,
119
- packageManager,
120
- serviceManager,
121
- isRoot,
122
- canSudo
123
- };
124
- systemDebug(
125
- "environment",
126
- `detect:done (${formatDuration(startedAt)}) ${JSON.stringify(profile)}`
127
- );
128
- return profile;
129
- }
130
- async function resolveEnvironment(executor) {
131
- let promise = profileCache.get(executor);
132
- if (!promise) {
133
- systemDebug("environment", "cache:miss");
134
- promise = detectProfile(executor);
135
- profileCache.set(executor, promise);
136
- } else {
137
- systemDebug("environment", "cache:hit");
138
- }
139
- return promise;
140
- }
141
-
142
- export {
143
- resolveEnvironment
144
- };
@@ -1,89 +0,0 @@
1
- #!/usr/bin/env sh
2
- ":" //# ; exec "$(command -v node || command -v bun)" "$0" "$@"
3
- import { createRequire as __ospCreateRequire } from "node:module";
4
- const require = __ospCreateRequire(import.meta.url);
5
-
6
- // ../../packages/adapters/src/system/errors.ts
7
- var SSH_AUTH_ERROR_PATTERNS = [
8
- "All configured authentication methods failed"
9
- ];
10
- var RETRYABLE_CONNECTION_ERROR_PATTERNS = [
11
- "ECONNRESET",
12
- "ECONNREFUSED",
13
- "ETIMEDOUT",
14
- "EHOSTUNREACH",
15
- "ENETUNREACH",
16
- "Timed out",
17
- "Not connected",
18
- "Connection lost",
19
- "read ECONNRESET",
20
- "Handshake failed",
21
- "keepalive timeout",
22
- "SSH connection closed before ready",
23
- // ssh2 emits "Channel open failure: open failed" / "Channel open failure: …"
24
- // when the SSH SERVER refuses a new channel - typically because the cached
25
- // connection has gone half-dead (peer-side LOGOUT, network blip,
26
- // remote sshd MaxSessions). The inner SshExecutor retries `exec`/
27
- // `streamExec` on this, but `pipeLocal`, `transferIn`, and any other
28
- // channel-bearing op bubble it up. Listing it here lets `withExecutor`
29
- // drop the dead connection and retry transparently - fixes the
30
- // "first redeploy fails, second click works" pattern.
31
- "Channel open failure",
32
- "open failed"
33
- ];
34
- var SshDisconnectedError = class extends Error {
35
- constructor(message = "SSH connection lost") {
36
- super(message);
37
- this.name = "SshDisconnectedError";
38
- }
39
- };
40
- function isSshDisconnectedError(err) {
41
- return err instanceof SshDisconnectedError || err instanceof Error && err.name === "SshDisconnectedError";
42
- }
43
- function isSshAuthError(err) {
44
- if (!(err instanceof Error)) return false;
45
- return SSH_AUTH_ERROR_PATTERNS.some((pattern) => err.message.includes(pattern));
46
- }
47
- function isRetryableRemoteConnectionError(err) {
48
- if (isSshDisconnectedError(err)) return true;
49
- if (!(err instanceof Error)) return false;
50
- return RETRYABLE_CONNECTION_ERROR_PATTERNS.some(
51
- (pattern) => err.message.includes(pattern)
52
- );
53
- }
54
- function isRemoteConnectionError(err) {
55
- return isSshAuthError(err) || isRetryableRemoteConnectionError(err);
56
- }
57
- function isRuntimeNotFoundError(err) {
58
- if (!err || typeof err !== "object") return false;
59
- const e = err;
60
- if (e.statusCode === 404) return true;
61
- return typeof e.message === "string" && /no such (container|image|volume|network)/i.test(e.message);
62
- }
63
-
64
- // ../../packages/adapters/src/system/debug.ts
65
- function isTruthy(value) {
66
- if (!value) return false;
67
- return ["1", "true", "yes", "on", "debug"].includes(value.toLowerCase());
68
- }
69
- function isSystemDebugEnabled() {
70
- return isTruthy(process.env.SYSTEM_DEBUG_LOGS);
71
- }
72
- function systemDebug(scope, message) {
73
- if (!isSystemDebugEnabled()) return;
74
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
75
- console.log(`[system-debug] ${timestamp} [${scope}] ${message}`);
76
- }
77
- function formatDuration(startMs) {
78
- return `${Date.now() - startMs}ms`;
79
- }
80
-
81
- export {
82
- SshDisconnectedError,
83
- isSshAuthError,
84
- isRetryableRemoteConnectionError,
85
- isRemoteConnectionError,
86
- isRuntimeNotFoundError,
87
- systemDebug,
88
- formatDuration
89
- };
@@ -1,31 +0,0 @@
1
- #!/usr/bin/env sh
2
- ":" //# ; exec "$(command -v node || command -v bun)" "$0" "$@"
3
- import { createRequire as __ospCreateRequire } from "node:module";
4
- const require = __ospCreateRequire(import.meta.url);
5
- import {
6
- CloudRuntime,
7
- PAGE_CONTAINER_PREFIX,
8
- provisionCloudWorkspace
9
- } from "./chunk-RRJJGVKE.js";
10
- import "./chunk-IOT5ZX23.js";
11
- import "./chunk-EMXI4UCU.js";
12
- import "./chunk-JIMUYEKN.js";
13
- import "./chunk-IW2UKBVF.js";
14
- import "./chunk-VDDMADOF.js";
15
- import "./chunk-UC7YIEHT.js";
16
- import "./chunk-6ODUBKUB.js";
17
- import "./chunk-ZCFVHA25.js";
18
- import "./chunk-6FH4AXVY.js";
19
- import "./chunk-EW6KB2J7.js";
20
- import "./chunk-I3DPMTSF.js";
21
- import "./chunk-VZ2ZHPS2.js";
22
- import "./chunk-3LDWWY7U.js";
23
- import "./chunk-YIPMDGG6.js";
24
- import "./chunk-ZFJXPCQP.js";
25
- import "./chunk-OTLSJYAC.js";
26
- import "./chunk-PXKCZB2I.js";
27
- export {
28
- CloudRuntime,
29
- PAGE_CONTAINER_PREFIX,
30
- provisionCloudWorkspace
31
- };