okstra 0.10.0 → 0.12.0

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.
@@ -36,18 +36,26 @@ Do NOT hard-code or guess any okstra path. Every run loads them fresh from
36
36
  the single authority — `okstra`:
37
37
 
38
38
  ```bash
39
+ # 0) Resolve runner: prefer PATH (npm-installed) over npx (avoids per-call registry lookup).
40
+ # If the user installed okstra via npm, they control upgrade timing — do not force @latest.
41
+ if command -v okstra >/dev/null 2>&1; then
42
+ OKSTRA_CMD="okstra"
43
+ else
44
+ OKSTRA_CMD="npx -y okstra@latest"
45
+ fi
46
+
39
47
  # 1) Ensure runtime is fresh (idempotent, cached when up-to-date)
40
- npx -y okstra@latest ensure-installed >/dev/null 2>&1 || {
48
+ $OKSTRA_CMD ensure-installed >/dev/null 2>&1 || {
41
49
  echo "FAIL: okstra not installed; tell the user to run: npx okstra@latest install" >&2
42
50
  exit 1
43
51
  }
44
52
 
45
53
  # 2) Load all runtime paths into the shell as OKSTRA_* exports
46
- eval "$(npx -y okstra@latest paths --shell)"
54
+ eval "$($OKSTRA_CMD paths --shell)"
47
55
  export PYTHONPATH="$OKSTRA_PYTHONPATH"
48
56
 
49
57
  # 3) Verify the current project has okstra metadata (project.json + projectId)
50
- OKSTRA_PROJECT_INFO="$(npx -y okstra@latest check-project --json)" || {
58
+ OKSTRA_PROJECT_INFO="$($OKSTRA_CMD check-project --json)" || {
51
59
  echo "FAIL: this project has no okstra setup. Tell the user to run /okstra-setup first." >&2
52
60
  echo "$OKSTRA_PROJECT_INFO" >&2
53
61
  exit 1
@@ -40,13 +40,18 @@ If `--title` is omitted, derive a default title from `task-group` (e.g. `uploadF
40
40
  Run before anything else in this skill:
41
41
 
42
42
  ```bash
43
- npx -y okstra@latest ensure-installed >/dev/null 2>&1 || {
43
+ if command -v okstra >/dev/null 2>&1; then
44
+ OKSTRA_CMD="okstra"
45
+ else
46
+ OKSTRA_CMD="npx -y okstra@latest"
47
+ fi
48
+ $OKSTRA_CMD ensure-installed >/dev/null 2>&1 || {
44
49
  echo "FAIL: okstra not installed; tell the user to run: npx okstra@latest install" >&2
45
50
  exit 1
46
51
  }
47
- eval "$(npx -y okstra@latest paths --shell)"
52
+ eval "$($OKSTRA_CMD paths --shell)"
48
53
  export PYTHONPATH="$OKSTRA_PYTHONPATH"
49
- OKSTRA_PROJECT_INFO="$(npx -y okstra@latest check-project --json)" || {
54
+ OKSTRA_PROJECT_INFO="$($OKSTRA_CMD check-project --json)" || {
50
55
  echo "FAIL: this project has no okstra setup. Tell the user to run /okstra-setup first." >&2
51
56
  echo "$OKSTRA_PROJECT_INFO" >&2
52
57
  exit 1
@@ -55,7 +55,13 @@ running the legacy `okstra-install.sh` — that path is dev-only.
55
55
  ## Step 2: Load runtime paths
56
56
 
57
57
  ```bash
58
- eval "$(npx -y okstra@latest paths --shell)"
58
+ # Prefer PATH-resolved okstra (npm-installed) over npx — avoids per-call registry lookup.
59
+ if command -v okstra >/dev/null 2>&1; then
60
+ OKSTRA_CMD="okstra"
61
+ else
62
+ OKSTRA_CMD="npx -y okstra@latest"
63
+ fi
64
+ eval "$($OKSTRA_CMD paths --shell)"
59
65
  export PYTHONPATH="$OKSTRA_PYTHONPATH"
60
66
  ```
61
67
 
@@ -113,7 +119,7 @@ PY
113
119
  ## Step 5: Verify
114
120
 
115
121
  ```bash
