@pleri/olam-cli 0.1.128 → 0.1.131

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 (51) hide show
  1. package/dist/commands/bootstrap.d.ts +8 -0
  2. package/dist/commands/bootstrap.d.ts.map +1 -1
  3. package/dist/commands/bootstrap.js +14 -0
  4. package/dist/commands/bootstrap.js.map +1 -1
  5. package/dist/commands/kg-build.d.ts.map +1 -1
  6. package/dist/commands/kg-build.js +10 -0
  7. package/dist/commands/kg-build.js.map +1 -1
  8. package/dist/commands/kg-classify.d.ts +10 -0
  9. package/dist/commands/kg-classify.d.ts.map +1 -0
  10. package/dist/commands/kg-classify.js +51 -0
  11. package/dist/commands/kg-classify.js.map +1 -0
  12. package/dist/commands/kg-doctor.d.ts +15 -0
  13. package/dist/commands/kg-doctor.d.ts.map +1 -0
  14. package/dist/commands/kg-doctor.js +182 -0
  15. package/dist/commands/kg-doctor.js.map +1 -0
  16. package/dist/commands/kg-install-hook.d.ts +14 -0
  17. package/dist/commands/kg-install-hook.d.ts.map +1 -0
  18. package/dist/commands/kg-install-hook.js +92 -0
  19. package/dist/commands/kg-install-hook.js.map +1 -0
  20. package/dist/commands/kg-service-container.d.ts +68 -0
  21. package/dist/commands/kg-service-container.d.ts.map +1 -0
  22. package/dist/commands/kg-service-container.js +181 -0
  23. package/dist/commands/kg-service-container.js.map +1 -0
  24. package/dist/commands/kg-uninstall-hook.d.ts +12 -0
  25. package/dist/commands/kg-uninstall-hook.d.ts.map +1 -0
  26. package/dist/commands/kg-uninstall-hook.js +121 -0
  27. package/dist/commands/kg-uninstall-hook.js.map +1 -0
  28. package/dist/commands/memory/index.d.ts.map +1 -1
  29. package/dist/commands/memory/index.js +2 -0
  30. package/dist/commands/memory/index.js.map +1 -1
  31. package/dist/commands/memory/mode.d.ts +47 -0
  32. package/dist/commands/memory/mode.d.ts.map +1 -0
  33. package/dist/commands/memory/mode.js +181 -0
  34. package/dist/commands/memory/mode.js.map +1 -0
  35. package/dist/commands/rekey.d.ts +84 -0
  36. package/dist/commands/rekey.d.ts.map +1 -0
  37. package/dist/commands/rekey.js +209 -0
  38. package/dist/commands/rekey.js.map +1 -0
  39. package/dist/commands/services.d.ts +5 -5
  40. package/dist/commands/services.d.ts.map +1 -1
  41. package/dist/commands/services.js +70 -6
  42. package/dist/commands/services.js.map +1 -1
  43. package/dist/image-digests.json +3 -3
  44. package/dist/index.js +2091 -667
  45. package/dist/index.js.map +1 -1
  46. package/dist/lib/memory-secret.d.ts +22 -0
  47. package/dist/lib/memory-secret.d.ts.map +1 -1
  48. package/dist/lib/memory-secret.js +38 -0
  49. package/dist/lib/memory-secret.js.map +1 -1
  50. package/dist/mcp-server.js +18499 -17383
  51. package/package.json +1 -1
