okstra 0.20.0 → 0.20.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.
@@ -836,7 +836,7 @@ Claude가 작성하는 최종 보고서는 brief에 더 구체적인 형식이
836
836
  ### Live-log mirror (codex / gemini wrapper)
837
837
 
838
838
  - `scripts/okstra-codex-exec.sh`, `scripts/okstra-gemini-exec.sh` 는 dispatch 마다 prompt path 옆에 `<prompt>.log` sidecar 를 만들고 stdout 을 거기로 mirror 합니다 (`tee`, `PIPESTATUS[0]` 로 종료코드 보존). stderr 은 같은 파일에 append (subagent stderr 캡처 contract 보존), 매 dispatch 시 truncate. 호출 subagent 의 `BashOutput` 폴링은 60s 간격이라 long-running run (analysis 의 large-codebase scan, implementation 의 cargo / pytest) 동안 사용자가 stalled state 를 탐지할 수 없는 문제를 해소합니다.
839
- - `$TMUX` 가 셋팅된 lead 환경이면 wrapper 가 sibling pane 을 자동 분할해 `tail -F <log-path>` 를 띄웁니다. pane title 은 `<cli>-<role>-trace` (e.g. `codex-executor-trace`, `gemini-worker-trace`); role 은 wrapper 의 5번째 optional positional 인자로 명시 가능하며, 누락 시 worktree-path 인자 유무에 따라 `executor` / `worker` 자동 결정. focus 는 caller pane 으로 복귀하고, CLI 종료 후 pane 은 유지돼 스크롤백 가능. `$TMUX` 미설정, split 실패, 구버전 tmux 등 모든 경로는 silent degrade.
839
+ - `$TMUX` 가 셋팅된 lead 환경이면 wrapper 가 sibling pane 을 자동 분할해 `tail -F <log-path>` 를 띄웁니다. pane title 은 `<cli>-<role>-trace` (e.g. `codex-worker-trace`, `gemini-worker-trace`); role 은 wrapper 의 5번째 optional positional 인자이며, 누락 시 기본값 `worker` 떨어집니다. caller 가 다른 라벨(예: `executor`)을 원하면 5번째 인자로 명시해야 합니다. focus 는 caller pane 으로 복귀하고, CLI 종료 후 pane 은 유지돼 스크롤백 가능. `$TMUX` 미설정, split 실패, 구버전 tmux 등 모든 경로는 silent degrade.
840
840
  - 디스크 누적은 `okstra-logs` skill 이 read-only 로 인벤토리 + cleanup 명령을 제안합니다 (실행은 사용자 copy-paste).
841
841
 
842
842
  ### Linked-worktree `.git/` write 권한 (codex / gemini)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "okstra",
3
- "version": "0.20.0",
3
+ "version": "0.20.1",
4
4
  "description": "Multi-agent cross-verification orchestrator runtime + Claude Code skills.",
5
5
  "license": "MIT",
6
6
  "author": "devonshin",
@@ -1,5 +1,5 @@
1
1
  {
2
- "package": "0.20.0",
3
- "builtAt": "2026-05-13T15:25:34.223Z",
2
+ "package": "0.20.1",
3
+ "builtAt": "2026-05-14T01:49:53.274Z",
4
4
  "repoRoot": "/home/runner/work/okstra/okstra"
5
5
  }
@@ -27,9 +27,11 @@ You are a Codex worker agent. Your job is to execute the OpenAI Codex CLI and re
27
27
 
28
28
  **Required form (uses the okstra wrapper to avoid redirect-triggered permission prompts):**
29
29
  ```bash
30
- $HOME/.okstra/bin/okstra-codex-exec.sh "<absolute-project-root>" "<assigned-model-execution-value>" "<absolute-prompt-history-path>" [<absolute-worktree-path>]
30
+ $HOME/.okstra/bin/okstra-codex-exec.sh "<absolute-project-root>" "<assigned-model-execution-value>" "<absolute-prompt-history-path>" [<absolute-worktree-path>] [<role>]
31
31
  ```
32
32
 
33
+ The fifth argument `<role>` is the trace-pane label suffix (`codex-<role>-trace`); pass the literal string `worker` for every dispatch from this subagent. The wrapper defaults to `worker` when the argument is omitted, but pass it explicitly so the dispatch is self-describing.
34
+
33
35
  The fourth argument is **mandatory for implementation phase** and optional otherwise. It must be the literal `EXECUTOR_WORKTREE_PATH` recorded in the run context; the wrapper forwards it to codex as `--add-dir`, which grants the codex sandbox write access to the worktree (where all implementation-phase mutations occur). Without it, codex's `workspace-write` sandbox is anchored only at `<project-root>` and rejects every Edit/Write that targets the worktree (EPERM), which is the failure pattern that originally motivated this argument.
