@pleri/olam-cli 0.1.175 → 0.1.180

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 (41) hide show
  1. package/README.md +19 -0
  2. package/bin/olam.cjs +22 -0
  3. package/dist/commands/flywheel/index.d.ts.map +1 -1
  4. package/dist/commands/flywheel/index.js +4 -0
  5. package/dist/commands/flywheel/index.js.map +1 -1
  6. package/dist/commands/flywheel/install-sessionstart-hook.d.ts +64 -0
  7. package/dist/commands/flywheel/install-sessionstart-hook.d.ts.map +1 -0
  8. package/dist/commands/flywheel/install-sessionstart-hook.js +197 -0
  9. package/dist/commands/flywheel/install-sessionstart-hook.js.map +1 -0
  10. package/dist/commands/flywheel/session-start.d.ts +26 -0
  11. package/dist/commands/flywheel/session-start.d.ts.map +1 -0
  12. package/dist/commands/flywheel/session-start.js +119 -0
  13. package/dist/commands/flywheel/session-start.js.map +1 -0
  14. package/dist/commands/host-cp.d.ts +0 -3
  15. package/dist/commands/host-cp.d.ts.map +1 -1
  16. package/dist/commands/host-cp.js +27 -2
  17. package/dist/commands/host-cp.js.map +1 -1
  18. package/dist/commands/yolo.d.ts +99 -0
  19. package/dist/commands/yolo.d.ts.map +1 -0
  20. package/dist/commands/yolo.js +377 -0
  21. package/dist/commands/yolo.js.map +1 -0
  22. package/dist/image-digests.json +8 -8
  23. package/dist/index.js +808 -207
  24. package/dist/index.js.map +1 -1
  25. package/dist/lib/auth-remote.d.ts +0 -17
  26. package/dist/lib/auth-remote.d.ts.map +1 -1
  27. package/dist/lib/auth-remote.js +6 -16
  28. package/dist/lib/auth-remote.js.map +1 -1
  29. package/dist/mcp-server.js +26 -0
  30. package/hermes-bundle/version.json +1 -1
  31. package/host-cp/k8s/manifests/50-deployment.yaml +1 -1
  32. package/host-cp/k8s/manifests/auth-service/50-deployment.yaml +1 -1
  33. package/host-cp/k8s/manifests/kg-service/50-deployment.yaml +1 -1
  34. package/host-cp/k8s/manifests/mcp-auth-service/50-deployment.yaml +1 -1
  35. package/host-cp/k8s/manifests/memory-service/50-deployment.yaml +1 -1
  36. package/host-cp/src/bootstrap-selective.mjs +56 -0
  37. package/host-cp/src/plan-chat-service.mjs +51 -0
  38. package/host-cp/src/redirect.mjs +152 -0
  39. package/host-cp/src/resolver.mjs +121 -0
  40. package/host-cp/src/server.mjs +57 -16
  41. package/package.json +1 -1
package/README.md CHANGED
@@ -121,6 +121,25 @@ olam --help
121
121
  olam <command> --help
