okstra 0.148.0 → 0.148.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "okstra",
3
- "version": "0.148.0",
3
+ "version": "0.148.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.148.0",
3
- "builtAt": "2026-08-03T19:00:08.212Z",
2
+ "package": "0.148.1",
3
+ "builtAt": "2026-08-04T05:55:30.824Z",
4
4
  "repoRoot": "/home/runner/work/okstra/okstra"
5
5
  }
@@ -9,6 +9,7 @@ import okstra_vendor # noqa: F401 # registers vendored dependency aliases
9
9
  from jinja2 import Environment, FileSystemLoader, StrictUndefined, select_autoescape
10
10
 
11
11
  from ..final_report_schema import load_schema_for_data, validate
12
+ from ..report_view_artifacts import user_responses_dir_for_report
12
13
  from .filters import audit_json, code_evidence, evidence_refs, inline_code, paragraphs
13
14
  from .models import HtmlRunMeta
14
15
  from .router import HtmlRenderError, resolve_html_route
@@ -73,4 +74,8 @@ def render_v2_html_view(
73
74
  }
74
75
  output_path = _html_path(data_path)
75
76
  output_path.write_text(env.get_template(route.template_name).render(**context), encoding="utf-8")
77
+ if context["clarificationItems"]:
78
+ # The footer tells the reader to drop the exported file here, so the
79
+ # directory has to exist before they go looking for it.
80
+ user_responses_dir_for_report(data_path).mkdir(parents=True, exist_ok=True)
76
81
  return output_path
@@ -36,6 +36,12 @@ th, td { text-align: left; vertical-align: top; border-bottom: 1px solid color-m
36
36
  .human-report-footer pre { flex-basis: 100%; white-space: pre-wrap; max-height: 14em; overflow: auto; }
37
37
  fieldset, label { display: block; margin: .7rem 0; }
38
38
  textarea, select { width: 100%; max-width: 60rem; padding: .55rem; font: inherit; }
39
+ .clarification-lede, .clarification-item p { max-width: 78ch; }
40
+ .clarification-item { padding: 1.2rem 0; border-top: 1px solid color-mix(in srgb, CanvasText 14%, transparent); }
41
+ .clarification-item:first-of-type { border-top: 0; }
42
+ .clarification-expected { color: GrayText; font-size: .9rem; }
43
+ .clarification-item label { font-weight: 600; margin-bottom: .3rem; }
44
+ .user-response-hint { flex-basis: 100%; margin: 0; color: GrayText; font-size: .9rem; }
39
45
  @media (max-width: 640px) { section { padding: 1rem; } .visualization { display: none; } }
40
46
  @media print { .skip-link, .audit, script { display: none !important; } body { color: #000; background: #fff; } section { break-inside: avoid; border-color: #bbb; } .visualization-fallback { display: table; } }
41
47
  code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .9em; padding: .1em .3em; border-radius: 4px; background: color-mix(in srgb, CanvasText 8%, Canvas); }
@@ -64,6 +64,7 @@
64
64
  <button type="button" data-action="export-user-response">사용자 응답 내보내기</button>
65
65
  <button type="button" data-action="copy-user-response">복사</button>
66
66
  <button type="button" data-action="dismiss-user-response" hidden>닫기</button>
67
+ <p class="user-response-hint">내보내기를 누르면 <code>user-response-{{ runMeta.task_type }}-{{ runMeta.seq }}.md</code> 가 다운로드됩니다. 그 파일을 <code>runs/{{ runMeta.task_type }}/user-responses/</code> 에 넣고 다음 run 을 실행하면 답변이 자동으로 반영됩니다.</p>
67
68
  <pre id="user-response-output" aria-live="polite"></pre>
68
69
  </footer>
69
70
  <script id="run-meta" type="application/json">{{ {
@@ -32,16 +32,18 @@
32
32
 
33
33
  {% macro clarification_responses(items) -%}
34
34
  {% if items %}
35
- <section class="clarification-responses" aria-label="열린 질문에 답하기">
36
- <h2>열린 질문에 답하기</h2>
37
- <table><thead><tr><th>ID</th><th>질문</th><th>기대 형식</th><th>사용자 응답</th></tr></thead><tbody>
35
+ <section class="clarification-responses" aria-label="답변이 필요한 질문">
36
+ <h2>답변이 필요한 질문 {{ items | length }}개</h2>
37
+ <p class="clarification-lede">코드만 봐서는 정할 수 없어 남겨 둔 항목입니다. 답을 채운 뒤 맨 아래 <strong>사용자 응답 내보내기</strong>를 누르세요.</p>
38
38
  {% for row in items %}
39
- <tr data-response-id="{{ row.id }}" data-kind="{{ row.kind }}">
40
- <td>{{ row.id }}</td><td>{{ row.statement | inline_code }}</td><td>{{ row.expectedForm | inline_code }}</td>
41
- <td><label for="response-{{ row.id }}">{{ row.id }} 사용자 응답</label><textarea id="response-{{ row.id }}" data-response-id="{{ row.id }}" rows="3">{{ row.userInput | default('') }}</textarea></td>
42
- </tr>
39
+ <article class="clarification-item" data-response-id="{{ row.id }}" data-kind="{{ row.kind }}">
40
+ <p class="eyebrow">{{ row.id }} · {{ row.kind }}</p>
41
+ {{ row.statement | paragraphs }}
42
+ <p class="clarification-expected"><strong>답변 형식</strong> — {{ row.expectedForm | inline_code }}</p>
43
+ <label for="response-{{ row.id }}">{{ row.id }} 답변</label>
44
+ <textarea id="response-{{ row.id }}" data-response-id="{{ row.id }}" rows="4">{{ row.userInput | default('') }}</textarea>
45
+ </article>
43
46
  {% endfor %}
44
- </tbody></table>
45
47
  </section>
46
48
  {% endif %}
47
49
  {%- endmacro %}
@@ -74,7 +74,13 @@
74
74
 
75
75
  function collectEntries() {
76
76
  var entries = [];
77
- var rows = document.querySelectorAll("tr[data-response-id]");
77
+ // `tr` is the legacy Markdown-derived view; `article` is the v2 task
78
+ // template's card. Both container shapes carry the id and kind, and an
79
+ // allowlist of the two keeps the inner widgets (which repeat
80
+ // `data-response-id`) from matching as containers themselves.
81
+ var rows = document.querySelectorAll(
82
+ "tr[data-response-id], article[data-response-id]"
83
+ );
78
84
  for (var i = 0; i < rows.length; i++) {
79
85
  var row = rows[i];
80
86
  var value = readRowValue(row);