@@ -0,0 +1,181 @@
1
+ /**
2
+ * olam memory mode <local|cloud> — flip the workspace's agent-memory
3
+ * source between the host-process (Phase A) and a remote agentmemory
4
+ * deployment (Phase C).
5
+ *
6
+ * Reads + rewrites `.olam/config.yaml`'s `memory:` block via the schema
7
+ * defined in C1. Idempotent: re-running the same mode is a noop.
8
+ *
9
+ * mode local → memory.mode = "local"; ensures host-process running
10
+ * mode cloud [--url ...] → prompts for URL + bearer secret, writes both to
11
+ * config + ~/.olam/cloud-memory-secret, stops the
12
+ * local host-process. Operator must re-create
13
+ * active worlds for the new env to take effect.
14
+ *
15
+ * Plan reference: docs/plans/olam-agent-memory-distributed/phase-c-tasks.md C3
16
+ */
17
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
18
+ import { join } from 'node:path';
19
+ import * as readline from 'node:readline/promises';
20
+ import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
21
+ import { MemorySchema } from '@olam/core/src/config/schema.js';
22
+ import { printError, printSuccess, printInfo, printHeader, printWarning } from '../../output.js';
23
+ import { writeCloudMemorySecret, CLOUD_MEMORY_SECRET_PATH } from '../../lib/memory-secret.js';
24
+ import { runMemoryStart } from './start.js';
25
+ import { runMemoryStop } from './stop.js';
26
+ const CONFIG_REL = '.olam/config.yaml';
27
+ function locateConfig(cwd) {
28
+ const absPath = join(cwd, CONFIG_REL);
29
+ if (!existsSync(absPath)) {
30
+ throw new Error(`No ${CONFIG_REL} at ${cwd}. Run \`olam init\` in your workspace root first.`);
31
+ }
32
+ return { absPath };
33
+ }
34
+ function readConfigYaml(absPath) {
35
+ const raw = readFileSync(absPath, 'utf-8');
36
+ const parsed = (parseYaml(raw) ?? {});
37
+ if (typeof parsed !== 'object' || parsed === null) {
38
+ throw new Error(`${absPath} is not a YAML object`);
39
+ }
40
+ return { raw, parsed };
41
+ }
42
+ function writeConfigYaml(absPath, parsed) {
43
+ // `yaml`'s default stringify is reasonable for round-trip; we don't
44
+ // preserve every comment edge case but the major shape + keys survive.
45
+ const out = stringifyYaml(parsed, { aliasDuplicateObjects: false });
46
+ writeFileSync(absPath, out, 'utf-8');
47
+ }
48
+ async function defaultPromptText(question) {
49
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
50
+ try {
51
+ return (await rl.question(question)).trim();
52
+ }
53
+ finally {
54
+ rl.close();
55
+ }
56
+ }
57
+ /**
58
+ * Same shape as defaultPromptText for now — terminals don't natively mask
59
+ * input via readline. Operators wanting a masked prompt can pipe via stdin
60
+ * or pass `--secret` (NOT recommended; argv leaks via ps). The choice is
61
+ * deferred to OQ4: "no Keychain integration in v1; document the limitation"
62
+ * (design rubric S5).
63
+ */
64
+ async function defaultPromptSecret(question) {
65
+ return defaultPromptText(`${question} (will appear on-screen; use stdin to pipe) `);
66
+ }
67
+ export async function runMemoryModeLocal(deps = {}) {
68
+ const cwd = deps.cwd ?? process.cwd();
69
+ const cfg = locateConfig(cwd);
70
+ const { parsed } = readConfigYaml(cfg.absPath);
71
+ const currentMode = parsed.memory?.mode ?? 'local';
72
+ if (currentMode === 'local') {
73
+ printInfo('memory.mode', 'already local — ensuring host-process is up');
74
+ const rc = (deps.runStart ?? runMemoryStart)();
75
+ await rc;
76
+ return { outcome: 'noop', mode: 'local' };
77
+ }
78
+ // Flip: drop the cloud block (operator can re-cloud later via mode cloud)
79
+ parsed.memory = { mode: 'local' };
80
+ writeConfigYaml(cfg.absPath, parsed);
81
+ printSuccess(`flipped .olam/config.yaml memory.mode → local`);
82
+ printInfo('host-process', 'starting');
83
+ const rc = await (deps.runStart ?? runMemoryStart)();
84
+ if (rc !== 0) {
85
+ printWarning('local host-process failed to start. Config flipped but service is down — fix the underlying issue and run `olam memory start`.');
86
+ }
87
+ return { outcome: 'flipped-to-local' };
88
+ }
89
+ export async function runMemoryModeCloud(deps = {}) {
90
+ const cwd = deps.cwd ?? process.cwd();
91
+ const cfg = locateConfig(cwd);
92
+ const { parsed } = readConfigYaml(cfg.absPath);
93
+ const currentMem = (parsed.memory ?? {});
94
+ const currentMode = currentMem.mode ?? 'local';
95
+ // Resolve URL: --url flag wins, else interactive prompt.
96
+ let url = deps.url;
97
+ if (!url) {
98
+ const askText = deps.promptText ?? defaultPromptText;
99
+ url = (await askText('Cloud agentmemory URL (e.g. https://agentmemory.<you>.workers.dev): ')).trim();
100
+ }
101
+ if (!url) {
102
+ throw new Error('cloud URL is required');
103
+ }
104
+ // Validate via the C1 schema before writing.
105
+ const candidate = { mode: 'cloud', cloud: { url } };
106
+ const parsedMem = MemorySchema.safeParse(candidate);
107
+ if (!parsedMem.success) {
108
+ const msg = parsedMem.error.issues.map((i) => i.message).join('; ');
109
+ throw new Error(`invalid memory.cloud config: ${msg}`);
110
+ }
111
+ // Resolve secret: --secret flag wins, else interactive prompt. The
112
+ // secret is the bearer the operator already configured on the remote
113
+ // service (Cloudflare wrangler secret or equivalent). We persist it to
114
+ // ~/.olam/cloud-memory-secret 0600 so B1's env-resolver can inject it
115
+ // into worlds at spawn (C4 wires the read path).
116
+ let secret = deps.secret;
117
+ if (!secret) {
118
+ const askSecret = deps.promptSecret ?? defaultPromptSecret;
119
+ secret = await askSecret('Cloud agentmemory bearer secret (64-hex):');
120
+ }
121
+ if (!secret) {
122
+ throw new Error('cloud secret is required');
123
+ }
124
+ // Idempotency check: if already cloud-mode with the same URL, just refresh secret.
125
+ const sameUrl = currentMode === 'cloud' && currentMem.cloud?.url === url;
126
+ if (sameUrl) {
127
+ printInfo('memory.mode', `already cloud (url=${url}) — refreshing secret only`);
128
+ (deps.writeSecret ?? ((v) => writeCloudMemorySecret(v)))(secret);
129
+ return { outcome: 'noop', mode: 'cloud' };
130
+ }
131
+ // Stop local host-process first — fail-soft if it wasn't running.
132
+ printInfo('host-process', 'stopping (was running for local mode)');
133
+ await (deps.runStop ?? runMemoryStop)();
134
+ // Persist the secret BEFORE updating the config so worlds spawned
135
+ // between the writes see at most a transient "cloud but no secret"
136
+ // state rather than the inverse (config flipped, secret missing).
137
+ (deps.writeSecret ?? ((v) => writeCloudMemorySecret(v)))(secret);
138
+ printSuccess(`wrote cloud bearer secret to ${CLOUD_MEMORY_SECRET_PATH} (0600)`);
139
+ parsed.memory = {
140
+ mode: 'cloud',
141
+ cloud: {
142
+ url,
143
+ secret_ref: '~/.olam/cloud-memory-secret',
144
+ },
145
+ };
146
+ writeConfigYaml(cfg.absPath, parsed);
147
+ printSuccess(`flipped .olam/config.yaml memory.mode → cloud (${url})`);
148
+ printWarning('Worlds spawned BEFORE this flip still have the old env. Re-create them ' +
149
+ '(olam destroy + olam create) to pick up the new AGENTMEMORY_URL + secret.');
150
+ return { outcome: 'flipped-to-cloud', url };
151
+ }
152
+ export function registerMemoryMode(cmd) {
153
+ const mode = cmd
154
+ .command('mode <target>')
155
+ .description('Flip agent-memory source between local (host-process) and cloud (remote agentmemory deployment)')
156
+ .option('--url <url>', 'Cloud URL (skips the interactive prompt; mode cloud only)')
157
+ .option('--secret <value>', 'Cloud bearer secret (skips interactive prompt; argv-visible — prefer stdin)');
158
+ mode.action(async (target, opts) => {
159
+ printHeader(`olam memory mode ${target}`);
160
+ try {
161
+ if (target === 'local') {
162
+ await runMemoryModeLocal();
163
+ }
164
+ else if (target === 'cloud') {
165
+ await runMemoryModeCloud({
166
+ ...(opts.url !== undefined ? { url: opts.url } : {}),
167
+ ...(opts.secret !== undefined ? { secret: opts.secret } : {}),
168
+ });
169
+ }
170
+ else {
171
+ printError(`mode must be 'local' or 'cloud' (got: ${target})`);
172
+ process.exitCode = 1;
173
+ }
174
+ }
175
+ catch (err) {
176
+ printError(err instanceof Error ? err.message : String(err));
177
+ process.exitCode = 1;
178
+ }
179
+ });
180
+ }
181
+ //# sourceMappingURL=mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mode.js","sourceRoot":"","sources":["../../../src/commands/memory/mode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * `olam rekey <world-id>` — rotate the per-world postgres password.
3
+ *
4
+ * Phase A9 of `olam-hybrid-shared-postgres`. Phase A4 (commit 7b4334ff)
5
+ * landed `applyPostgresWorldRole` which already supports rotation via
6
+ * `ALTER ROLE` when the role exists. A9 exposes that rotation as a
7
+ * standalone operator-facing command, useful when:
8
+ *
9
+ * - The operator wants to force-rotate credentials (suspected leak).
10
+ * - A world container lost its env-injected password (e.g. crashed
11
+ * before the app read it).
12
+ * - A future tmpfs cred-mount flow needs a re-inject path.
13
+ *
14
+ * Flow:
15
+ * 1. Load context + WorldManager.getWorld(worldId).
16
+ * 2. Hybrid + DB gates (exit 3 if non-hybrid or no per-world DBs).
17
+ * 3. `applyPostgresWorldRole(id, worldDbNames)` → ALTER ROLE rotates
18
+ * the password atomically. The old password is gone.
19
+ * 4. Write new password to `~/.olam/worlds/<id>/credentials.json`
20
+ * (chmod 600).
21
+ * 5. `docker restart olam-<id>-devbox` so the container picks up the
22
+ * new password from env on next process start.
23
+ * 6. Audit-log line to `~/.olam/usage.log` (SEC-002): timestamp +
24
+ * world-id + "rekey" — NEVER the password.
25
+ *
26
+ * Exit codes:
27
+ * 0 success
28
+ * 1 unexpected error
29
+ * 2 world not found
30
+ * 3 precondition failed (non-hybrid, no DBs, etc.)
31
+ */
32
+ import type { Command } from 'commander';
33
+ import { type PostgresWorldRoleResult } from '@olam/core/src/world/manager.js';
34
+ import type { WorldMetadata } from '@olam/core/src/world/types.js';
35
+ export interface RekeyOptions {
36
+ readonly print?: boolean;
37
+ readonly json?: boolean;
38
+ }
39
+ export interface RekeyResult {
40
+ readonly worldId: string;
41
+ readonly worldRoleName: string;
42
+ readonly password: string;
43
+ readonly credentialsPath: string;
44
+ readonly rotatedAt: string;
45
+ readonly containerRestarted: boolean;
46
+ }
47
+ /**
48
+ * Minimal dependency surface used by {@link doRekey}. Pure-function
49
+ * injection lets tests run without docker, without disk writes outside
50
+ * the test's tmp dir, and without mocking modules.
51
+ */
52
+ export interface RekeyDeps {
53
+ readonly getWorld: (id: string) => WorldMetadata | undefined;
54
+ readonly applyPostgresWorldRole: (worldId: string, worldDbNames: ReadonlyArray<string>) => PostgresWorldRoleResult;
55
+ readonly restartContainer: (containerName: string) => {
56
+ ok: boolean;
57
+ stderr: string;
58
+ };
59
+ /** Override for tests. Default: real fs + ~/.olam. */
60
+ readonly olamHomeDir: () => string;
61
+ readonly now: () => Date;
62
+ /** Stream for human-readable lines (overridable for tests). */
63
+ readonly stdout: {
64
+ write(s: string): void;
65
+ };
66
+ /** Audit-log appender; default writes to `${olamHomeDir()}/usage.log`. */
67
+ readonly appendAuditLog: (line: string) => void;
68
+ }
69
+ /** Domain-specific error carrying the documented exit code. */
70
+ export declare class RekeyError extends Error {
71
+ readonly exitCode: number;
72
+ constructor(message: string, exitCode: number);
73
+ }
74
+ /**
75
+ * Core rekey logic. Returns the rotation result on success, throws
76
+ * {@link RekeyError} with the documented exit code on failure.
77
+ *
78
+ * The password is held in this function's local binding and the
79
+ * returned object only; it is written to disk with mode 0o600 and
80
+ * NEVER logged or written to the audit trail (SEC-002).
81
+ */
82
+ export declare function doRekey(worldId: string, deps: RekeyDeps): Promise<RekeyResult>;
83
+ export declare function registerRekey(program: Command): void;
84
+ //# sourceMappingURL=rekey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rekey.d.ts","sourceRoot":"","sources":["../../src/commands/rekey.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAcnE,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;CACtC;AAED;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,aAAa,GAAG,SAAS,CAAC;IAC7D,QAAQ,CAAC,sBAAsB,EAAE,CAC/B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,aAAa,CAAC,MAAM,CAAC,KAChC,uBAAuB,CAAC;IAC7B,QAAQ,CAAC,gBAAgB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACtF,sDAAsD;IACtD,QAAQ,CAAC,WAAW,EAAE,MAAM,MAAM,CAAC;IACnC,QAAQ,CAAC,GAAG,EAAE,MAAM,IAAI,CAAC;IACzB,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,EAAE;QAAE,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAC5C,0EAA0E;IAC1E,QAAQ,CAAC,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACjD;AAsCD,+DAA+D;AAC/D,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBACd,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAK9C;AAED;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAC3B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,GACd,OAAO,CAAC,WAAW,CAAC,CA0EtB;AAuBD,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAqCpD"}
@@ -0,0 +1,209 @@
1
+ /**
2
+ * `olam rekey <world-id>` — rotate the per-world postgres password.
3
+ *
4
+ * Phase A9 of `olam-hybrid-shared-postgres`. Phase A4 (commit 7b4334ff)
5
+ * landed `applyPostgresWorldRole` which already supports rotation via
6
+ * `ALTER ROLE` when the role exists. A9 exposes that rotation as a
7
+ * standalone operator-facing command, useful when:
8
+ *
9
+ * - The operator wants to force-rotate credentials (suspected leak).
10
+ * - A world container lost its env-injected password (e.g. crashed
11
+ * before the app read it).
12
+ * - A future tmpfs cred-mount flow needs a re-inject path.
13
+ *
14
+ * Flow:
15
+ * 1. Load context + WorldManager.getWorld(worldId).
16
+ * 2. Hybrid + DB gates (exit 3 if non-hybrid or no per-world DBs).
17
+ * 3. `applyPostgresWorldRole(id, worldDbNames)` → ALTER ROLE rotates
18
+ * the password atomically. The old password is gone.
19
+ * 4. Write new password to `~/.olam/worlds/<id>/credentials.json`
20
+ * (chmod 600).
21
+ * 5. `docker restart olam-<id>-devbox` so the container picks up the
22
+ * new password from env on next process start.
23
+ * 6. Audit-log line to `~/.olam/usage.log` (SEC-002): timestamp +
24
+ * world-id + "rekey" — NEVER the password.
25
+ *
26
+ * Exit codes:
27
+ * 0 success
28
+ * 1 unexpected error
29
+ * 2 world not found
30
+ * 3 precondition failed (non-hybrid, no DBs, etc.)
31
+ */
32
+ import { spawnSync as defaultSpawnSync } from 'node:child_process';
33
+ import * as fs from 'node:fs';
34
+ import * as os from 'node:os';
35
+ import * as path from 'node:path';
36
+ import { applyPostgresWorldRole as defaultApplyPostgresWorldRole, } from '@olam/core/src/world/manager.js';
37
+ import { loadContext } from '../context.js';
38
+ import { printError, printSuccess, printInfo, printHeader } from '../output.js';
39
+ /** Container name convention — mirrors enter.ts:286, refresh.ts:90, ps.ts:157. */
40
+ function devboxContainerName(worldId) {
41
+ return `olam-${worldId}-devbox`;
42
+ }
43
+ /** Resolve `~/.olam` honoring OLAM_HOME (mirrors host-cp.ts:55). */
44
+ function olamHomeDir() {
45
+ return process.env['OLAM_HOME'] ?? path.join(os.homedir(), '.olam');
46
+ }
47
+ function defaultRestartContainer(name, spawn = defaultSpawnSync) {
48
+ // 30s graceful-stop window matches refresh.ts:41 (RESTART_TIMEOUT_S).
49
+ const r = spawn('docker', ['restart', '--time', '30', name], {
50
+ encoding: 'utf-8',
51
+ stdio: ['ignore', 'pipe', 'pipe'],
52
+ });
53
+ return {
54
+ ok: r.status === 0 && r.error === undefined,
55
+ stderr: (r.stderr || '').trim() || (r.stdout || '').trim(),
56
+ };
57
+ }
58
+ function defaultAppendAuditLog(homeDir, line) {
59
+ fs.mkdirSync(homeDir, { recursive: true });
60
+ fs.appendFileSync(path.join(homeDir, 'usage.log'), line.endsWith('\n') ? line : line + '\n', {
61
+ encoding: 'utf-8',
62
+ });
63
+ }
64
+ function buildDefaultDeps() {
65
+ return {
66
+ // Replaced inside `registerRekey` once the context is loaded; the
67
+ // default here keeps the type contract self-consistent.
68
+ getWorld: () => undefined,
69
+ applyPostgresWorldRole: (id, dbs) => defaultApplyPostgresWorldRole(id, dbs),
70
+ restartContainer: (name) => defaultRestartContainer(name),
71
+ olamHomeDir,
72
+ now: () => new Date(),
73
+ stdout: { write: (s) => process.stdout.write(s) },
74
+ appendAuditLog: (line) => defaultAppendAuditLog(olamHomeDir(), line),
75
+ };
76
+ }
77
+ /** Domain-specific error carrying the documented exit code. */
78
+ export class RekeyError extends Error {
79
+ exitCode;
80
+ constructor(message, exitCode) {
81
+ super(message);
82
+ this.name = 'RekeyError';
83
+ this.exitCode = exitCode;
84
+ }
85
+ }
86
+ /**
87
+ * Core rekey logic. Returns the rotation result on success, throws
88
+ * {@link RekeyError} with the documented exit code on failure.
89
+ *
90
+ * The password is held in this function's local binding and the
91
+ * returned object only; it is written to disk with mode 0o600 and
92
+ * NEVER logged or written to the audit trail (SEC-002).
93
+ */
94
+ export async function doRekey(worldId, deps) {
95
+ const world = deps.getWorld(worldId);
96
+ if (!world) {
97
+ throw new RekeyError(`world not found: ${worldId}`, 2);
98
+ }
99
+ if (world.worldRoleName === undefined) {
100
+ throw new RekeyError(`world ${worldId} is not hybrid-mode (no per-world role). ` +
101
+ '`olam rekey` only applies to hybrid-mode worlds; use the bridge ' +
102
+ "postgres's `development` user.", 3);
103
+ }
104
+ if (world.worldDbNames === undefined || world.worldDbNames.length === 0) {
105
+ throw new RekeyError('world has no per-world DBs to rotate role on', 3);
106
+ }
107
+ // 1. Rotate. ALTER ROLE inside applyPostgresWorldRole is idempotent —
108
+ // the same function handles both initial create and rotation.
109
+ const { worldRoleName, password } = deps.applyPostgresWorldRole(worldId, world.worldDbNames);
110
+ // 2. Persist credentials BEFORE restart so the container always has a
111
+ // valid file to consult if env-injection ever moves to file-mount.
112
+ const rotatedAt = deps.now().toISOString();
113
+ const homeDir = deps.olamHomeDir();
114
+ const worldDir = path.join(homeDir, 'worlds', worldId);
115
+ fs.mkdirSync(worldDir, { recursive: true });
116
+ const credentialsPath = path.join(worldDir, 'credentials.json');
117
+ const payload = {
118
+ worldRoleName,
119
+ password,
120
+ rotatedAt,
121
+ };
122
+ // chmod 600 — owner read/write only. Order matters: create empty file
123
+ // first, fchmod, THEN write. `writeFileSync({ mode })` only applies on
124
+ // initial create, so re-rotations on an existing file keep the old
125
+ // mode if we skip the explicit chmod.
126
+ fs.writeFileSync(credentialsPath, JSON.stringify(payload, null, 2) + '\n', {
127
+ encoding: 'utf-8',
128
+ mode: 0o600,
129
+ });
130
+ fs.chmodSync(credentialsPath, 0o600);
131
+ // 3. Restart the world devbox container so the (env-injected)
132
+ // password reload happens. Failure here is reported but the
133
+ // rotation itself is already durable in postgres.
134
+ const restart = deps.restartContainer(devboxContainerName(worldId));
135
+ // Container restart is best-effort; rotation already landed in pg.
136
+ // 4. Audit-log line — NO password. SEC-002 closure.
137
+ deps.appendAuditLog(`${rotatedAt} ${worldId} rekey`);
138
+ if (!restart.ok) {
139
+ // Surface the restart failure in stderr; caller can re-run
140
+ // `docker restart olam-<id>-devbox` manually. Exit code stays 0
141
+ // because the credential rotation succeeded.
142
+ process.stderr.write(`warn: docker restart ${devboxContainerName(worldId)} failed (` +
143
+ `${restart.stderr || 'unknown'}). Run it manually to pick up the new ` +
144
+ 'password.\n');
145
+ }
146
+ return {
147
+ worldId,
148
+ worldRoleName,
149
+ password,
150
+ credentialsPath,
151
+ rotatedAt,
152
+ containerRestarted: restart.ok,
153
+ };
154
+ }
155
+ function emitJson(stdout, result) {
156
+ stdout.write(JSON.stringify(result, null, 2) + '\n');
157
+ }
158
+ function emitHuman(result, opts) {
159
+ printHeader(`Rotated credentials for ${result.worldId}`);
160
+ printInfo('role', result.worldRoleName);
161
+ printInfo('credentials', result.credentialsPath);
162
+ printInfo('rotated', result.rotatedAt);
163
+ printInfo('container', result.containerRestarted ? 'restarted' : 'restart failed (see stderr)');
164
+ if (opts.print) {
165
+ // Plain stdout (no `printInfo` decorator) so the password can be
166
+ // piped: `olam rekey <id> --print | tail -n1`.
167
+ process.stdout.write(result.password + '\n');
168
+ }
169
+ printSuccess(`Run \`olam enter ${result.worldId}\` to verify the new password works`);
170
+ }
171
+ export function registerRekey(program) {
172
+ program
173
+ .command('rekey')
174
+ .description('Rotate the per-world postgres password for a hybrid-mode world')
175
+ .argument('<world-id>', 'World ID (e.g. iron-bay-3122)')
176
+ .option('--print', 'Also print the new password to stdout (default: write to file only)')
177
+ .option('--json', 'Emit the rotation result as JSON')
178
+ .action(async (worldId, opts) => {
179
+ const { ctx, error } = await loadContext();
180
+ if (!ctx) {
181
+ printError(error?.message ?? 'Olam is not configured. Run `olam init` first.');
182
+ process.exitCode = 1;
183
+ return;
184
+ }
185
+ const deps = {
186
+ ...buildDefaultDeps(),
187
+ getWorld: (id) => ctx.worldManager.getWorld(id),
188
+ };
189
+ try {
190
+ const result = await doRekey(worldId, deps);
191
+ if (opts.json) {
192
+ emitJson(deps.stdout, result);
193
+ }
194
+ else {
195
+ emitHuman(result, opts);
196
+ }
197
+ }
198
+ catch (err) {
199
+ if (err instanceof RekeyError) {
200
+ printError(err.message);
201
+ process.exitCode = err.exitCode;
202
+ return;
203
+ }
204
+ printError(err instanceof Error ? err.message : String(err));
205
+ process.exitCode = 1;
206
+ }
207
+ });
208
+ }
209
+ //# sourceMappingURL=rekey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rekey.js","sourceRoot":"","sources":["../../src/commands/rekey.ts"],"names":[],"mappings":"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"}
@@ -2,9 +2,9 @@
2
2
  * `olam services` — umbrella verb for managing Olam service containers.