122
122
  ```
123
123
 
124
+ ## Agentic coding — yolo dispatch
125
+
126
+ `olam yolo` dispatches a parallel Claude Code session (`--dangerously-skip-permissions`)
127
+ in a new tmux window backed by an isolated git worktree. Each session gets its
128
+ own branch so it can't clobber the operator's main shell.
129
+
130
+ ```sh
131
+ # Spawn a yolo on a bounded task
132
+ olam yolo my-task --branch feat/my-task --prompt-file /tmp/my-task.txt
133
+
134
+ # List active yolo windows
135
+ olam yolo --list
136
+
137
+ # Clean up after merge
138
+ olam yolo --cleanup my-task
139
+ ```
140
+
141
+ Full reference: `olam yolo --help` and [`docs/runbooks/olam-yolo-cli.md`](../../docs/runbooks/olam-yolo-cli.md).
142
+
124
143
  ## Multi-account Claude Code (`--claude-home`)
125
144
 
126
145
  Inspired by [t3code](https://github.com/pingdotgg/t3code) — one operator,
package/bin/olam.cjs CHANGED
@@ -16,6 +16,28 @@ if (!result.ok) {
16
16
  process.exit(64);
17
17
  }
18
18
 
19
+ // Fast-path `--version` / `-V` BEFORE loading the ESM bundle (issue #988).
20
+ // Fresh-user installs run `olam --version` as the install-script sanity
21
+ // check; any hang in the bundle's import graph (better-sqlite3 native probe,
22
+ // agentmemory MCP context-loader, Dockerode lazy-binding) would block this
23
+ // path indefinitely. Reading package.json directly from the CJS shim
24
+ // guarantees `--version` returns in <100ms regardless of bundle state.
25
+ const argv = process.argv.slice(2);
26
+ if (argv.length === 1 && (argv[0] === '--version' || argv[0] === '-V')) {
27
+ try {
28
+ const fs = require('node:fs');
29
+ const path = require('node:path');
30
+ const pkgPath = path.join(__dirname, '..', 'package.json');
31
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
32
+ process.stdout.write(`${pkg.version || '0.0.0-unknown'}\n`);
33
+ process.exit(0);
34
+ } catch (err) {
35
+ // Fall through to the bundle if the fast-path read fails for any reason
36
+ // (corrupt package.json, missing file). The bundle's own readCliVersion
37
+ // has the same fallback chain and will print '0.0.0-unknown' if needed.
38
+ }
39
+ }
40
+
19
41
  const { join } = require('node:path');
20
42
  const { pathToFileURL } = require('node:url');
21
43
  const bundlePath = join(__dirname, '..', 'dist', 'index.js');
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/flywheel/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYzC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAiBvD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/flywheel/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAczC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmBvD"}
@@ -32,6 +32,8 @@ import { registerFlywheelDiversityCheck } from './diversity-check.js';
32
32
  import { registerFlywheelPing } from './ping.js';
33
33
  import { registerFlywheelInstallShims } from './install-shims.js';
34
34
  import { registerFlywheelMigrateOverlays } from './migrate-overlays.js';
35
+ import { registerFlywheelSessionStart } from './session-start.js';
36
+ import { registerFlywheelInstallSessionStartHook } from './install-sessionstart-hook.js';
35
37
  export function registerFlywheel(program) {
36
38
  const flywheel = program
37
39
  .command('flywheel')
@@ -46,5 +48,7 @@ export function registerFlywheel(program) {
46
48
  registerFlywheelPing(flywheel);
47
49
  registerFlywheelInstallShims(flywheel);
48
50
  registerFlywheelMigrateOverlays(flywheel);
51
+ registerFlywheelSessionStart(flywheel);
52
+ registerFlywheelInstallSessionStartHook(flywheel);
49
53
  }
50
54
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/flywheel/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EAAE,8BAA8B,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,qCAAqC,EAAE,MAAM,8BAA8B,CAAC;AACrF,OAAO,EAAE,oCAAoC,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,8BAA8B,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAE,+BAA+B,EAAE,MAAM,uBAAuB,CAAC;AAExE,MAAM,UAAU,gBAAgB,CAAC,OAAgB;IAC/C,MAAM,QAAQ,GAAG,OAAO;SACrB,OAAO,CAAC,UAAU,CAAC;SACnB,WAAW,CACV,qNAAqN,CACtN,CAAC;IAEJ,8BAA8B,CAAC,QAAQ,CAAC,CAAC;IACzC,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IAClC,0BAA0B,CAAC,QAAQ,CAAC,CAAC;IACrC,0BAA0B,CAAC,QAAQ,CAAC,CAAC;IACrC,qCAAqC,CAAC,QAAQ,CAAC,CAAC;IAChD,oCAAoC,CAAC,QAAQ,CAAC,CAAC;IAC/C,8BAA8B,CAAC,QAAQ,CAAC,CAAC;IACzC,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAC/B,4BAA4B,CAAC,QAAQ,CAAC,CAAC;IACvC,+BAA+B,CAAC,QAAQ,CAAC,CAAC;AAC5C,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/flywheel/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EAAE,8BAA8B,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,qCAAqC,EAAE,MAAM,8BAA8B,CAAC;AACrF,OAAO,EAAE,oCAAoC,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,8BAA8B,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAE,+BAA+B,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAE,uCAAuC,EAAE,MAAM,gCAAgC,CAAC;AAEzF,MAAM,UAAU,gBAAgB,CAAC,OAAgB;IAC/C,MAAM,QAAQ,GAAG,OAAO;SACrB,OAAO,CAAC,UAAU,CAAC;SACnB,WAAW,CACV,qNAAqN,CACtN,CAAC;IAEJ,8BAA8B,CAAC,QAAQ,CAAC,CAAC;IACzC,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IAClC,0BAA0B,CAAC,QAAQ,CAAC,CAAC;IACrC,0BAA0B,CAAC,QAAQ,CAAC,CAAC;IACrC,qCAAqC,CAAC,QAAQ,CAAC,CAAC;IAChD,oCAAoC,CAAC,QAAQ,CAAC,CAAC;IAC/C,8BAA8B,CAAC,QAAQ,CAAC,CAAC;IACzC,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAC/B,4BAA4B,CAAC,QAAQ,CAAC,CAAC;IACvC,+BAA+B,CAAC,QAAQ,CAAC,CAAC;IAC1C,4BAA4B,CAAC,QAAQ,CAAC,CAAC;IACvC,uCAAuC,CAAC,QAAQ,CAAC,CAAC;AACpD,CAAC"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * `olam flywheel install-sessionstart-hook [--scope project|user] [--uninstall]`
3
+ *
4
+ * Wires `olam flywheel session-start` into `<scope>/.claude/settings.json`
5
+ * hooks.SessionStart so Claude Code injects operator-state context (active
6
+ * workspace + active world + most-recent wake-brief) before the first user
7
+ * prompt. The 4th defense layer in Olam's hook chain (FF / PreToolUse /
8
+ * PostToolUse / Stop).
9
+ *
10
+ * Coexists with the existing skills-sync SessionStart hook
11
+ * (sentinel `olam-skills-sync-hook-v1`). Both entries sit side-by-side in
12
+ * the SessionStart array; Claude Code runs each matcher in order and merges
13
+ * their `additionalContext` outputs into the first turn's system prompt.
14
+ *
15
+ * Idempotent: re-running over an existing install is a no-op (sentinel match
16
+ * via `mergeHomeSettingsJson`).
17
+ *
18
+ * Pairs with: `docs/runbooks/install-sessionstart-hook.md`,
19
+ * `docs/decisions/051-sessionstart-hook-4th-defense.md`.
20
+ */
21
+ import type { Command } from 'commander';
22
+ export declare const SESSIONSTART_HOOK_STAGE = "SessionStart";
23
+ export declare const SESSIONSTART_HOOK_TIMEOUT_MS = 5000;
24
+ interface SessionStartHookMatcher {
25
+ readonly matcher: string;
26
+ readonly hooks: ReadonlyArray<{
27
+ readonly type: 'command';
28
+ readonly command: string;
29
+ readonly timeout: number;
30
+ }>;
31
+ }
32
+ /**
33
+ * Build the matcher-entry object that lands under hooks.SessionStart in
34
+ * .claude/settings.json. Embeds the sentinel as a leading no-op shell
35
+ * assignment so `command.includes(sentinel)` works for idempotent install +
36
+ * surgical uninstall, then guards against uninstalled-olam to keep the hook
37
+ * silent when the CLI is missing (audited by `audit:hook-guards`).
38
+ */
39
+ export declare function buildSessionStartHookEntry(): SessionStartHookMatcher;
40
+ export interface InstallResult {
41
+ readonly status: 'installed' | 'already-present' | 'no-op';
42
+ readonly filePath: string;
43
+ readonly backupPath: string | null;
44
+ }
45
+ /**
46
+ * Install (idempotent) — programmatic API for both the CLI action and tests.
47
+ * Creates parent dir if needed; backs up an existing settings.json before
48
+ * writing (auto-deletes the backup when the install is a no-op).
49
+ */
50
+ export declare function installSessionStartHook(filePath: string): InstallResult;
51
+ export interface UninstallResult {
52
+ readonly status: 'removed' | 'not-found' | 'no-settings';
53
+ readonly filePath: string;
54
+ }
55
+ /**
56
+ * Uninstall (surgical) — walks hooks.SessionStart, drops inner entries whose
57
+ * command contains the sentinel, drops the outer matcher when its hooks
58
+ * array becomes empty. Other SessionStart entries (e.g. the skills-sync
59
+ * hook) are preserved verbatim.
60
+ */
61
+ export declare function uninstallSessionStartHook(filePath: string): UninstallResult;
62
+ export declare function registerFlywheelInstallSessionStartHook(parent: Command): void;
63
+ export {};
64
+ //# sourceMappingURL=install-sessionstart-hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-sessionstart-hook.d.ts","sourceRoot":"","sources":["../../../src/commands/flywheel/install-sessionstart-hook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,eAAO,MAAM,uBAAuB,iBAAiB,CAAC;AACtD,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAIjD,UAAU,uBAAuB;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;QAC5B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;QACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;KAC1B,CAAC,CAAC;CACJ;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,IAAI,uBAAuB,CAWpE;AAsBD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,iBAAiB,GAAG,OAAO,CAAC;IAC3D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAsBvE;AAOD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,aAAa,CAAC;IACzD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,CAiD3E;AAED,wBAAgB,uCAAuC,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAsD7E"}
@@ -0,0 +1,197 @@
1
+ /**
2
+ * `olam flywheel install-sessionstart-hook [--scope project|user] [--uninstall]`
3
+ *
4
+ * Wires `olam flywheel session-start` into `<scope>/.claude/settings.json`
5
+ * hooks.SessionStart so Claude Code injects operator-state context (active
6
+ * workspace + active world + most-recent wake-brief) before the first user
7
+ * prompt. The 4th defense layer in Olam's hook chain (FF / PreToolUse /
8
+ * PostToolUse / Stop).
9
+ *
10
+ * Coexists with the existing skills-sync SessionStart hook
11
+ * (sentinel `olam-skills-sync-hook-v1`). Both entries sit side-by-side in
12
+ * the SessionStart array; Claude Code runs each matcher in order and merges
13
+ * their `additionalContext` outputs into the first turn's system prompt.
14
+ *
15
+ * Idempotent: re-running over an existing install is a no-op (sentinel match
16
+ * via `mergeHomeSettingsJson`).
17
+ *
18
+ * Pairs with: `docs/runbooks/install-sessionstart-hook.md`,
19
+ * `docs/decisions/051-sessionstart-hook-4th-defense.md`.
20
+ */
21
+ import { existsSync, copyFileSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
22
+ import { homedir } from 'node:os';
23
+ import { dirname, join } from 'node:path';
24
+ import { mergeHomeSettingsJson } from '@olam/core/src/world/merge-settings.js';
25
+ import { printError, printInfo, printSuccess, printWarning } from '../../output.js';
26
+ import { SESSIONSTART_HOOK_SENTINEL } from './session-start.js';
27
+ export const SESSIONSTART_HOOK_STAGE = 'SessionStart';
28
+ export const SESSIONSTART_HOOK_TIMEOUT_MS = 5000;
29
+ const NOOP_GUARD = 'command -v olam >/dev/null 2>&1 || exit 0;';
30
+ /**
31
+ * Build the matcher-entry object that lands under hooks.SessionStart in
32
+ * .claude/settings.json. Embeds the sentinel as a leading no-op shell
33
+ * assignment so `command.includes(sentinel)` works for idempotent install +
34
+ * surgical uninstall, then guards against uninstalled-olam to keep the hook
35
+ * silent when the CLI is missing (audited by `audit:hook-guards`).
36
+ */
37
+ export function buildSessionStartHookEntry() {
38
+ return {
39
+ matcher: '',
40
+ hooks: [
41
+ {
42
+ type: 'command',
43
+ command: `OLAM_SESSIONSTART_SENTINEL=${SESSIONSTART_HOOK_SENTINEL}; ${NOOP_GUARD} olam flywheel session-start`,
44
+ timeout: SESSIONSTART_HOOK_TIMEOUT_MS,
45
+ },
46
+ ],
47
+ };
48
+ }
49
+ function settingsPathFor(scope, cwd) {
50
+ if (scope === 'user')
51
+ return join(homedir(), '.claude', 'settings.json');
52
+ return join(cwd ?? process.cwd(), '.claude', 'settings.json');
53
+ }
54
+ function backup(filePath) {
55
+ if (!existsSync(filePath))
56
+ return null;
57
+ const ts = new Date().toISOString().replace(/[:.]/g, '-');
58
+ const backupPath = `${filePath}.olam-bak.${ts}`;
59
+ copyFileSync(filePath, backupPath);
60
+ return backupPath;
61
+ }
62
+ /**
63
+ * Install (idempotent) — programmatic API for both the CLI action and tests.
64
+ * Creates parent dir if needed; backs up an existing settings.json before
65
+ * writing (auto-deletes the backup when the install is a no-op).
66
+ */
67
+ export function installSessionStartHook(filePath) {
68
+ mkdirSync(dirname(filePath), { recursive: true });
69
+ const backupPath = backup(filePath);
70
+ const result = mergeHomeSettingsJson(filePath, {
71
+ ensureHook: {
72
+ stage: SESSIONSTART_HOOK_STAGE,
73
+ sentinel: SESSIONSTART_HOOK_SENTINEL,
74
+ entry: buildSessionStartHookEntry(),
75
+ },
76
+ });
77
+ if (result.status === 'already-present' && backupPath) {
78
+ try {
79
+ unlinkSync(backupPath);
80
+ }
81
+ catch {
82
+ // best-effort
83
+ }
84
+ return { status: 'already-present', filePath, backupPath: null };
85
+ }
86
+ return { status: result.status, filePath, backupPath };
87
+ }
88
+ /**
89
+ * Uninstall (surgical) — walks hooks.SessionStart, drops inner entries whose
90
+ * command contains the sentinel, drops the outer matcher when its hooks
91
+ * array becomes empty. Other SessionStart entries (e.g. the skills-sync
92
+ * hook) are preserved verbatim.
93
+ */
94
+ export function uninstallSessionStartHook(filePath) {
95
+ if (!existsSync(filePath))
96
+ return { status: 'no-settings', filePath };
97
+ const raw = readFileSync(filePath, 'utf-8');
98
+ const settings = raw.trim() ? JSON.parse(raw) : {};
99
+ const matchers = settings.hooks?.SessionStart;
100
+ if (!Array.isArray(matchers) || matchers.length === 0) {
101
+ return { status: 'not-found', filePath };
102
+ }
103
+ let changed = false;
104
+ const kept = [];
105
+ for (const matcher of matchers) {
106
+ const inner = matcher.hooks ?? [];
107
+ const keptInner = inner.filter((h) => {
108
+ if (typeof h.command === 'string' && h.command.includes(SESSIONSTART_HOOK_SENTINEL)) {
109
+ changed = true;
110
+ return false;
111
+ }
112
+ return true;
113
+ });
114
+ if (keptInner.length === 0 && inner.length > 0) {
115
+ changed = true;
116
+ continue;
117
+ }
118
+ if (keptInner.length === inner.length) {
119
+ kept.push(matcher);
120
+ }
121
+ else {
122
+ kept.push({ ...matcher, hooks: keptInner });
123
+ }
124
+ }
125
+ if (!changed)
126
+ return { status: 'not-found', filePath };
127
+ const next = {
128
+ ...settings,
129
+ hooks: { ...settings.hooks, SessionStart: kept },
130
+ };
131
+ if (kept.length === 0) {
132
+ const otherStages = Object.keys(next.hooks ?? {}).filter((k) => k !== 'SessionStart');
133
+ if (otherStages.length === 0) {
134
+ delete next.hooks;
135
+ }
136
+ else {
137
+ delete next.hooks.SessionStart;
138
+ }
139
+ }
140
+ writeFileSync(filePath, JSON.stringify(next, null, 2) + '\n');
141
+ return { status: 'removed', filePath };
142
+ }
143
+ export function registerFlywheelInstallSessionStartHook(parent) {
144
+ parent
145
+ .command('install-sessionstart-hook')
146
+ .description('Install (or --uninstall) the SessionStart context hook into .claude/settings.json. Idempotent. 4th defense layer — preloads operator state before the first prompt.')
147
+ .option('--scope <scope>', 'project (default; <cwd>/.claude/settings.json) or user (~/.claude/settings.json)', 'project')
148
+ .option('--uninstall', 'Remove the hook instead of installing it')
149
+ .action((opts) => {
150
+ const scope = opts.scope === 'user' ? 'user' : 'project';
151
+ const filePath = settingsPathFor(scope);
152
+ if (opts.uninstall) {
153
+ try {
154
+ const r = uninstallSessionStartHook(filePath);
155
+ switch (r.status) {
156
+ case 'removed':
157
+ printSuccess(`SessionStart context hook removed from ${filePath}`);
158
+ return;
159
+ case 'not-found':
160
+ printInfo('sessionstart hook', `not found in ${filePath} — already uninstalled`);
161
+ return;
162
+ case 'no-settings':
163
+ printInfo('sessionstart hook', `no settings.json at ${filePath} — nothing to remove`);
164
+ return;
165
+ }
166
+ }
167
+ catch (err) {
168
+ printError(`uninstall failed: ${err instanceof Error ? err.message : String(err)}`);
169
+ process.exitCode = 1;
170
+ }
171
+ return;
172
+ }
173
+ try {
174
+ const r = installSessionStartHook(filePath);
175
+ switch (r.status) {
176
+ case 'installed':
177
+ printSuccess(`SessionStart context hook installed (${scope} scope)`);
178
+ printInfo('settings', r.filePath);
179
+ if (r.backupPath)
180
+ printInfo('backup', r.backupPath);
181
+ printInfo('next', 'open a new Claude Code session — Olam state will preload via additionalContext');
182
+ return;
183
+ case 'already-present':
184
+ printInfo('sessionstart hook', `already installed at ${r.filePath}`);
185
+ return;
186
+ case 'no-op':
187
+ printWarning(`no change made to ${r.filePath}`);
188
+ return;
189
+ }
190
+ }
191
+ catch (err) {
192
+ printError(`install failed: ${err instanceof Error ? err.message : String(err)}`);
193
+ process.exitCode = 1;
194
+ }
195
+ });
196
+ }
197
+ //# sourceMappingURL=install-sessionstart-hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-sessionstart-hook.js","sourceRoot":"","sources":["../../../src/commands/flywheel/install-sessionstart-hook.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * `olam flywheel session-start` — emit operator-state context for the
3
+ * SessionStart hook (4th defense layer).
4
+ *
5
+ * Wire shape mirrors the standalone `scripts/hooks/session-start.mjs` so
6
+ * both surfaces are valid invocation paths:
7
+ * - settings.json `hooks.SessionStart` calls `olam flywheel session-start`.
8
+ * - Dev / Hermes / smoke-tests can run `node scripts/hooks/session-start.mjs`
9
+ * directly without touching the CLI.
10
+ *
11
+ * Contract (matches MJS verbatim):
12
+ * - stdout: `{}` when no state; else
13
+ * `{ hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: "<text>" } }`
14
+ * - stderr: human-readable warnings only.
15
+ * - exit: ALWAYS 0 (fail-soft — never block session start).
16
+ *
17
+ * Budget: <50 ms. Reads at most 3 small files under ~/.olam/state/. No network.
18
+ *
19
+ * ADR: docs/decisions/051-sessionstart-hook-4th-defense.md
20
+ */
21
+ import type { Command } from 'commander';
22
+ export declare const SESSIONSTART_HOOK_SENTINEL = "olam-sessionstart-context-hook-v1";
23
+ export declare function buildContextBlock(olamHome: string): string | null;
24
+ export declare function emitSessionStartContext(olamHome: string): void;
25
+ export declare function registerFlywheelSessionStart(parent: Command): void;
26
+ //# sourceMappingURL=session-start.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-start.d.ts","sourceRoot":"","sources":["../../../src/commands/flywheel/session-start.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,eAAO,MAAM,0BAA0B,sCAAsC,CAAC;AAkD9E,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAsCjE;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAqB9D;AAED,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAYlE"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * `olam flywheel session-start` — emit operator-state context for the
3
+ * SessionStart hook (4th defense layer).
4
+ *
5
+ * Wire shape mirrors the standalone `scripts/hooks/session-start.mjs` so
6
+ * both surfaces are valid invocation paths:
7
+ * - settings.json `hooks.SessionStart` calls `olam flywheel session-start`.
8
+ * - Dev / Hermes / smoke-tests can run `node scripts/hooks/session-start.mjs`
9
+ * directly without touching the CLI.
10
+ *
11
+ * Contract (matches MJS verbatim):
12
+ * - stdout: `{}` when no state; else
13
+ * `{ hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: "<text>" } }`
14
+ * - stderr: human-readable warnings only.
15
+ * - exit: ALWAYS 0 (fail-soft — never block session start).
16
+ *
17
+ * Budget: <50 ms. Reads at most 3 small files under ~/.olam/state/. No network.
18
+ *
19
+ * ADR: docs/decisions/051-sessionstart-hook-4th-defense.md
20
+ */
21
+ import { readFileSync, statSync } from 'node:fs';
22
+ import { homedir } from 'node:os';
23
+ import { join } from 'node:path';
24
+ export const SESSIONSTART_HOOK_SENTINEL = 'olam-sessionstart-context-hook-v1';
25
+ const MAX_WAKE_BRIEF_BYTES = 8 * 1024;
26
+ const MAX_ACTIVE_WORLD_BYTES = 4 * 1024;
27
+ const MAX_CONFIG_BYTES = 8 * 1024;
28
+ function tryReadCapped(path, maxBytes) {
29
+ try {
30
+ const stat = statSync(path);
31
+ if (!stat.isFile() || stat.size === 0)
32
+ return null;
33
+ if (stat.size > maxBytes) {
34
+ process.stderr.write(`[${SESSIONSTART_HOOK_SENTINEL}] skipping ${path}: ${stat.size} bytes > ${maxBytes} cap\n`);
35
+ return null;
36
+ }
37
+ return readFileSync(path, 'utf-8');
38
+ }
39
+ catch (err) {
40
+ const code = err?.code;
41
+ if (code === 'ENOENT')
42
+ return null;
43
+ process.stderr.write(`[${SESSIONSTART_HOOK_SENTINEL}] read failed for ${path}: ${err?.message ?? err}\n`);
44
+ return null;
45
+ }
46
+ }
47
+ function tryParseJson(raw, label) {
48
+ if (raw === null)
49
+ return null;
50
+ try {
51
+ return JSON.parse(raw);
52
+ }
53
+ catch (err) {
54
+ process.stderr.write(`[${SESSIONSTART_HOOK_SENTINEL}] ${label} JSON parse failed: ${err?.message ?? err}\n`);
55
+ return null;
56
+ }
57
+ }
58
+ export function buildContextBlock(olamHome) {
59
+ const config = tryParseJson(tryReadCapped(join(olamHome, 'config.json'), MAX_CONFIG_BYTES), 'config.json');
60
+ const activeWorld = tryParseJson(tryReadCapped(join(olamHome, 'state', 'active-world.json'), MAX_ACTIVE_WORLD_BYTES), 'active-world.json');
61
+ const wakeBrief = tryReadCapped(join(olamHome, 'state', 'wake-brief.md'), MAX_WAKE_BRIEF_BYTES);
62
+ const sections = [];
63
+ if (config && typeof config.activeWorkspace === 'string') {
64
+ sections.push(`Active workspace: ${config.activeWorkspace}`);
65
+ }
66
+ if (activeWorld && typeof activeWorld === 'object') {
67
+ const parts = [];
68
+ if (typeof activeWorld.worldId === 'string')
69
+ parts.push(`worldId=${activeWorld.worldId}`);
70
+ if (typeof activeWorld.branch === 'string')
71
+ parts.push(`branch=${activeWorld.branch}`);
72
+ if (typeof activeWorld.repo === 'string')
73
+ parts.push(`repo=${activeWorld.repo}`);
74
+ if (typeof activeWorld.tier === 'string')
75
+ parts.push(`tier=${activeWorld.tier}`);
76
+ if (typeof activeWorld.enteredAt === 'string')
77
+ parts.push(`enteredAt=${activeWorld.enteredAt}`);
78
+ if (parts.length > 0)
79
+ sections.push(`Active world: ${parts.join(', ')}`);
80
+ }
81
+ if (wakeBrief && wakeBrief.trim().length > 0) {
82
+ sections.push('Most recent wake brief:\n\n' + wakeBrief.trimEnd());
83
+ }
84
+ if (sections.length === 0)
85
+ return null;
86
+ const body = sections.join('\n\n');
87
+ return `Olam SessionStart context (${Buffer.byteLength(body, 'utf-8')} bytes):\n\n${body}`;
88
+ }
89
+ export function emitSessionStartContext(olamHome) {
90
+ try {
91
+ const context = buildContextBlock(olamHome);
92
+ if (context === null) {
93
+ process.stdout.write('{}\n');
94
+ return;
95
+ }
96
+ process.stdout.write(JSON.stringify({
97
+ hookSpecificOutput: {
98
+ hookEventName: 'SessionStart',
99
+ additionalContext: context,
100
+ },
101
+ }) + '\n');
102
+ }
103
+ catch (err) {
104
+ process.stderr.write(`[${SESSIONSTART_HOOK_SENTINEL}] unexpected error: ${err?.message ?? err}\n`);
105
+ process.stdout.write('{}\n');
106
+ }
107
+ }
108
+ export function registerFlywheelSessionStart(parent) {
109
+ parent
110
+ .command('session-start')
111
+ .description('Emit operator-state context for the SessionStart hook (4th defense layer). Reads ~/.olam/state/* and writes the additionalContext JSON to stdout. Fail-soft: always exits 0.')
112
+ .action(() => {
113
+ const olamHome = process.env.OLAM_HOME ?? join(homedir(), '.olam');
114
+ emitSessionStartContext(olamHome);
115
+ // Always exit 0 — the hook must NEVER block session start.
116
+ process.exit(0);
117
+ });
118
+ }
119
+ //# sourceMappingURL=session-start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-start.js","sourceRoot":"","sources":["../../../src/commands/flywheel/session-start.ts"],"names":[],"mappings":"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"}
@@ -81,9 +81,6 @@ interface ContainerInfo {
81
81
  readonly state: string;
82
82
  readonly status: string;
83
83
  }
84
- /**
85
- * Find the host-cp container by name. Returns null if absent.
86
- */
87
84
  export declare function findHostCpContainer(): Promise<ContainerInfo | null>;
88
85
  /**
89
86
  * Phase host-cp-reliability: Probe for a running host CP, supporting
@@ -1 +1 @@
1
- {"version":3,"file":"host-cp.d.ts","sourceRoot":"","sources":["../../src/commands/host-cp.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"host-cp.d.ts","sourceRoot":"","sources":["../../src/commands/host-cp.ts"],"names":[],"mappings":"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"}
@@ -180,11 +180,36 @@ export function removePid() {
180
180
  return true;
181
181
  }
182
182
  /**
183
- * Find the host-cp container by name. Returns null if absent.
183
+ * Find the host-cp container by name. Returns null if absent OR if the
184
+ * Docker daemon is unresponsive within `DOCKER_PROBE_TIMEOUT_MS`.
185
+ *
186
+ * The timeout is critical for issue #988: `olam status` calls this via
187
+ * `probeHostCp()`; without a timeout, a wedged Docker daemon (Colima with
188
+ * stale state, dockerd-rootless socket present but unresponsive, etc.)
189
+ * makes the command hang indefinitely. Read-only commands must never hang
190
+ * waiting on backing services.
184
191
  */
192
+ const DOCKER_PROBE_TIMEOUT_MS = 2_000;
185
193
  export async function findHostCpContainer() {
186
194
  const docker = new Dockerode(resolveDockerHostOptions());
187
- const containers = await docker.listContainers({ all: true });
195
+ let timer = null;
196
+ const listing = docker.listContainers({ all: true }).then((cs) => cs);
197
+ const timeout = new Promise((resolve) => {
198
+ timer = setTimeout(() => resolve(null), DOCKER_PROBE_TIMEOUT_MS);
199
+ });
200
+ let containers;
201
+ try {
202
+ containers = (await Promise.race([listing, timeout]));
203
+ }
204
+ catch {
205
+ containers = null;
206
+ }
207
+ finally {
208
+ if (timer !== null)
209
+ clearTimeout(timer);
210
+ }
211
+ if (containers === null)
212
+ return null;
188
213
  for (const c of containers) {
189
214
  const names = (c.Names ?? []).map((n) => n.replace(/^\//, ''));
190
215
  if (names.includes('olam-host-cp')) {