mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-15 10:59:32 +01:00
fix(omp): report approvals without claiming Claude's hook set
Review follow-up. omp declared `hooks: 'always'`, which every consumer reads
as Claude's full hook set, so an omp session picked up behaviour it cannot
back. omp goes back to `hooks: 'none'`; `capabilities.approvalHookFile` is now
a separate, narrower capability with its own predicate,
`approvalHookAvailableForMode()` (local, non-adopted sessions only).
- An explicit `stop` wait on omp is a 400 again; `blocked` still works.
- omp inbox items are alert-only (`answerInTerminal`, no `approvalId` on the
push), and only `permission_prompt` / `elicitation_complete` are accepted for
an approval-only session.
- The module is installed from POST /api/quick-start too (new and existing
cases, not Docker or remote) and on reboot-restore, after the launch
pre-flight on both create paths. Claude's settings.local.json block and the
Docker CLAUDE.md no longer land in omp workspaces.
- The generated module passes Bun's `tls: { rejectUnauthorized: false }` for an
https CODEMAN_API_URL (checked against a `--https` server), clears the alert
only when the last pending toolCallId resolves, sends reports in order,
carries omp's policy `reason` as `message`, and imports HookAPI from
`@oh-my-pi/pi-coding-agent/extensibility/hooks`.
- Every path component and the target file are lstat-checked.
- docs/omp-integration.md, verbs.md and the stock.ts comments updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0bbf483a35
commit
27d6e2e30a
14 files changed
+701
-125
No files matched your search
@@ -1661,9 +1661,11 @@ const DEEPSEEK: CliEntry = {
|
||||
};
|
||||
|
||||
// OMP (`omp`, omp.sh). The plainest entry in the catalog after opencode: no permission
|
||||
// flags at all — omp reads its model routing and hooks from `~/.omp/agent`, so the CLI's
|
||||
// own config governs and there is deliberately nothing bypass-shaped to clamp. Its only
|
||||
// privileged surface is a pair of ENV keys (see privilegedEnvKeys below).
|
||||
// flags at all — omp reads its model routing, approval mode and user hooks from
|
||||
// `~/.omp/agent`, so the CLI's own config governs and there is deliberately nothing
|
||||
// bypass-shaped to clamp. The one thing Codeman adds is a project hook module that
|
||||
// reports approval dialogs (`approvalHookFile` below). Its only privileged surface is a
|
||||
// pair of ENV keys (see privilegedEnvKeys below).
|
||||
const OMP: CliEntry = {
|
||||
id: 'omp' as CliEntry['id'],
|
||||
label: 'OMP',
|
||||
@@ -1745,17 +1747,15 @@ const OMP: CliEntry = {
|
||||
// omp emits REAL approval events (`tool_approval_requested` / `tool_approval_resolved`),
|
||||
// so an omp pane can report a pending dialog first-hand instead of by inference.
|
||||
// Codeman installs the hook module named by `approvalHookFile` into
|
||||
// `<workspace>/.claude/hooks/pre/` when a session is created; it forwards those two
|
||||
// events to /api/hook-event as `permission_prompt` / `elicitation_complete`, the same
|
||||
// names claude's settings block sends, so the tab alert, the desktop notification and
|
||||
// the Approvals Inbox work unchanged.
|
||||
// ⚠️ 'always' rather than 'supervised': the report comes from a hook Codeman owns and
|
||||
// installs (like claude's), not from a supervised-CLI status bridge.
|
||||
// ⚠️ Only approvals are reported. `stop`/`idle_prompt` still come from `workDetect`
|
||||
// below, which stays the source of truth for whether an omp pane is working or idle.
|
||||
hooks: 'always',
|
||||
// The hook module Codeman writes for this CLI. Declared as data so the session-create
|
||||
// path asks "does this CLI declare a hook file?" instead of branching on an id.
|
||||
// `<workspace>/.claude/hooks/pre/` when a session is created (both create paths); it
|
||||
// forwards those two events to /api/hook-event as `permission_prompt` /
|
||||
// `elicitation_complete`, so the tab alert, the desktop notification and an ALERT-ONLY
|
||||
// Approvals Inbox item (answer in the terminal) work.
|
||||
// ⚠️ `hooks` stays 'none' (inherited from agentDefaults): that value means Claude's full
|
||||
// hook set (`stop`, `idle_prompt`, answerable dialogs, `.claude/settings.local.json`),
|
||||
// and omp has none of it. `approvalHookFile` is the separate, narrower capability;
|
||||
// `approvalHookAvailableForMode()` is its predicate. Idle stays screen-read via
|
||||
// `workDetect` below.
|
||||
approvalHookFile: 'codeman-approval.ts',
|
||||
// Fullscreen alt-screen TUI, same shape as antigravity/grok: only the
|
||||
// tmux-attach-time smcup strip, not Ink's full erase-scrollback+DECSET strip.
|
||||
@@ -1778,7 +1778,8 @@ const OMP: CliEntry = {
|
||||
promptGlyph: '╰─',
|
||||
workingLine: '[⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏] [0-9hms ]+> |⎋ Working',
|
||||
},
|
||||
// No permission prompts and no bypass flag, so nothing config-shaped to clamp — the
|
||||
// No permission FLAGS (omp's approval mode lives in its own config, `tools.approvalMode`)
|
||||
// and no bypass flag, so nothing config-shaped to clamp — the
|
||||
// whole privileged surface here is env-shaped.
|
||||
privilegedParams: [],
|
||||
// Where omp resolves its auth from. No known concrete exfiltration path today (omp
|
||||
|
||||
@@ -508,10 +508,11 @@ export interface CliCapabilities {
|
||||
* Whether `stop`/`blocked` wait signals can ever fire for this CLI.
|
||||
*
|
||||
* ⚠️ A TRI-STATE, not a boolean, because for one CLI this is a per-SESSION question:
|
||||
* 'none' — no hook signals, ever (every external CLI, and `shell`).
|
||||
* 'always' — the CLI's signals are installed by Codeman and are unconditional:
|
||||
* claude via a `.claude/settings.local.json` block, omp via the hook
|
||||
* MODULE named by `approvalHookFile` below.
|
||||
* 'none' — no hook signals, ever (every external CLI, and `shell`). A CLI can
|
||||
* still report approval dialogs alone through `approvalHookFile` below.
|
||||
* 'always' — the CLI installs Codeman's hooks (claude). Every consumer reads this
|
||||
* as Claude's FULL hook set: `stop`, `idle_prompt`, answerable inbox
|
||||
* items, and a `.claude/settings.local.json` block in the workspace.
|
||||
* 'supervised' — the CLI REPORTS its own idle/working/blocked state to a supervisor
|
||||
* over a generic env-gated contract, and Codeman is that supervisor
|
||||
* (deepseek, via deepseek-status-shim.ts). Definitive rather than
|
||||
@@ -526,16 +527,17 @@ export interface CliCapabilities {
|
||||
*/
|
||||
hooks: 'none' | 'always' | 'supervised';
|
||||
/**
|
||||
* A CLI whose hooks are MODULES rather than a settings-file block names the file
|
||||
* Codeman installs into its project hook directory.
|
||||
* The hook MODULE Codeman installs into the workspace of a CLI that reports its
|
||||
* approval dialogs, and nothing else, through hooks. Independent of `hooks` above.
|
||||
*
|
||||
* omp is the case that exists today: it loads `<cwd>/.claude/hooks/pre/*.ts`, and the
|
||||
* installed module forwards `tool_approval_requested`/`tool_approval_resolved` to
|
||||
* `/api/hook-event` as `permission_prompt`/`elicitation_complete`, so an omp pane asking
|
||||
* for approval raises the same tab alert, notification and Approvals Inbox item a claude
|
||||
* pane does. Absent with `hooks: 'always'` means Claude's settings-file block.
|
||||
* `/api/hook-event` as `permission_prompt`/`elicitation_complete`. What that earns
|
||||
* (`approvalHookAvailableForMode()`): the `blocked` wait signal, a tab alert, a
|
||||
* notification and an ALERT-ONLY inbox item (`answerInTerminal`). Never `stop`, never
|
||||
* `idle_prompt`, never Approve/Deny keystrokes.
|
||||
*
|
||||
* Declared as data, not a branch on the id, so the session-create path can ask
|
||||
* Declared as data, not a branch on the id, so both create paths can ask
|
||||
* "does this CLI need a hook file installed?" (see cli-registry-no-id-branching).
|
||||
*/
|
||||
approvalHookFile?: string;
|
||||
|
||||
Reference in new issue
Block a user