@automagik/omni 2.260405.3 → 2.260407.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsQpC,wBAAgB,iBAAiB,IAAI,OAAO,CAiI3C"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuRpC,wBAAgB,iBAAiB,IAAI,OAAO,CAiI3C"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Doctor Command
3
+ *
4
+ * omni doctor [--fix] [--json] [--verbose]
5
+ *
6
+ * In-place diagnose + repair for the embedded-omni runtime. This is the
7
+ * command operators are pointed at when `omni update` reports a version
8
+ * mismatch or an auth failure after a restart.
9
+ *
10
+ * Checks performed, in order:
11
+ * 1. pm2-env-drift — pm2-stored env for omni-api vs. buildRuntimeEnv()
12
+ * 2. cli-key-valid — stored CLI key still validates against the server
13
+ * 3. pgserve-reachable — TCP connect to localhost:PGSERVE_PORT
14
+ * 4. omni-db-exists — `omni` database exists on the embedded pgserve
15
+ * 5. orphaned-data-dirs — `.pgserve-data/` directories under cwd
16
+ * 6. version-match — CLI version vs. /api/v2/health `version` field
17
+ * 7. pm2-status — omni-api and omni-nats both `online` in pm2
18
+ *
19
+ * Each check returns OK / WARN / FAIL with a one-line detail. `--fix`
20
+ * attempts repair for checks with a known repair path. The fix flow
21
+ * NEVER touches `~/.omni/data/pgserve/` — that safety constraint is
22
+ * load-bearing and has a dedicated mutation-safety test.
23
+ *
24
+ * Repair paths:
25
+ * - pm2-env-drift: `pm2 delete omni-api` + re-launch via the same code
26
+ * path used by `omni start`, with a sanitized env.
27
+ * - cli-key-valid: Delete `__primary__` from api_keys, restart with a
28
+ * freshly generated OMNI_API_KEY, re-validate, write
29
+ * the new key to `~/.omni/config.json`.
30
+ * - orphaned-data-dirs: Print `rm -rf` commands for the user to review
31
+ * (we never auto-delete data directories).
32
+ */
33
+ import { Command } from 'commander';
34
+ import { type Config, type ServerConfig } from '../config.js';
35
+ /** Severity levels reported by each check. */
36
+ export type CheckLevel = 'OK' | 'WARN' | 'FAIL';
37
+ /** Identifier used in tests and --json output. */
38
+ export type CheckId = 'pm2-env-drift' | 'cli-key-valid' | 'pgserve-reachable' | 'omni-db-exists' | 'orphaned-data-dirs' | 'version-match' | 'pm2-status';
39
+ export interface CheckResult {
40
+ id: CheckId;
41
+ level: CheckLevel;
42
+ detail: string;
43
+ }
44
+ export interface DoctorReport {
45
+ checks: CheckResult[];
46
+ summary: {
47
+ ok: number;
48
+ warn: number;
49
+ fail: number;
50
+ };
51
+ fixesApplied: string[];
52
+ }
53
+ export interface DoctorOptions {
54
+ fix?: boolean;
55
+ json?: boolean;
56
+ verbose?: boolean;
57
+ }
58
+ /**
59
+ * Narrow shape of a pm2 process entry from `pm2 jlist`. We only care about
60
+ * fields relevant to env-drift and status checks.
61
+ */
62
+ interface Pm2Entry {
63
+ name?: string;
64
+ pm_id?: number;
65
+ pm2_env?: {
66
+ status?: string;
67
+ env?: Record<string, string | undefined>;
68
+ pm_exec_path?: string;
69
+ args?: string[];
70
+ interpreter?: string;
71
+ OMNI_API_KEY?: string;
72
+ DATABASE_URL?: string;
73
+ PGSERVE_DATA?: string;
74
+ API_PORT?: string;
75
+ NODE_ENV?: string;
76
+ LOG_LEVEL?: string;
77
+ } & Record<string, unknown>;
78
+ }
79
+ /** Shape injected by the test harness to mock slow/external inputs. */
80
+ export interface DoctorDeps {
81
+ /** Return all pm2 processes (or null on error). */
82
+ getPm2Processes: () => Promise<Pm2Entry[] | null>;
83
+ /** Return true if a TCP connect to localhost:port succeeds. */
84
+ canConnect: (port: number) => Promise<boolean>;
85
+ /** Return true if the omni database exists on the embedded pgserve. */
86
+ omniDbExists: () => Promise<boolean>;
87
+ /** Walk the filesystem for orphaned `.pgserve-data` directories. */
88
+ findOrphanedDataDirs: () => string[];
89
+ /** Fetch the health body from the running server. */
90
+ fetchHealthVersion: (apiPort: number) => Promise<string | null>;
91
+ /** Validate the stored CLI key against the running server. */
92
+ validateStoredKey: (apiPort: number) => Promise<boolean>;
93
+ /** Return the current `~/.omni/` configs. */
94
+ loadState: () => {
95
+ serverConfig: ServerConfig;
96
+ cliConfig: Config;
97
+ };
98
+ /**
99
+ * Run a pm2 command. Returns the exit code. Tests stub this with a no-op
100
+ * to prevent fix handlers from actually mutating the host's pm2 state.
101
+ */
102
+ runPm2: (args: string[], env?: Record<string, string>) => Promise<number>;
103
+ /** Persist a new CLI config. Tests stub this to in-memory state. */
104
+ saveCliConfig: (config: Config) => void;
105
+ /** Re-read the CLI config from disk (stubbed in tests). */
106
+ reloadCliConfig: () => Config;
107
+ /** Generate a new API key. Tests stub for determinism. */
108
+ generateApiKey: () => string;
109
+ /** Sleep briefly after a pm2 restart. Tests stub to zero-delay. */
110
+ sleepMs: (ms: number) => Promise<void>;
111
+ }
112
+ /**
113
+ * Run all checks and optionally apply fixes. Returns a structured
114
+ * DoctorReport — the caller decides how to render it (human vs. JSON).
115
+ */
116
+ export declare function runDoctor(options: DoctorOptions, depsOverride?: DoctorDeps): Promise<DoctorReport>;
117
+ export declare function createDoctorCommand(): Command;
118
+ export {};
119
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -16,5 +16,28 @@
16
16
  * 10. Done banner + next steps