116
- npx -y okstra@latest doctor
122
+ $OKSTRA_CMD doctor
117
123
  ```
118
124
 
119
125
  If all checks return `OK`, the setup is complete. If any check fails, surface
@@ -17,13 +17,18 @@ Before any other step, ensure both the okstra runtime and the current
17
17
  project's okstra metadata are in place:
18
18
 
19
19
  ```bash
20
- npx -y okstra@latest ensure-installed >/dev/null 2>&1 || {
20
+ if command -v okstra >/dev/null 2>&1; then
21
+ OKSTRA_CMD="okstra"
22
+ else
23
+ OKSTRA_CMD="npx -y okstra@latest"
24
+ fi
25
+ $OKSTRA_CMD ensure-installed >/dev/null 2>&1 || {
21
26
  echo "FAIL: okstra not installed; tell the user to run: npx okstra@latest install" >&2
22
27
  exit 1
23
28
  }
24
- eval "$(npx -y okstra@latest paths --shell)"
29
+ eval "$($OKSTRA_CMD paths --shell)"
25
30
  export PYTHONPATH="$OKSTRA_PYTHONPATH"
26
- OKSTRA_PROJECT_INFO="$(npx -y okstra@latest check-project --json)" || {
31
+ OKSTRA_PROJECT_INFO="$($OKSTRA_CMD check-project --json)" || {
27
32
  echo "FAIL: this project has no okstra setup. Tell the user to run /okstra-setup first." >&2
28
33
  echo "$OKSTRA_PROJECT_INFO" >&2
29
34
  exit 1
@@ -30,13 +30,18 @@ If a run never reached Phase 7, its `team-state` will not have `durationMs` fill
30
30
  ## Step 0: Verify okstra runtime + project setup
31
31
 
32
32
  ```bash
33
- npx -y okstra@latest ensure-installed >/dev/null 2>&1 || {
33
+ if command -v okstra >/dev/null 2>&1; then
34
+ OKSTRA_CMD="okstra"
35
+ else
36
+ OKSTRA_CMD="npx -y okstra@latest"
37
+ fi
38
+ $OKSTRA_CMD ensure-installed >/dev/null 2>&1 || {
34
39
  echo "FAIL: okstra not installed; tell the user to run: npx okstra@latest install" >&2
35
40
  exit 1
36
41
  }
37
- eval "$(npx -y okstra@latest paths --shell)"
42
+ eval "$($OKSTRA_CMD paths --shell)"
38
43
  export PYTHONPATH="$OKSTRA_PYTHONPATH"
39
- OKSTRA_PROJECT_INFO="$(npx -y okstra@latest check-project --json)" || {
44
+ OKSTRA_PROJECT_INFO="$($OKSTRA_CMD check-project --json)" || {
40
45
  echo "FAIL: this project has no okstra setup. Tell the user to run /okstra-setup first." >&2
41
46
  echo "$OKSTRA_PROJECT_INFO" >&2
42
47
  exit 1
@@ -324,6 +324,28 @@ def validate_team_state(
324
324
  failures.append("team-state.workers must be a list")
325
325
  return
326
326
 
327
+ dispatched_statuses = {"completed", "timeout", "error", "in-progress"}
328
+ any_dispatched = any(
329
+ isinstance(w, dict) and str(w.get("status", "")).strip() in dispatched_statuses
330
+ for w in workers
331
+ )
332
+ if any_dispatched:
333
+ team_create = team_state.get("teamCreate")
334
+ if not isinstance(team_create, dict) or not team_create.get("attempted"):
335
+ failures.append(
336
+ "team-state.teamCreate.attempted must be true once any worker has "
337
+ "been dispatched (status in completed/timeout/error/in-progress). "
338
+ "Phase 3 (TeamCreate) was skipped — workers ran in-process without "
339
+ "the Teams split-pane surface. See agents/SKILL.md Phase 3."
340
+ )
341
+ else:
342
+ tc_status = str(team_create.get("status", "")).strip()
343
+ if tc_status not in {"ok", "error"}:
344
+ failures.append(
345
+ "team-state.teamCreate.status must be `ok` or `error` once "
346
+ f"workers have been dispatched (found: `{tc_status}`)."
347
+ )
348
+
327
349
  by_role: dict[str, dict] = {}
328
350
  for worker in workers:
329
351
  if not isinstance(worker, dict):