3
3
  *
4
4
  * Subcommands:
5
- * olam services up — start olam-auth + olam-mcp-auth (idempotent)
6
- * olam services down — stop both containers
7
- * olam services status — show state of both containers
5
+ * olam services up — start olam-auth + olam-mcp-auth + olam-kg-service (idempotent)
6
+ * olam services down — stop all service containers
7
+ * olam services status — show state of all service containers
8
8
  *
9
9
  * `olam auth up/down/status` delegates here with a deprecation warning.
10
10
  */
@@ -27,11 +27,11 @@ export declare class McpAuthContainerController {
27
27
  export declare function servicesUp(): Promise<{
28
28
  exitCode: number;
29
29
  }>;
30
- /** Stop both auth containers. */
30
+ /** Stop all service containers. */
31
31
  export declare function servicesDown(): {
32
32
  exitCode: number;
33
33
  };
34
- /** Show container state for both services. */
34
+ /** Show container state for all services. */
35
35
  export declare function servicesStatus(): void;
36
36
  export declare function registerServices(program: Command): void;
37
37
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/commands/services.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2BzC,KAAK,cAAc,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAExD,UAAU,eAAe;IACvB,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,qBAAa,0BAA0B;IACrC,OAAO,CAAC,QAAQ,CAA8B;IAE9C,MAAM,IAAI,eAAe;IAiBzB,OAAO,CAAC,WAAW;IAInB,KAAK,IAAI,IAAI;IAgCb,IAAI,IAAI,IAAI;IAMZ,MAAM,IAAI,IAAI;IAIR,YAAY,CAAC,SAAS,SAA6B,GAAG,OAAO,CAAC,OAAO,CAAC;CAa7E;AAgCD,wBAAsB,UAAU,IAAI,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgDhE;AAED,iCAAiC;AACjC,wBAAgB,YAAY,IAAI;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAsBnD;AAED,8CAA8C;AAC9C,wBAAgB,cAAc,IAAI,IAAI,CAuBrC;AAID,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA2BvD"}
1
+ {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/commands/services.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgCzC,KAAK,cAAc,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAExD,UAAU,eAAe;IACvB,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,qBAAa,0BAA0B;IACrC,OAAO,CAAC,QAAQ,CAA8B;IAE9C,MAAM,IAAI,eAAe;IAiBzB,OAAO,CAAC,WAAW;IAInB,KAAK,IAAI,IAAI;IAgCb,IAAI,IAAI,IAAI;IAMZ,MAAM,IAAI,IAAI;IAIR,YAAY,CAAC,SAAS,SAA6B,GAAG,OAAO,CAAC,OAAO,CAAC;CAa7E;AAgCD,wBAAsB,UAAU,IAAI,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgGhE;AAED,mCAAmC;AACnC,wBAAgB,YAAY,IAAI;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CA+BnD;AAED,6CAA6C;AAC7C,wBAAgB,cAAc,IAAI,IAAI,CAiCrC;AAID,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA2BvD"}