17
17
  */
18
18
  import { Command } from 'commander';
19
+ /**
20
+ * Compute the default database URL for the install wizard.
21
+ *
22
+ * Embedded mode is the default and derives the URL from the configured
23
+ * pgserve port (never from the calling shell, which has historically
24
+ * leaked foreign databases into omni-api via pm2's stored env). If an
25
+ * operator wants to point omni at an external PostgreSQL they must pass
26
+ * `--database-url <url>` explicitly — an opt-in signal that the external
27
+ * URL is intentional and not an accidental shell export.
28
+ *
29
+ * Exported so `install-env-leak.test.ts` can assert hermeticity.
30
+ */
31
+ export declare function computeDefaultDatabaseUrl(): string;
32
+ /**
33
+ * Resolve the `databaseUrl` that will be written to `~/.omni/config.json`.
34
+ * Exported for hermeticity tests. Never reads the calling shell's env.
35
+ *
36
+ * @param options.databaseUrlFlag — the explicit `--database-url` value, if
37
+ * the operator passed one. Opt-in external-DB mode.
38
+ */
39
+ export declare function resolveInstallDatabaseUrl(options: {
40
+ databaseUrlFlag?: string;
41
+ }): string;
19
42
  export declare function createInstallCommand(): Command;
20
43
  //# sourceMappingURL=install.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+kBpC,wBAAgB,oBAAoB,IAAI,OAAO,CAO9C"}
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoBpC;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,CAElD;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE;IAAE,eAAe,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAMvF;AA0kBD,wBAAgB,oBAAoB,IAAI,OAAO,CAQ9C"}
@@ -2,6 +2,13 @@
2
2
  * Restart Command
3
3
  *
4
4
  * omni restart — Restart omni PM2 processes and wait for health check
5
+ *
6
+ * IMPORTANT: This command does NOT ask pm2 to re-read the shell environment
7
+ * on restart. Doing so would re-introduce env-pollution bugs (e.g. stray
8
+ * `DATABASE_URL` from a parent tmux session leaking into omni-api). Instead,
9
+ * we rely on the env that was captured at original `pm2 start` time (built
10
+ * by `buildRuntimeEnv` from config). If the stored env is stale, use
11
+ * `omni doctor --fix` to rebuild it deterministically.
5
12
  */
