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.
- package/docs/kr/architecture.md +1 -1
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/codex-worker.md +6 -4
- package/runtime/agents/workers/gemini-worker.md +6 -4
- package/runtime/bin/okstra-codex-exec.sh +5 -6
- package/runtime/bin/okstra-gemini-exec.sh +6 -8
- package/runtime/python/okstra_ctl/run.py +0 -6
- package/runtime/python/okstra_ctl/worktree.py +0 -3
- package/runtime/python/okstra_token_usage/blocks.py +0 -2
- package/runtime/python/okstra_token_usage/claude.py +0 -2
package/docs/kr/architecture.md
CHANGED
|
@@ -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-
|
|
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
package/runtime/BUILD.json
CHANGED
|
@@ -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`
|
|
131
|
-
#
|
|
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`
|
|
116
|
-
#
|
|
117
|
-
#
|
|
118
|
-
# the silent-degrade failure
|
|
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
|
|
@@ -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"]
|