34
36
 
35
37
  The wrapper internally runs:
@@ -73,7 +75,7 @@ The wrapper exists because Claude Code's Bash permission matcher rejects simple-
73
75
 
74
76
  **Dispatch (background, no foreground timeout):**
75
77
  ```bash
76
- $HOME/.okstra/bin/okstra-codex-exec.sh "<absolute-project-root>" "<assigned-model-execution-value>" "<absolute-prompt-history-path>" "<absolute-worktree-path>"
78
+ $HOME/.okstra/bin/okstra-codex-exec.sh "<absolute-project-root>" "<assigned-model-execution-value>" "<absolute-prompt-history-path>" "<absolute-worktree-path>" "worker"
77
79
  ```
78
80
  Call `Bash` with `run_in_background: true`. Capture the returned `bash_id` (a.k.a. `shell_id`). Pass the positional arguments verbatim — do NOT use environment variables, `cd`, `&&` chains, or pipes from `cat`. Substitute the literal extracted Project Root, model execution value, prompt-history path, and worktree path. The fourth argument is **mandatory for implementation phase** (extract from `EXECUTOR_WORKTREE_PATH` in the lead prompt's run context or the `**Worktree:**` / `cwd for every mutating command:` line) and **may be omitted only for non-implementation analysis phases** that do not mutate the worktree. Omitting it during implementation will cause every Edit/Write to fail with EPERM. The wrapper handles `-C`, `--add-dir`, `--model`, `--sandbox workspace-write`, the stdin redirect from the prompt file, and stderr suppression internally. Calling `codex exec` directly (without the wrapper) is an error in this skill: the redirect tokens disqualify the prefix match against `Bash(codex exec:*)` and produce a permission prompt every dispatch.
79
81
 
@@ -114,7 +116,7 @@ This wrapper does NOT invoke MCP tools directly. MCP availability inside the Cod
114
116
  - Include context (code, diff, file paths) if provided.
115
117
  - For long prompts, the wrapper script reads from the saved project-local prompt history file via stdin redirect internally. The caller invokes the wrapper with three required positional args + the worktree path for implementation phase:
116
118
  ```bash
117
- $HOME/.okstra/bin/okstra-codex-exec.sh "<literal-project-root>" "<assigned-model-execution-value>" "<literal-prompt-history-path>" "<literal-worktree-path>"
119
+ $HOME/.okstra/bin/okstra-codex-exec.sh "<literal-project-root>" "<assigned-model-execution-value>" "<literal-prompt-history-path>" "<literal-worktree-path>" "worker"
118
120
  ```
119
121
  - If the parent directory does not exist yet, create it before writing the prompt file.
120
122
 
@@ -184,7 +186,7 @@ and the run-level error log staying empty.
184
186
  --agent codex-worker --agent-role worker \
185
187
  --model "<assigned-model-execution-value>" \
186
188
  --error-type cli-failure \
187
- --command "$HOME/.okstra/bin/okstra-codex-exec.sh <project-root> <m> <prompt-path> <worktree-path>" \
189
+ --command "$HOME/.okstra/bin/okstra-codex-exec.sh <project-root> <m> <prompt-path> <worktree-path> worker" \
188
190
  --command-kind cli-invoke \
189
191
  --exit-code <N> --duration-ms <ms> \
190
192
  --message "<one-line summary>" \
@@ -27,9 +27,11 @@ You are a Gemini worker agent. Your job is to execute the Google Gemini CLI and
27
27
 
28
28
  **Required form (uses the okstra wrapper to avoid redirect-triggered permission prompts):**
29
29
  ```bash
30
- $HOME/.okstra/bin/okstra-gemini-exec.sh "<absolute-project-root>" "<assigned-model-execution-value>" "<absolute-prompt-history-path>" [<absolute-worktree-path>]
30
+ $HOME/.okstra/bin/okstra-gemini-exec.sh "<absolute-project-root>" "<assigned-model-execution-value>" "<absolute-prompt-history-path>" [<absolute-worktree-path>] [<role>]
31
31
  ```
32
32
 
33
+ The fifth argument `<role>` is the trace-pane label suffix (`gemini-<role>-trace`); pass the literal string `worker` for every dispatch from this subagent. The wrapper defaults to `worker` when the argument is omitted, but pass it explicitly so the dispatch is self-describing.
34
+
33
35
  The fourth argument is **mandatory for implementation phase** and optional otherwise. It must be the literal `EXECUTOR_WORKTREE_PATH` recorded in the run context; the wrapper appends it to gemini's `--include-directories` list so the model can both read and operate on the worktree alongside project-root.
34
36
 
35
37
  The wrapper internally runs:
@@ -73,7 +75,7 @@ The wrapper exists because Claude Code's Bash permission matcher rejects simple-
73
75
 
74
76
  **Dispatch (background, no foreground timeout):**
75
77
  ```bash
76
- $HOME/.okstra/bin/okstra-gemini-exec.sh "<absolute-project-root>" "<assigned-model-execution-value>" "<absolute-prompt-history-path>" "<absolute-worktree-path>"
78
+ $HOME/.okstra/bin/okstra-gemini-exec.sh "<absolute-project-root>" "<assigned-model-execution-value>" "<absolute-prompt-history-path>" "<absolute-worktree-path>" "worker"
77
79
  ```
78
80
  Call `Bash` with `run_in_background: true`. Capture the returned `bash_id` (a.k.a. `shell_id`). Pass the positional arguments verbatim — do NOT use environment variables, `cd`, `&&` chains, or pipes from `cat`. Substitute the literal extracted Project Root, model execution value, prompt-history path, and worktree path. The fourth argument is **mandatory for implementation phase** (extract from `EXECUTOR_WORKTREE_PATH` in the lead prompt's run context or the `**Worktree:**` / `cwd for every mutating command:` line) and **may be omitted only for non-implementation analysis phases** that do not mutate the worktree. The wrapper handles `-p -`, `-m`, `-o text`, `--include-directories`, the stdin redirect from the prompt file, and stderr suppression internally. Calling `gemini` directly (without the wrapper) is an error in this skill: the redirect tokens disqualify the prefix match against `Bash(gemini:*)` and produce a permission prompt every dispatch.
79
81
 
@@ -114,7 +116,7 @@ This wrapper does NOT invoke MCP tools directly. MCP availability inside the Gem
114
116
  - Include context (code, diff, file paths) if provided.
115
117
  - For long prompts, dispatch through the wrapper with literal absolute paths (plus the worktree path for implementation phase):
116
118
  ```bash
117
- $HOME/.okstra/bin/okstra-gemini-exec.sh "<literal-project-root>" "<assigned-model-execution-value>" "<literal-prompt-history-path>" "<literal-worktree-path>"
119
+ $HOME/.okstra/bin/okstra-gemini-exec.sh "<literal-project-root>" "<assigned-model-execution-value>" "<literal-prompt-history-path>" "<literal-worktree-path>" "worker"
118
120
  ```
119
121
  - If the parent directory does not exist yet, create it before writing the prompt file.
120
122
 
@@ -184,7 +186,7 @@ and the run-level error log staying empty.
184
186
  --agent gemini-worker --agent-role worker \
185
187
  --model "<assigned-model-execution-value>" \
186
188
  --error-type cli-failure \
187
- --command "$HOME/.okstra/bin/okstra-gemini-exec.sh <project-root> <m> <prompt-path> <worktree-path>" \
189
+ --command "$HOME/.okstra/bin/okstra-gemini-exec.sh <project-root> <m> <prompt-path> <worktree-path> worker" \
188
190
  --command-kind cli-invoke \
189
191
  --exit-code <N> --duration-ms <ms> \
190
192
  --message "<one-line summary>" \
@@ -53,10 +53,7 @@ project_root="$1"
53
53
  model="$2"
54
54
  prompt_path="$3"
55
55
  worktree_path="${4-}"
56
- role="${5-}"
57
- if [[ -z "$role" ]]; then
58
- if [[ -n "$worktree_path" ]]; then role="executor"; else role="worker"; fi
59
- fi
56
+ role="${5:-worker}"
60
57
 
61
58
  if [[ -z "$project_root" || ! -d "$project_root" ]]; then
62
59
  printf 'okstra-codex-exec: project-root is missing or not a directory: %q\n' "$project_root" >&2
@@ -127,8 +124,10 @@ log_path="${prompt_path%.md}.log"
127
124
  # for the wrapper to exit. This fires in every phase the wrapper is invoked
128
125
  # from (analysis, error-analysis, implementation-planning, implementation,
129
126
  # …) — long-running codex dispatches are not implementation-specific. The
130
- # new pane carries the title `codex-<role>-trace` (e.g. `codex-worker-trace`
131
- # in analysis, `codex-executor-trace` in implementation) and uses `tail -F`
127
+ # new pane carries the title `codex-<role>-trace` `role` is the optional
128
+ # 5th positional arg (defaults to `worker`); callers that dispatch a
129
+ # different role (e.g. `executor`) must pass it explicitly. The pane uses
130
+ # `tail -F`
132
131
  # (follow-by-name) so it survives any truncation a re-dispatch performs on
133
132
  # the same log path. Failures are tolerated silently: missing $TMUX, a tmux
134
133
  # that refuses to split (size constraints, locked client), or a stale socket
@@ -45,10 +45,7 @@ project_root="$1"
45
45
  model="$2"
46
46
  prompt_path="$3"
47
47
  worktree_path="${4-}"
48
- role="${5-}"
49
- if [[ -z "$role" ]]; then
50
- if [[ -n "$worktree_path" ]]; then role="executor"; else role="worker"; fi
51
- fi
48
+ role="${5:-worker}"
52
49
 
53
50
  if [[ -z "$project_root" || ! -d "$project_root" ]]; then
54
51
  printf 'okstra-gemini-exec: project-root is missing or not a directory: %q\n' "$project_root" >&2
@@ -112,10 +109,11 @@ log_path="${prompt_path%.md}.log"
112
109
  # When a tmux session is reachable, split a sibling pane tailing the log so
113
110
  # the operator can watch progress live. This fires in every phase the
114
111
  # wrapper is invoked from — long-running gemini dispatches are not
115
- # implementation-specific. Title `gemini-<role>-trace` (e.g.
116
- # `gemini-worker-trace` in analysis, `gemini-executor-trace` in
117
- # implementation). See the codex wrapper for the full design rationale and
118
- # the silent-degrade failure model.
112
+ # implementation-specific. Title `gemini-<role>-trace` — `role` is the
113
+ # optional 5th positional arg (defaults to `worker`); callers that
114
+ # dispatch a different role must pass it explicitly. See the codex
115
+ # wrapper for the full design rationale and the silent-degrade failure
116
+ # model.
119
117
  if [[ -n "${TMUX:-}" ]]; then
120
118
  trace_pane=$(tmux split-window -h -P -F '#{pane_id}' \
121
119
  -c "$(dirname "$log_path")" \
@@ -19,7 +19,6 @@ import json
19
19
  import os
20
20
  import re
21
21
  import shutil
22
- import subprocess
23
22
  from dataclasses import dataclass, field
24
23
  from datetime import datetime, timezone
25
24
  from pathlib import Path
@@ -819,11 +818,6 @@ def prepare_task_bundle(inp: PrepareInputs) -> PrepareOutputs:
819
818
  )
820
819
 
821
820
 
822
- def claude_is_available() -> bool:
823
- """`claude` CLI 가 PATH 에 있는지 확인."""
824
- return shutil.which("claude") is not None
825
-
826
-
827
821
  def main(argv: list[str]) -> int:
828
822
  """CLI dispatcher for bash thin-wrapper use. Parses a flat list of argv
829
823
  (the same flags `okstra.sh` accepts), runs prepare_task_bundle, prints
@@ -43,9 +43,6 @@ from .ids import _safe_fs_segment
43
43
  from . import worktree_registry
44
44
 
45
45
 
46
- OKSTRA_WORKTREES_RELATIVE = Path(".okstra/worktrees")
47
-
48
-
49
46
  # Project-root directories that hold okstra task state, ignored by git, or
50
47
  # otherwise required for the executor to operate but NOT carried across by
51
48
  # `git worktree add`. Each is symlinked from the MAIN worktree into the new
@@ -5,8 +5,6 @@ from .paths import utc_now
5
5
  from .pricing import (
6
6
  claude_billable_equivalent,
7
7
  claude_cost_usd,
8
- codex_cost_usd,
9
- gemini_cost_usd,
10
8
  )
11
9
 
12
10
 
@@ -15,8 +15,6 @@ def claude_session_totals(jsonl_path: Path) -> dict:
15
15
  model: str | None = None
16
16
  first_ts: str | None = None
17
17
  last_ts: str | None = None
18
- started_at: str | None = None
19
- ended_at: str | None = None
20
18
  for rec in iter_jsonl(jsonl_path):
21
19
  if agent_name is None and rec.get("agentName"):
22
20
  agent_name = rec["agentName"]