6
13
  import { Command } from 'commander';
7
14
  export declare function createRestartCommand(): Command;
@@ -1 +1 @@
1
- {"version":3,"file":"restart.d.ts","sourceRoot":"","sources":["../../src/commands/restart.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuEpC,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C"}
1
+ {"version":3,"file":"restart.d.ts","sourceRoot":"","sources":["../../src/commands/restart.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoDpC,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C"}
@@ -1 +1 @@
1
- {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiGpC,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C"}
1
+ {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0EpC,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C"}
@@ -6,9 +6,64 @@
6
6
  * Self-update from npm: checks latest @automagik/omni version, prompts the
7
7
  * user (unless --yes), installs with `bun add -g`, and restarts PM2 services
8
8
  * only if they were already running. When that restart path runs, update
9
- * checks API health on the configured API port; if restart or health checks
10
- * fail, exits non-zero and points operators to `omni status`.
9
+ * performs a 3-step visible verification:
10
+ *
11
+ * 1. CLI version matches `package.json` (trivial — known at compile time).
12
+ * 2. Server version matches the newly-installed CLI version (fetched from
13
+ * `/api/v2/health`). If not, update exits non-zero and tells the
14
+ * operator to run `omni doctor`.
15
+ * 3. The stored API key still validates against the (restarted) server. If
16
+ * not, update exits non-zero and tells the operator to run
17
+ * `omni doctor --fix`.
18
+ *
19
+ * This replaces the previous silent-success path where the CLI would report
20
+ * "updated to vX" even when the server was still running the old version or
21
+ * when the stored key no longer validated.
11
22
  */
12
23
  import { Command } from 'commander';
24
+ /** Shape of the `/api/v2/health` response we care about. */
25
+ export interface HealthBody {
26
+ status?: string;
27
+ version?: string;
28
+ }
29
+ /**
30
+ * Normalize a version string for comparison. Strips a git-hash suffix
31
+ * (e.g. `2.20260218.18+abc1234` → `2.20260218.18`) so build metadata doesn't
32
+ * trigger a spurious mismatch.
33
+ */
34
+ export declare function normalizeVersion(version: string): string;
35
+ /**
36
+ * Result of the pure 3-step update verification. Exported so tests can
37
+ * exercise the logic without mocking pm2 / fetch / process.exit.
38
+ */
39
+ export type UpdateVerifyResult = {
40
+ kind: 'ok';
41
+ cliVersion: string;
42
+ serverVersion: string;
43
+ } | {
44
+ kind: 'health-unreachable';
45
+ apiPort: number;
46
+ } | {
47
+ kind: 'version-mismatch';
48
+ cliVersion: string;
49
+ serverVersion: string | null;
50
+ } | {
51
+ kind: 'auth-invalid';
52
+ };
53
+ /**
54
+ * Pure decision function for update verification. Given the raw inputs
55
+ * (health body + key-valid flag + CLI version + port), return a tagged
56
+ * union describing the outcome. The caller decides how to render and
57
+ * whether to exit non-zero.
58
+ */
59
+ export declare function decideUpdateVerify(args: {
60
+ latest: string;
61
+ apiPort: number;
62
+ healthBody: HealthBody | null;
63
+ keyValid: boolean;
64
+ }): UpdateVerifyResult;
65
+ /** Error message strings — exported for tests and documentation. */
66
+ export declare function updateErrorVersionMismatch(cli: string, server: string | null): string;
67
+ export declare const UPDATE_ERROR_AUTH_INVALID = "Auth key invalid after restart. Run: omni doctor --fix";
13
68
  export declare function createUpdateCommand(): Command;
14
69
  //# sourceMappingURL=update.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA4LpC,wBAAgB,mBAAmB,IAAI,OAAO,CAkB7C"}
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAKH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA6HpC,4DAA4D;AAC5D,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC9E;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,CAAC;AAE7B;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,OAAO,CAAC;CACnB,GAAG,kBAAkB,CAarB;AAED,oEAAoE;AACpE,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAErF;AAED,eAAO,MAAM,yBAAyB,2DAA2D,CAAC;AAuOlG,wBAAgB,mBAAmB,IAAI,OAAO,CAmC7C"}