okstra 0.198.0 → 0.198.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.
@@ -27,6 +27,8 @@ Usage:
27
27
 
28
28
  'init' auto-fills --workspace-root from 'okstra paths --field workspace',
29
29
  so callers do not pass it.
30
+ Pass --preferred-task-key <project:group:task> to prioritize the task selected
31
+ in this conversation over project-wide recommendations without skipping the picker.
30
32
 
31
33
  All subcommands emit a single JSON object on stdout. On validation failure
32
34
  'step' returns {ok:false, error, current} so the skill can re-prompt.
@@ -102,6 +104,10 @@ export function buildPythonArgs(sub, flags, workspaceRoot = "") {
102
104
  if (hostRuntime) {
103
105
  pyArgs.push("--host-runtime", hostRuntime);
104
106
  }
107
+ const preferredTaskKey = stringFlag(flags, "preferred-task-key");
108
+ if (preferredTaskKey) {
109
+ pyArgs.push("--preferred-task-key", preferredTaskKey);
110
+ }
105
111
  for (const value of stringListFlag(flags, "available-function")) {
106
112
  pyArgs.push("--available-function", value);
107
113
  }
@@ -1 +1 @@
1
- {"version":3,"file":"wizard.mjs","sourceRoot":"","sources":["../../../src/commands/execute/wizard.mts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"wizard.mjs","sourceRoot":"","sources":["../../../src/commands/execute/wizard.mts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "okstra",
3
- "version": "0.198.0",
3
+ "version": "0.198.1",
4
4
  "description": "Host-aware multi-provider cross-verification orchestrator runtime and agent skills.",
5
5
  "license": "MIT",
6
6
  "author": "devonshin",
@@ -1,5 +1,5 @@
1
1
  {
2
- "package": "0.198.0",
3
- "builtAt": "2026-09-10T21:29:19.454Z",
2
+ "package": "0.198.1",
3
+ "builtAt": "2026-09-11T12:26:44.689Z",
4
4
  "repoRoot": "/home/runner/work/okstra/okstra"
5
5
  }
@@ -20,6 +20,8 @@ This adapter maps neutral Okstra lead operations to the Grok CLI. Read it only w
20
20
 
21
21
  ## Wizard interaction relay
22
22
 
23
+ Set `multi_select` explicitly on each object in `questions[]`: `true` for a multi-select question and `false` for a single-select question. The field belongs inside the question object, not at the call's top level. Grok uses `multi_select`; `multiSelect` is the Claude Code field. Before calling `ask_user_question`, check that every question carries the value specified by this relay. The relay field names and values are covered by `tests/contract/test_host_orchestration_rules.py`; the live host call still depends on the lead passing them.
24
+
23
25
  Read this contract when `okstra preflight` returns this file as `runtimeReadiness.relayContract`. The JSON is the complete interaction mapping for this host. `semanticFunctions` is an allowlist: the skill may declare a function only when both this list and the live harness expose it.
24
26
 
25
27
  ```json
@@ -45,7 +47,7 @@ Read this contract when `okstra preflight` returns this file as `runtimeReadines
45
47
  "questions": "one",
46
48
  "question": "label-with-progress",
47
49
  "options": "all-in-original-order-as-label-description",
48
- "multiSelect": false
50
+ "multi_select": false
49
51
  },
50
52
  "response": {
51
53
  "envelope": "answers",
@@ -61,7 +63,7 @@ Read this contract when `okstra preflight` returns this file as `runtimeReadines
61
63
  "questions": "one",
62
64
  "question": "label-with-progress",
63
65
  "options": "all-in-original-order-as-label-description",
64
- "multiSelect": true
66
+ "multi_select": true
65
67
  },
66
68
  "response": {
67
69
  "envelope": "answers",
@@ -77,7 +79,7 @@ Read this contract when `okstra preflight` returns this file as `runtimeReadines
77
79
  "questions": "all-in-original-order",
78
80
  "question": "label-with-progress",
79
81
  "options": "all-in-original-order-as-label-description",
80
- "multiSelect": "questions[].multi"
82
+ "multi_select": "questions[].multi"
81
83
  },
82
84
  "response": {
83
85
  "envelope": "answers",
@@ -456,11 +456,26 @@ def spawn_worker_surface(
456
456
  )
457
457
  target = _pane_by_id(panes, placement.pane_id)
458
458
  surface_uuid = _open_worker_surface(workspace, placement, target)
459
- rename_surface(surface_uuid, title)
460
- _exec_worker(surface_uuid, cwd=cwd, command=command)
461
- owned = (*owned_surface_ids, surface_uuid)
462
- _size_lead_pane(workspace, owned)
463
- _equalize_worker_heights(workspace, owned)
459
+ try:
460
+ renamed = rename_surface(surface_uuid, title)
461
+ if renamed.returncode != 0:
462
+ raise RuntimeError(renamed.stderr.strip() or "cmux could not name the worker")
463
+ _exec_worker(surface_uuid, cwd=cwd, command=command)
464
+ owned = (*owned_surface_ids, surface_uuid)
465
+ _size_lead_pane(workspace, owned)
466
+ _equalize_worker_heights(workspace, owned)
467
+ except (RuntimeError, OSError, subprocess.SubprocessError) as exc:
468
+ # 호출이 반환되기 전에는 명부에 창 식별자가 없다. 여기서 정리하지
469
+ # 않으면 대체 실행으로 전환된 뒤에도 회수할 수 없는 창이 남는다.
470
+ try:
471
+ closed = run_cmux(["close-surface", "--surface", surface_uuid])
472
+ if closed.returncode != 0:
473
+ raise RuntimeError(closed.stderr.strip() or "cmux close failed")
474
+ except (RuntimeError, OSError, subprocess.SubprocessError) as cleanup_error:
475
+ raise RuntimeError(
476
+ f"{exc}; cleanup failed for cmux surface {surface_uuid}: {cleanup_error}"
477
+ ) from exc
478
+ raise
464
479
  return surface_uuid
465
480
 
466
481
 
@@ -1188,17 +1188,10 @@ def _required_worker_roles(ctx: dict, reviewers: list[str]) -> list[dict]:
1188
1188
 
1189
1189
 
1190
1190
  def _optional_worker_roles(ctx: dict) -> list[dict]:
1191
- """Roles this run may dispatch but does not require today, the critics.
1191
+ """선택해 배정한 비평 역할. 선택 후에는 실행 또는 미실행 사유가 필요하다.
1192
1192
 
1193
- A critic is opt-in, so it never belonged in `requiredWorkerRoles`. But it
1194
- was absent from the roster entirely, and both `okstra team dispatch` and
1195
- the liveness reader locate a worker by its team-state row: dispatching a
1196
- critic failed with `team-state has no workerId=acceptance`, while adding
1197
- the row by hand failed validation as an `unexpected worker role`. Declaring
1198
- it here makes the roster say what the run may run, so both sides agree.
1199
-
1200
- Keyed off `invocationAssignments`, which is where the run records the
1201
- critic it actually resolved — an absent `critic/*` entry means no critic.
1193
+ `invocationAssignments`의 `critic/*` 배정만 선언하므로 역할을 선택하지
1194
+ 않은 실행에는 행이 없다. 완료 검증은 선언된 행의 결과와 사유를 검사한다.
1202
1195
  """
1203
1196
  assignments = _invocation_assignments(ctx)
1204
1197
  roles: list[dict] = []
@@ -1220,7 +1213,7 @@ def _optional_worker_roles(ctx: dict) -> list[dict]:
1220
1213
  # critic has no prompt or result until it is dispatched.
1221
1214
  "resultPath": "",
1222
1215
  "promptPath": "",
1223
- "attemptRequired": False,
1216
+ "attemptRequired": True,
1224
1217
  })
1225
1218
  return roles
1226
1219
 
@@ -42,6 +42,7 @@ def main(argv: list[str]) -> int:
42
42
  p_init.add_argument("--workspace-root", required=True)
43
43
  p_init.add_argument("--project-root", required=True)
44
44
  p_init.add_argument("--project-id", required=True)
45
+ p_init.add_argument("--preferred-task-key", default="")
45
46
  p_init.add_argument(
46
47
  "--host-runtime",
47
48
  default="claude-code",
@@ -81,6 +82,7 @@ def main(argv: list[str]) -> int:
81
82
  workspace_root=args.workspace_root,
82
83
  project_root=args.project_root,
83
84
  project_id=args.project_id,
85
+ preferred_task_key=args.preferred_task_key,
84
86
  host_runtime=args.host_runtime,
85
87
  host_entry_mode=args.entry_mode,
86
88
  available_functions=args.available_function,
@@ -54,6 +54,7 @@ def init_state(
54
54
  host_runtime: str = "claude-code",
55
55
  host_entry_mode: str = "current-session",
56
56
  available_functions: Optional[list[str]] = None,
57
+ preferred_task_key: str = "",
57
58
  ) -> WizardState:
58
59
  """Bootstrap a new wizard state."""
59
60
  return WizardState(
@@ -61,6 +62,7 @@ def init_state(
61
62
  workspace_root=workspace_root,
62
63
  project_root=project_root,
63
64
  project_id=project_id,
65
+ preferred_task_key=preferred_task_key,
64
66
  host_runtime=host_runtime,
65
67
  host_entry_mode=host_entry_mode,
66
68
  available_functions=list(available_functions or []),
@@ -39,6 +39,7 @@ class WizardState:
39
39
  workspace_root: str = ""
40
40
  project_root: str = ""
41
41
  project_id: str = ""
42
+ preferred_task_key: str = ""
42
43
  host_runtime: str = "claude-code"
43
44
  host_entry_mode: str = "current-session"
44
45
  available_functions: list[str] = field(default_factory=list)
@@ -129,9 +129,12 @@ def _next_phase_cell(raw: Any) -> str:
129
129
  return f"{cell} ({pointer['status']})"
130
130
 
131
131
 
132
- def _recommended_task_entry(remaining: list[dict], latest_key: str) -> dict | None:
132
+ def _recommended_task_entry(
133
+ remaining: list[dict], latest_key: str, preferred_key: str = "",
134
+ ) -> dict | None:
133
135
  """남은 task 중 이 run 이 권하는 하나.
134
136
 
137
+ 현재 대화에서 전달한 task 를 우선한다. 전달값이 없으면
135
138
  포인터가 `ready` 인 task 는 지금 바로 다음 phase 를 시작할 수 있는 task 다
136
139
  — 그중 최신(카탈로그는 updatedAt 내림차순)을 권한다. `ready` 가 없으면
137
140
  마지막으로 만진 task(`latest-task.json`)를, 그것도 목록에 없으면 최신
@@ -139,6 +142,11 @@ def _recommended_task_entry(remaining: list[dict], latest_key: str) -> dict | No
139
142
  산문에서 2번을 권했다 — 추천이 여럿이면 라벨은 아무것도 고르지 않은
140
143
  것이다.
141
144
  """
145
+ if preferred_key:
146
+ for entry in remaining:
147
+ if entry.get("taskKey") == preferred_key:
148
+ return entry
149
+ raise WizardError(f"preferred task not found in project catalog: {preferred_key}")
142
150
  if not remaining:
143
151
  return None
144
152
  for entry in remaining:
@@ -158,9 +166,10 @@ def _build_task_pick(state: WizardState) -> Prompt:
158
166
  latest = read_latest_task(project_root) or {}
159
167
  latest_key = latest.get("taskKey") or ""
160
168
  latest_suffix = t["options"].get("_LATEST_SUFFIX", "")
161
- remaining = [e for e in tasks if (e.get("workStatus") or "") != "done"]
169
+ remaining = [e for e in tasks if (e.get("workStatus") or "") != "done"
170
+ or e.get("taskKey") == state.preferred_task_key]
162
171
  # 추천은 하나이고 1번이다. 나머지는 최신순 그대로.
163
- recommended = _recommended_task_entry(remaining, latest_key)
172
+ recommended = _recommended_task_entry(remaining, latest_key, state.preferred_task_key)
164
173
  ordered = (
165
174
  [recommended, *(e for e in remaining if e is not recommended)]
166
175
  if recommended is not None else remaining
@@ -187,6 +196,7 @@ def _build_task_pick(state: WizardState) -> Prompt:
187
196
  def _submit_task_pick(state: WizardState, value: str) -> Optional[str]:
188
197
  value = value.strip()
189
198
  if value == TASK_PICK_NEW_TOKEN:
199
+ state.preferred_task_key = ""
190
200
  state.is_new_task = True
191
201
  state.task_group = ""
192
202
  state.task_id = ""
@@ -207,6 +217,7 @@ def _submit_task_pick(state: WizardState, value: str) -> Optional[str]:
207
217
  state.is_new_task = False
208
218
  state.task_group = tg
209
219
  state.task_id = tid
220
+ state.preferred_task_key = value
210
221
  state.existing_brief_path = _existing_task_brief(
211
222
  Path(state.project_root), value
212
223
  )
@@ -149,7 +149,13 @@ okstra wizard new-state-file
149
149
 
150
150
  This prints one absolute path on stdout (e.g. `/var/folders/.../okstra-wizard.AbCd.json`). Read that path from the tool output and **paste it literally** into every subsequent `--state-file` argument.
151
151
 
152
- Then initialize the wizard with the literal `projectRoot` / `projectId` you parsed from Step 1 and the literal state-file path from above:
152
+ Then initialize the wizard with the literal `projectRoot` / `projectId` you parsed from Step 1 and the literal state-file path from above.
153
+
154
+ For task continuity, pass `--preferred-task-key <project-id:task-group:task-id>` on every initialization when this conversation has a known task. Use the task explicitly requested in the current message first; otherwise use the last task the user selected in this conversation's wizard. Resolve abbreviated task IDs against the project catalog before passing the full key. If the ID is ambiguous, ask which matching task the user means. Never infer this conversation's selection from project-wide `latest-task.json`, catalog recency, or another session. With neither an explicit task nor a prior selection in this conversation, omit the flag. The runtime puts the preferred task first, including a completed task when explicitly carried in, and rejects a key absent from the catalog instead of substituting another task; ordering is covered by `tests/domain/wizard/test_task_selection.py`. The task picker still lets the user change tasks.
155
+
156
+ After a successful task selection, retain the returned full task key in this conversation as its task context, including in continuation summaries, and carry it into the next initialization. A different selection replaces it. Selecting a brand-new task clears the previous selection; retain the new full key once its project, group, and task ID are resolved. This conversation carry-forward is a lead instruction, not automatic host-session discovery by the runtime.
157
+
158
+ Initialize with the optional preferred key resolved above:
153
159
 
154
160
  ```bash
155
161
  okstra wizard init \
@@ -77,7 +77,6 @@
77
77
  </table>
78
78
  </section>
79
79
  {% endif %}
80
- {{ clarification_responses(clarificationItems) }}
81
80
  {% if evidenceIndex %}
82
81
  <section data-report-section="evidence-ledger" data-reader-kind="audit">
83
82
  <h2>{{ t('base.evidence-ledger') }}</h2>
@@ -139,6 +138,7 @@
139
138
  </table>
140
139
  </section>
141
140
  {% endif %}
141
+ {{ clarification_responses(clarificationItems) }}
142
142
  </main>
143
143
  {% if approval is not defined or not (approval and approval.reentry_command) %}<footer class="human-report-footer">
144
144
  <button type="button" data-action="export-user-response">{{ t('base.export-my-answers') }}</button>
@@ -147,8 +147,9 @@
147
147
  <p class="user-response-hint">{{ t('base.export-downloads') }} <code>user-response-{{ runMeta.task_type }}-{{ runMeta.seq }}.md</code>{{ t('base.drop-that-file-into') }} <code>{{ userResponseDir }}</code> {{ t('base.and-the-next-run-picks-your-answers-up-on-it') }}</p>
148
148
  <pre id="user-response-output" aria-live="polite"></pre>
149
149
  </footer>{% endif %}
150
+ <div id="bottom"></div>
150
151
  <div class="back-to-top-wrap">
151
- <nav class="back-to-top-index" id="back-to-top-index" aria-label="{{ t('base.contents') }}"><!--report-index-items--></nav>
152
+ <nav class="back-to-top-index" id="back-to-top-index" aria-label="{{ t('base.contents') }}"><!--report-index-items--><a href="#bottom">{{ t('base.go-to-bottom') }}</a></nav>
152
153
  <a class="back-to-top" href="#top">{{ t('base.back-to-top') }}</a>
153
154
  </div>
154
155
  <script id="run-meta" type="application/json">{{ {
@@ -164,6 +164,7 @@
164
164
  "base": {
165
165
  "skip-to-report-content": "Skip to report content",
166
166
  "back-to-top": "Back to top",
167
+ "go-to-bottom": "Go to bottom",
167
168
  "contents": "Contents",
168
169
  "task": "Task",
169
170
  "execution-roles": "Execution roles",
@@ -164,6 +164,7 @@
164
164
  "base": {
165
165
  "skip-to-report-content": "리포트 본문으로 건너뛰기",
166
166
  "back-to-top": "맨 위로",
167
+ "go-to-bottom": "맨 아래로",
167
168
  "contents": "목차",
168
169
  "task": "태스크",
169
170
  "execution-roles": "실행 역할",
@@ -1570,7 +1570,12 @@ def validate_team_state(
1570
1570
  by_role[role] = worker
1571
1571
 
1572
1572
  expected_workers: dict[str, dict] = {}
1573
- for worker in contract["required_worker_roles"]:
1573
+ # 선택은 배정 전의 선택이다. 배정된 비평 역할도 결과 또는 생략 사유가
1574
+ # 있어야 하므로 필수 역할과 같은 상태 검사를 거친다.
1575
+ for worker in [
1576
+ *contract["required_worker_roles"],
1577
+ *contract.get("optional_worker_roles", []),
1578
+ ]:
1574
1579
  if not isinstance(worker, dict):
1575
1580
  failures.append("requiredWorkerRoles contains a non-object entry")
1576
1581
  continue
@@ -1646,15 +1651,7 @@ def validate_team_state(
1646
1651
  if status != "completed" and not reason:
1647
1652
  failures.append(f"{role} with status `{status}` must include a reason")
1648
1653
 
1649
- # A declared optional role may appear in the roster and may equally be
1650
- # absent: the run states which ones it can dispatch (today, the critics),
1651
- # and running one is not a contract violation.
1652
- optional_roles = {
1653
- str(worker.get("role", "")).strip()
1654
- for worker in contract.get("optional_worker_roles", [])
1655
- if isinstance(worker, dict) and str(worker.get("role", "")).strip()
1656
- }
1657
- unexpected_roles = set(by_role) - set(expected_workers) - optional_roles
1654
+ unexpected_roles = set(by_role) - set(expected_workers)
1658
1655
  for role in sorted(unexpected_roles):
1659
1656
  failures.append(f"unexpected worker role detected: {role}")
1660
1657