@mcptoolshop/accessibility-suite 0.1.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.
- package/.github/workflows/ci.yml +63 -0
- package/LICENSE +21 -0
- package/README.md +37 -0
- package/docs/prov-spec/.github/workflows/ci.yml +68 -0
- package/docs/prov-spec/CHANGELOG.md +69 -0
- package/docs/prov-spec/CODE_OF_CONDUCT.md +129 -0
- package/docs/prov-spec/CONFORMANCE_LEVELS.md +223 -0
- package/docs/prov-spec/CONTRIBUTING.md +145 -0
- package/docs/prov-spec/IMPLEMENTER_CHECKLIST.md +137 -0
- package/docs/prov-spec/LICENSE +21 -0
- package/docs/prov-spec/PRESS_RELEASE.md +74 -0
- package/docs/prov-spec/README.md +182 -0
- package/docs/prov-spec/SETUP.md +135 -0
- package/docs/prov-spec/WHY.md +86 -0
- package/docs/prov-spec/examples/artifact.example.json +14 -0
- package/docs/prov-spec/examples/artifact.ref.example.json +9 -0
- package/docs/prov-spec/examples/evidence.example.json +6 -0
- package/docs/prov-spec/examples/mcp.envelope.example.json +97 -0
- package/docs/prov-spec/examples/mcp.request.example.json +28 -0
- package/docs/prov-spec/examples/prov.record.example.json +35 -0
- package/docs/prov-spec/interop/PROOF_NODE_ENGINE.md +114 -0
- package/docs/prov-spec/spec/MCP_COMPATIBILITY.md +241 -0
- package/docs/prov-spec/spec/PROV_METHODS_CATALOG.md +142 -0
- package/docs/prov-spec/spec/PROV_METHODS_SPEC.md +397 -0
- package/docs/prov-spec/spec/methods.json +213 -0
- package/docs/prov-spec/spec/schemas/artifact.ref.schema.v0.1.json +58 -0
- package/docs/prov-spec/spec/schemas/artifact.schema.v0.1.json +61 -0
- package/docs/prov-spec/spec/schemas/assist.request.schema.v0.1.json +52 -0
- package/docs/prov-spec/spec/schemas/assist.response.schema.v0.1.json +70 -0
- package/docs/prov-spec/spec/schemas/cli.error.schema.v0.1.json +78 -0
- package/docs/prov-spec/spec/schemas/evidence.schema.v0.1.json +37 -0
- package/docs/prov-spec/spec/schemas/mcp.envelope.schema.v0.1.json +141 -0
- package/docs/prov-spec/spec/schemas/mcp.request.schema.v0.1.json +79 -0
- package/docs/prov-spec/spec/schemas/methods.schema.json +93 -0
- package/docs/prov-spec/spec/schemas/prov-capabilities.schema.json +122 -0
- package/docs/prov-spec/spec/schemas/prov.record.schema.v0.1.json +133 -0
- package/docs/prov-spec/spec/vectors/adapter.wrap.envelope_v0_1/expected.json +4 -0
- package/docs/prov-spec/spec/vectors/adapter.wrap.envelope_v0_1/input.json +1 -0
- package/docs/prov-spec/spec/vectors/adapter.wrap.envelope_v0_1/negative/double_wrapped.json +14 -0
- package/docs/prov-spec/spec/vectors/adapter.wrap.envelope_v0_1/negative/wrong_schema_version.json +11 -0
- package/docs/prov-spec/spec/vectors/engine.extract.evidence.json_pointer/expected.json +24 -0
- package/docs/prov-spec/spec/vectors/engine.extract.evidence.json_pointer/input.json +8 -0
- package/docs/prov-spec/spec/vectors/integrity.digest.sha256/expected.json +7 -0
- package/docs/prov-spec/spec/vectors/integrity.digest.sha256/input.json +1 -0
- package/docs/prov-spec/spec/vectors/integrity.digest.sha256/negative/non_hex_chars.json +16 -0
- package/docs/prov-spec/spec/vectors/integrity.digest.sha256/negative/uppercase_hex.json +16 -0
- package/docs/prov-spec/spec/vectors/integrity.digest.sha256/negative/wrong_length.json +16 -0
- package/docs/prov-spec/spec/vectors/method_id_syntax/negative/hyphen_separator.json +8 -0
- package/docs/prov-spec/spec/vectors/method_id_syntax/negative/reserved_namespace.json +8 -0
- package/docs/prov-spec/spec/vectors/method_id_syntax/negative/starts_with_digit.json +8 -0
- package/docs/prov-spec/spec/vectors/method_id_syntax/negative/uppercase.json +8 -0
- package/docs/prov-spec/spec/vectors/method_id_syntax/positive/valid_ids.json +18 -0
- package/docs/prov-spec/tools/python/prov_validator.py +428 -0
- package/examples/a11y-demo-site/.github/workflows/a11y-artifacts.yml +81 -0
- package/examples/a11y-demo-site/.github/workflows/a11y.yml +34 -0
- package/examples/a11y-demo-site/CODE_OF_CONDUCT.md +129 -0
- package/examples/a11y-demo-site/CONTRIBUTING.md +83 -0
- package/examples/a11y-demo-site/LICENSE +21 -0
- package/examples/a11y-demo-site/README.md +155 -0
- package/examples/a11y-demo-site/html/contact.html +15 -0
- package/examples/a11y-demo-site/html/index.html +20 -0
- package/examples/a11y-demo-site/scripts/a11y.sh +20 -0
- package/package.json +26 -0
- package/src/a11y-assist/.github/workflows/publish.yml +52 -0
- package/src/a11y-assist/.github/workflows/test.yml +30 -0
- package/src/a11y-assist/A11Y_ASSIST_TEST_COVERAGE_REQUIREMENTS.md +104 -0
- package/src/a11y-assist/CODE_OF_CONDUCT.md +129 -0
- package/src/a11y-assist/CONTRIBUTING.md +98 -0
- package/src/a11y-assist/ENGINE.md +363 -0
- package/src/a11y-assist/LICENSE +21 -0
- package/src/a11y-assist/PRESS_RELEASE.md +71 -0
- package/src/a11y-assist/QUICKSTART.md +101 -0
- package/src/a11y-assist/README.md +192 -0
- package/src/a11y-assist/RELEASE_NOTES.md +319 -0
- package/src/a11y-assist/a11y_assist/__init__.py +3 -0
- package/src/a11y-assist/a11y_assist/cli.py +599 -0
- package/src/a11y-assist/a11y_assist/from_cli_error.py +149 -0
- package/src/a11y-assist/a11y_assist/guard.py +444 -0
- package/src/a11y-assist/a11y_assist/ingest.py +407 -0
- package/src/a11y-assist/a11y_assist/methods.py +137 -0
- package/src/a11y-assist/a11y_assist/parse_raw.py +71 -0
- package/src/a11y-assist/a11y_assist/profiles/__init__.py +29 -0
- package/src/a11y-assist/a11y_assist/profiles/cognitive_load.py +245 -0
- package/src/a11y-assist/a11y_assist/profiles/cognitive_load_render.py +86 -0
- package/src/a11y-assist/a11y_assist/profiles/dyslexia.py +144 -0
- package/src/a11y-assist/a11y_assist/profiles/dyslexia_render.py +77 -0
- package/src/a11y-assist/a11y_assist/profiles/plain_language.py +119 -0
- package/src/a11y-assist/a11y_assist/profiles/plain_language_render.py +66 -0
- package/src/a11y-assist/a11y_assist/profiles/screen_reader.py +348 -0
- package/src/a11y-assist/a11y_assist/profiles/screen_reader_render.py +89 -0
- package/src/a11y-assist/a11y_assist/render.py +95 -0
- package/src/a11y-assist/a11y_assist/schemas/assist.request.schema.v0.1.json +52 -0
- package/src/a11y-assist/a11y_assist/schemas/assist.response.schema.v0.1.json +70 -0
- package/src/a11y-assist/a11y_assist/schemas/cli.error.schema.v0.1.json +78 -0
- package/src/a11y-assist/a11y_assist/storage.py +31 -0
- package/src/a11y-assist/pyproject.toml +60 -0
- package/src/a11y-assist/tests/__init__.py +1 -0
- package/src/a11y-assist/tests/fixtures/base_inputs/cli_error_high.json +18 -0
- package/src/a11y-assist/tests/fixtures/base_inputs/cli_error_medium.json +16 -0
- package/src/a11y-assist/tests/fixtures/base_inputs/raw_text_low.txt +3 -0
- package/src/a11y-assist/tests/fixtures/cli_error_good.json +9 -0
- package/src/a11y-assist/tests/fixtures/cli_error_missing_id.json +7 -0
- package/src/a11y-assist/tests/fixtures/cli_error_string_format.json +7 -0
- package/src/a11y-assist/tests/fixtures/expected/cognitive_load_high.txt +20 -0
- package/src/a11y-assist/tests/fixtures/expected/dyslexia_high.txt +20 -0
- package/src/a11y-assist/tests/fixtures/expected/lowvision_high.txt +18 -0
- package/src/a11y-assist/tests/fixtures/expected/plain_language_high.txt +14 -0
- package/src/a11y-assist/tests/fixtures/expected/screen_reader_high.txt +19 -0
- package/src/a11y-assist/tests/fixtures/golden_screen_reader_cli_error.txt +16 -0
- package/src/a11y-assist/tests/fixtures/golden_screen_reader_raw_no_id.txt +14 -0
- package/src/a11y-assist/tests/fixtures/golden_screen_reader_raw_with_id.txt +14 -0
- package/src/a11y-assist/tests/fixtures/raw_good.txt +11 -0
- package/src/a11y-assist/tests/fixtures/raw_no_id.txt +2 -0
- package/src/a11y-assist/tests/test_cognitive_load.py +469 -0
- package/src/a11y-assist/tests/test_dyslexia.py +337 -0
- package/src/a11y-assist/tests/test_explain.py +74 -0
- package/src/a11y-assist/tests/test_golden.py +127 -0
- package/src/a11y-assist/tests/test_guard.py +819 -0
- package/src/a11y-assist/tests/test_guard_integration.py +457 -0
- package/src/a11y-assist/tests/test_ingest.py +311 -0
- package/src/a11y-assist/tests/test_methods_metadata.py +236 -0
- package/src/a11y-assist/tests/test_plain_language.py +348 -0
- package/src/a11y-assist/tests/test_render.py +117 -0
- package/src/a11y-assist/tests/test_screen_reader.py +703 -0
- package/src/a11y-assist/tests/test_storage_last.py +61 -0
- package/src/a11y-assist/tests/test_triage.py +86 -0
- package/src/a11y-ci/.github/workflows/ci.yml +43 -0
- package/src/a11y-ci/.github/workflows/test.yml +30 -0
- package/src/a11y-ci/A11Y_CI_TEST_COVERAGE_REQUIREMENTS.md +94 -0
- package/src/a11y-ci/CODE_OF_CONDUCT.md +129 -0
- package/src/a11y-ci/CONTRIBUTING.md +142 -0
- package/src/a11y-ci/LICENSE +21 -0
- package/src/a11y-ci/README.md +105 -0
- package/src/a11y-ci/a11y_ci/__init__.py +3 -0
- package/src/a11y-ci/a11y_ci/allowlist.py +83 -0
- package/src/a11y-ci/a11y_ci/cli.py +145 -0
- package/src/a11y-ci/a11y_ci/gate.py +131 -0
- package/src/a11y-ci/a11y_ci/render.py +48 -0
- package/src/a11y-ci/a11y_ci/schemas/allowlist.schema.json +24 -0
- package/src/a11y-ci/a11y_ci/scorecard.py +99 -0
- package/src/a11y-ci/npm/package.json +35 -0
- package/src/a11y-ci/pyproject.toml +64 -0
- package/src/a11y-ci/tests/__init__.py +1 -0
- package/src/a11y-ci/tests/fixtures/allowlist_expired.json +10 -0
- package/src/a11y-ci/tests/fixtures/allowlist_ok.json +10 -0
- package/src/a11y-ci/tests/fixtures/baseline_ok.json +7 -0
- package/src/a11y-ci/tests/fixtures/current_fail.json +6 -0
- package/src/a11y-ci/tests/fixtures/current_ok.json +6 -0
- package/src/a11y-ci/tests/fixtures/current_regresses.json +7 -0
- package/src/a11y-ci/tests/test_gate.py +134 -0
- package/src/a11y-evidence-engine/.github/workflows/ci.yml +53 -0
- package/src/a11y-evidence-engine/CODE_OF_CONDUCT.md +129 -0
- package/src/a11y-evidence-engine/CONTRIBUTING.md +128 -0
- package/src/a11y-evidence-engine/LICENSE +21 -0
- package/src/a11y-evidence-engine/README.md +71 -0
- package/src/a11y-evidence-engine/bin/a11y-engine.js +11 -0
- package/src/a11y-evidence-engine/fixtures/bad/button-no-name.html +30 -0
- package/src/a11y-evidence-engine/fixtures/bad/img-missing-alt.html +19 -0
- package/src/a11y-evidence-engine/fixtures/bad/input-missing-label.html +26 -0
- package/src/a11y-evidence-engine/fixtures/bad/missing-lang.html +11 -0
- package/src/a11y-evidence-engine/fixtures/good/index.html +29 -0
- package/src/a11y-evidence-engine/package-lock.json +109 -0
- package/src/a11y-evidence-engine/package.json +45 -0
- package/src/a11y-evidence-engine/src/cli.js +74 -0
- package/src/a11y-evidence-engine/src/evidence/canonicalize.js +52 -0
- package/src/a11y-evidence-engine/src/evidence/json_pointer.js +34 -0
- package/src/a11y-evidence-engine/src/evidence/prov_emit.js +153 -0
- package/src/a11y-evidence-engine/src/fswalk.js +56 -0
- package/src/a11y-evidence-engine/src/html_parse.js +117 -0
- package/src/a11y-evidence-engine/src/ids.js +53 -0
- package/src/a11y-evidence-engine/src/rules/document_missing_lang.js +50 -0
- package/src/a11y-evidence-engine/src/rules/form_control_missing_label.js +105 -0
- package/src/a11y-evidence-engine/src/rules/img_missing_alt.js +77 -0
- package/src/a11y-evidence-engine/src/rules/index.js +37 -0
- package/src/a11y-evidence-engine/src/rules/interactive_missing_name.js +129 -0
- package/src/a11y-evidence-engine/src/scan.js +128 -0
- package/src/a11y-evidence-engine/test/scan.test.js +149 -0
- package/src/a11y-evidence-engine/test/vectors.test.js +200 -0
- package/src/a11y-lint/.github/workflows/ci.yml +46 -0
- package/src/a11y-lint/.github/workflows/test.yml +34 -0
- package/src/a11y-lint/CODE_OF_CONDUCT.md +129 -0
- package/src/a11y-lint/CONTRIBUTING.md +70 -0
- package/src/a11y-lint/GOVERNANCE.md +57 -0
- package/src/a11y-lint/LICENSE +21 -0
- package/src/a11y-lint/PRESS_RELEASE.md +50 -0
- package/src/a11y-lint/README.md +276 -0
- package/src/a11y-lint/RELEASE_NOTES.md +57 -0
- package/src/a11y-lint/RELEASING.md +57 -0
- package/src/a11y-lint/a11y_lint/__init__.py +64 -0
- package/src/a11y-lint/a11y_lint/cli.py +319 -0
- package/src/a11y-lint/a11y_lint/errors.py +252 -0
- package/src/a11y-lint/a11y_lint/render.py +293 -0
- package/src/a11y-lint/a11y_lint/report_md.py +289 -0
- package/src/a11y-lint/a11y_lint/scan_cli_text.py +434 -0
- package/src/a11y-lint/a11y_lint/schemas/cli.error.schema.v0.1.json +83 -0
- package/src/a11y-lint/a11y_lint/scorecard.py +244 -0
- package/src/a11y-lint/a11y_lint/validate.py +225 -0
- package/src/a11y-lint/pyproject.toml +75 -0
- package/src/a11y-lint/tests/__init__.py +1 -0
- package/src/a11y-lint/tests/test_cli.py +200 -0
- package/src/a11y-lint/tests/test_errors.py +188 -0
- package/src/a11y-lint/tests/test_render.py +202 -0
- package/src/a11y-lint/tests/test_report_md.py +188 -0
- package/src/a11y-lint/tests/test_scan_cli_text.py +290 -0
- package/src/a11y-lint/tests/test_scorecard.py +195 -0
- package/src/a11y-lint/tests/test_validate.py +257 -0
- package/src/a11y-mcp-tools/.github/workflows/ci.yml +53 -0
- package/src/a11y-mcp-tools/CODE_OF_CONDUCT.md +129 -0
- package/src/a11y-mcp-tools/CONTRIBUTING.md +136 -0
- package/src/a11y-mcp-tools/LICENSE +21 -0
- package/src/a11y-mcp-tools/PROV_METHODS_CATALOG.md +104 -0
- package/src/a11y-mcp-tools/README.md +168 -0
- package/src/a11y-mcp-tools/bin/cli.js +452 -0
- package/src/a11y-mcp-tools/bin/server.js +244 -0
- package/src/a11y-mcp-tools/fixtures/requests/a11y.diagnose.ok.json +27 -0
- package/src/a11y-mcp-tools/fixtures/requests/a11y.evidence.ok.json +25 -0
- package/src/a11y-mcp-tools/fixtures/responses/a11y.diagnose.ok.json +139 -0
- package/src/a11y-mcp-tools/fixtures/responses/a11y.diagnose.provenance_fail.json +13 -0
- package/src/a11y-mcp-tools/fixtures/responses/a11y.evidence.ok.json +88 -0
- package/src/a11y-mcp-tools/package-lock.json +189 -0
- package/src/a11y-mcp-tools/package.json +49 -0
- package/src/a11y-mcp-tools/src/envelope.js +197 -0
- package/src/a11y-mcp-tools/src/index.js +9 -0
- package/src/a11y-mcp-tools/src/schemas/artifact.js +85 -0
- package/src/a11y-mcp-tools/src/schemas/diagnosis.schema.v0.1.json +137 -0
- package/src/a11y-mcp-tools/src/schemas/envelope.schema.v0.1.json +108 -0
- package/src/a11y-mcp-tools/src/schemas/evidence.bundle.schema.v0.1.json +129 -0
- package/src/a11y-mcp-tools/src/schemas/evidence.js +97 -0
- package/src/a11y-mcp-tools/src/schemas/index.js +11 -0
- package/src/a11y-mcp-tools/src/schemas/provenance.js +140 -0
- package/src/a11y-mcp-tools/src/schemas/tools/a11y.diagnose.request.schema.v0.1.json +77 -0
- package/src/a11y-mcp-tools/src/schemas/tools/a11y.diagnose.response.schema.v0.1.json +50 -0
- package/src/a11y-mcp-tools/src/schemas/tools/a11y.evidence.request.schema.v0.1.json +120 -0
- package/src/a11y-mcp-tools/src/schemas/tools/a11y.evidence.response.schema.v0.1.json +50 -0
- package/src/a11y-mcp-tools/src/tools/diagnose.js +597 -0
- package/src/a11y-mcp-tools/src/tools/evidence.js +481 -0
- package/src/a11y-mcp-tools/src/tools/index.js +10 -0
- package/src/a11y-mcp-tools/test/contract.test.mjs +154 -0
- package/src/a11y-mcp-tools/test/diagnose.test.js +485 -0
- package/src/a11y-mcp-tools/test/evidence.test.js +183 -0
- package/src/a11y-mcp-tools/test/schema.test.js +327 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""Plain-language profile renderer.
|
|
2
|
+
|
|
3
|
+
Output format optimized for maximum clarity:
|
|
4
|
+
- Simple structure
|
|
5
|
+
- Explicit labels
|
|
6
|
+
- Numeric steps
|
|
7
|
+
- Short sections
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from ..render import AssistResult
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def render_plain_language(result: AssistResult) -> str:
|
|
16
|
+
"""Render AssistResult in plain-language format.
|
|
17
|
+
|
|
18
|
+
Format:
|
|
19
|
+
ASSIST (Plain Language)
|
|
20
|
+
ID: <ID or none>
|
|
21
|
+
Confidence: High | Medium | Low
|
|
22
|
+
|
|
23
|
+
What happened:
|
|
24
|
+
<one simple sentence>
|
|
25
|
+
|
|
26
|
+
What to do next:
|
|
27
|
+
<one sentence>
|
|
28
|
+
|
|
29
|
+
Steps:
|
|
30
|
+
1. <sentence>
|
|
31
|
+
2. <sentence>
|
|
32
|
+
...
|
|
33
|
+
|
|
34
|
+
Safe command:
|
|
35
|
+
<command>
|
|
36
|
+
"""
|
|
37
|
+
lines = []
|
|
38
|
+
|
|
39
|
+
# Header
|
|
40
|
+
lines.append("ASSIST (Plain Language)")
|
|
41
|
+
lines.append(f"ID: {result.anchored_id or 'none'}")
|
|
42
|
+
lines.append(f"Confidence: {result.confidence}")
|
|
43
|
+
lines.append("")
|
|
44
|
+
|
|
45
|
+
# What to do next (maps to safest_next_step)
|
|
46
|
+
lines.append("What to do next:")
|
|
47
|
+
lines.append(f" {result.safest_next_step}")
|
|
48
|
+
lines.append("")
|
|
49
|
+
|
|
50
|
+
# Steps - simple numeric list
|
|
51
|
+
if result.plan:
|
|
52
|
+
lines.append("Steps:")
|
|
53
|
+
for i, step in enumerate(result.plan, 1):
|
|
54
|
+
lines.append(f" {i}. {step}")
|
|
55
|
+
lines.append("")
|
|
56
|
+
|
|
57
|
+
# Safe command - only if confidence is not Low
|
|
58
|
+
if result.next_safe_commands and result.confidence != "Low":
|
|
59
|
+
lines.append("Safe command:")
|
|
60
|
+
lines.append(f" {result.next_safe_commands[0]}")
|
|
61
|
+
lines.append("")
|
|
62
|
+
|
|
63
|
+
# Notes are omitted in plain-language for simplicity
|
|
64
|
+
# (keeping output as clear as possible)
|
|
65
|
+
|
|
66
|
+
return "\n".join(lines)
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
"""Screen-reader profile transformation.
|
|
2
|
+
|
|
3
|
+
Transforms AssistResult for users consuming output via:
|
|
4
|
+
- Screen readers / TTS
|
|
5
|
+
- Braille displays
|
|
6
|
+
- Listen-first workflows
|
|
7
|
+
|
|
8
|
+
Invariants (non-negotiable):
|
|
9
|
+
1. No invented facts - only rephrases existing content
|
|
10
|
+
2. No invented commands - SAFE commands must be verbatim from input
|
|
11
|
+
3. SAFE-only remains absolute
|
|
12
|
+
4. Additive behavior - doesn't rewrite original output
|
|
13
|
+
5. Deterministic - no randomness, no network calls
|
|
14
|
+
|
|
15
|
+
Screen-reader-specific invariants:
|
|
16
|
+
6. No meaning in punctuation/formatting alone
|
|
17
|
+
7. No "visual navigation" references (see above, below, left, right, arrow)
|
|
18
|
+
8. No parentheticals as meaning carriers
|
|
19
|
+
9. Avoid dense inline abbreviations unless expanded
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import re
|
|
25
|
+
from typing import List, Optional
|
|
26
|
+
|
|
27
|
+
from ..render import AssistResult, Confidence
|
|
28
|
+
|
|
29
|
+
# Max step length (audio tolerates longer than visual)
|
|
30
|
+
MAX_STEP_LENGTH = 110
|
|
31
|
+
|
|
32
|
+
# Max note length
|
|
33
|
+
MAX_NOTE_LENGTH = 120
|
|
34
|
+
|
|
35
|
+
# Max steps by confidence
|
|
36
|
+
MAX_STEPS_DEFAULT = 5
|
|
37
|
+
MAX_STEPS_LOW = 3
|
|
38
|
+
|
|
39
|
+
# Boilerplate prefixes to strip
|
|
40
|
+
BOILERPLATE_PREFIXES = re.compile(
|
|
41
|
+
r"^(re-?run:\s*|run:\s*|try:\s*|next:\s*|\$\s*|>\s*)", re.IGNORECASE
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# Parenthetical patterns
|
|
45
|
+
PARENTHETICAL_RE = re.compile(r"\s*[\(\[][^\)\]]*[\)\]]\s*")
|
|
46
|
+
|
|
47
|
+
# Visual navigation phrases to remove
|
|
48
|
+
VISUAL_NAV_PHRASES = re.compile(
|
|
49
|
+
r"\b(see\s+)?(above|below|left|right|arrow)\b", re.IGNORECASE
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# Abbreviation expansions (small, fixed set for determinism)
|
|
53
|
+
ABBREVIATIONS = [
|
|
54
|
+
(re.compile(r"\bCLI\b"), "command line"),
|
|
55
|
+
(re.compile(r"\bID\b"), "I D"),
|
|
56
|
+
(re.compile(r"\bURL\b"), "U R L"),
|
|
57
|
+
(re.compile(r"\bJSON\b"), "J S O N"),
|
|
58
|
+
(re.compile(r"\benv\b"), "environment"),
|
|
59
|
+
(re.compile(r"\bSFTP\b"), "S F T P"),
|
|
60
|
+
(re.compile(r"\bSSH\b"), "S S H"),
|
|
61
|
+
(re.compile(r"\bAPI\b"), "A P I"),
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
# Symbol replacements for better TTS
|
|
65
|
+
SYMBOL_REPLACEMENTS = [
|
|
66
|
+
("->", " to "),
|
|
67
|
+
("=>", " to "),
|
|
68
|
+
(" & ", " and "),
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _strip_boilerplate(s: str) -> str:
|
|
73
|
+
"""Strip boilerplate prefixes from a string."""
|
|
74
|
+
return BOILERPLATE_PREFIXES.sub("", s).strip()
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _remove_parentheticals(s: str) -> str:
|
|
78
|
+
"""Remove parenthetical content (...) and [...] from string."""
|
|
79
|
+
result = PARENTHETICAL_RE.sub(" ", s).strip()
|
|
80
|
+
# If removal empties the string, revert
|
|
81
|
+
if not result:
|
|
82
|
+
return s
|
|
83
|
+
# Clean up double spaces
|
|
84
|
+
return re.sub(r"\s+", " ", result)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _remove_visual_references(s: str) -> str:
|
|
88
|
+
"""Remove visual navigation references."""
|
|
89
|
+
result = VISUAL_NAV_PHRASES.sub("", s)
|
|
90
|
+
# Clean up double spaces
|
|
91
|
+
return re.sub(r"\s+", " ", result).strip()
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _expand_abbreviations(s: str) -> str:
|
|
95
|
+
"""Expand a small, fixed set of abbreviations for TTS."""
|
|
96
|
+
for pattern, expansion in ABBREVIATIONS:
|
|
97
|
+
s = pattern.sub(expansion, s)
|
|
98
|
+
return s
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _replace_symbols(s: str) -> str:
|
|
102
|
+
"""Replace symbols that screen readers read awkwardly."""
|
|
103
|
+
for old, new in SYMBOL_REPLACEMENTS:
|
|
104
|
+
s = s.replace(old, new)
|
|
105
|
+
# Clean up double spaces
|
|
106
|
+
return re.sub(r"\s+", " ", s).strip()
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _one_sentence(s: str) -> str:
|
|
110
|
+
"""Keep only the first sentence/clause."""
|
|
111
|
+
# Split on semicolon first
|
|
112
|
+
if ";" in s:
|
|
113
|
+
s = s.split(";")[0].strip()
|
|
114
|
+
|
|
115
|
+
# Split on comma with multiple clauses (be conservative)
|
|
116
|
+
# Only split if comma appears to separate independent clauses
|
|
117
|
+
# For now, keep simple: first sentence only
|
|
118
|
+
sentences = s.split(". ")
|
|
119
|
+
if sentences:
|
|
120
|
+
first = sentences[0].strip()
|
|
121
|
+
return first
|
|
122
|
+
return s
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _ensure_period(s: str) -> str:
|
|
126
|
+
"""Ensure string ends with a period."""
|
|
127
|
+
s = s.strip()
|
|
128
|
+
if s and not s.endswith("."):
|
|
129
|
+
s += "."
|
|
130
|
+
return s
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _cap_length(s: str, max_len: int = MAX_STEP_LENGTH) -> str:
|
|
134
|
+
"""Cap string length, truncating with ellipsis if needed."""
|
|
135
|
+
if len(s) <= max_len:
|
|
136
|
+
return s
|
|
137
|
+
return s[: max_len - 1] + "…"
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def normalize_step(step: str) -> str:
|
|
141
|
+
"""Normalize a single step for screen-reader profile.
|
|
142
|
+
|
|
143
|
+
Order of operations:
|
|
144
|
+
1. Strip boilerplate prefixes
|
|
145
|
+
2. Remove parentheticals
|
|
146
|
+
3. Remove visual navigation references
|
|
147
|
+
4. Expand abbreviations
|
|
148
|
+
5. Replace awkward symbols
|
|
149
|
+
6. Keep one sentence
|
|
150
|
+
7. Ensure ends with period
|
|
151
|
+
8. Cap length
|
|
152
|
+
"""
|
|
153
|
+
s = step.strip()
|
|
154
|
+
if not s:
|
|
155
|
+
return s
|
|
156
|
+
|
|
157
|
+
# 1. Strip boilerplate
|
|
158
|
+
s = _strip_boilerplate(s)
|
|
159
|
+
|
|
160
|
+
# 2. Remove parentheticals
|
|
161
|
+
s = _remove_parentheticals(s)
|
|
162
|
+
|
|
163
|
+
# 3. Remove visual navigation references
|
|
164
|
+
s = _remove_visual_references(s)
|
|
165
|
+
|
|
166
|
+
# 4. Expand abbreviations
|
|
167
|
+
s = _expand_abbreviations(s)
|
|
168
|
+
|
|
169
|
+
# 5. Replace symbols
|
|
170
|
+
s = _replace_symbols(s)
|
|
171
|
+
|
|
172
|
+
# 6. One sentence
|
|
173
|
+
s = _one_sentence(s)
|
|
174
|
+
|
|
175
|
+
# 7. Ensure period
|
|
176
|
+
s = _ensure_period(s)
|
|
177
|
+
|
|
178
|
+
# 8. Cap length
|
|
179
|
+
s = _cap_length(s)
|
|
180
|
+
|
|
181
|
+
return s
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def normalize_safest_step(s: str) -> str:
|
|
185
|
+
"""Normalize safest_next_step for screen-reader profile.
|
|
186
|
+
|
|
187
|
+
- One sentence max
|
|
188
|
+
- No parentheticals
|
|
189
|
+
- Ends with period
|
|
190
|
+
"""
|
|
191
|
+
if not s:
|
|
192
|
+
return "Follow the steps in order."
|
|
193
|
+
|
|
194
|
+
# Remove parentheticals
|
|
195
|
+
s = _remove_parentheticals(s)
|
|
196
|
+
|
|
197
|
+
# Remove visual references
|
|
198
|
+
s = _remove_visual_references(s)
|
|
199
|
+
|
|
200
|
+
# Expand abbreviations
|
|
201
|
+
s = _expand_abbreviations(s)
|
|
202
|
+
|
|
203
|
+
# Replace symbols
|
|
204
|
+
s = _replace_symbols(s)
|
|
205
|
+
|
|
206
|
+
# One sentence
|
|
207
|
+
s = _one_sentence(s)
|
|
208
|
+
|
|
209
|
+
# Ensure period
|
|
210
|
+
s = _ensure_period(s)
|
|
211
|
+
|
|
212
|
+
return _cap_length(s, MAX_STEP_LENGTH)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def generate_summary(result: AssistResult) -> str:
|
|
216
|
+
"""Generate a one-sentence summary from the result.
|
|
217
|
+
|
|
218
|
+
Uses available information without inventing facts.
|
|
219
|
+
"""
|
|
220
|
+
# Try to derive from safest_next_step or first plan item
|
|
221
|
+
if result.notes:
|
|
222
|
+
# Look for "Original title:" note
|
|
223
|
+
for note in result.notes:
|
|
224
|
+
if note.lower().startswith("original title:"):
|
|
225
|
+
title = note.split(":", 1)[1].strip()
|
|
226
|
+
if title:
|
|
227
|
+
return _ensure_period(_cap_length(title, 80))
|
|
228
|
+
|
|
229
|
+
# Fall back to a generic summary based on confidence
|
|
230
|
+
if result.confidence == "High":
|
|
231
|
+
return "A structured error was detected."
|
|
232
|
+
elif result.confidence == "Medium":
|
|
233
|
+
return "An error was detected with partial information."
|
|
234
|
+
else:
|
|
235
|
+
return "The input did not include a stable error identifier."
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def reduce_plan(plan: List[str], confidence: Confidence) -> List[str]:
|
|
239
|
+
"""Reduce plan to appropriate number of normalized steps.
|
|
240
|
+
|
|
241
|
+
- High/Medium confidence: max 5 steps
|
|
242
|
+
- Low confidence: max 3 steps (reduce listening time)
|
|
243
|
+
"""
|
|
244
|
+
if not plan:
|
|
245
|
+
return ["Follow the tool's instructions."]
|
|
246
|
+
|
|
247
|
+
max_steps = MAX_STEPS_LOW if confidence == "Low" else MAX_STEPS_DEFAULT
|
|
248
|
+
|
|
249
|
+
normalized = [normalize_step(s) for s in plan if s.strip()]
|
|
250
|
+
# Filter out empty results
|
|
251
|
+
normalized = [s for s in normalized if s]
|
|
252
|
+
|
|
253
|
+
if not normalized:
|
|
254
|
+
return ["Follow the tool's instructions."]
|
|
255
|
+
|
|
256
|
+
return normalized[:max_steps]
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def select_safe_command(
|
|
260
|
+
commands: List[str], confidence: Confidence
|
|
261
|
+
) -> Optional[str]:
|
|
262
|
+
"""Select at most one SAFE command for screen-reader profile.
|
|
263
|
+
|
|
264
|
+
Rules:
|
|
265
|
+
- Only include if confidence is High or Medium
|
|
266
|
+
- Return first command only
|
|
267
|
+
- No command synthesis
|
|
268
|
+
- Never prefix with $ (screen readers read it as "dollar")
|
|
269
|
+
"""
|
|
270
|
+
if confidence == "Low":
|
|
271
|
+
return None
|
|
272
|
+
|
|
273
|
+
if not commands:
|
|
274
|
+
return None
|
|
275
|
+
|
|
276
|
+
cmd = commands[0]
|
|
277
|
+
# Strip leading $ if present (verbatim but remove the symbol)
|
|
278
|
+
if cmd.startswith("$ "):
|
|
279
|
+
cmd = cmd[2:]
|
|
280
|
+
elif cmd.startswith("$"):
|
|
281
|
+
cmd = cmd[1:]
|
|
282
|
+
|
|
283
|
+
return cmd
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def reduce_notes(notes: List[str], max_notes: int = 3) -> List[str]:
|
|
287
|
+
"""Reduce notes for screen-reader profile.
|
|
288
|
+
|
|
289
|
+
- Max 3 notes
|
|
290
|
+
- Each note is one sentence max
|
|
291
|
+
- Remove parentheticals
|
|
292
|
+
- Cap each at 120 chars
|
|
293
|
+
"""
|
|
294
|
+
if not notes:
|
|
295
|
+
return []
|
|
296
|
+
|
|
297
|
+
reduced = []
|
|
298
|
+
for note in notes[:max_notes]:
|
|
299
|
+
n = _remove_parentheticals(note)
|
|
300
|
+
n = _remove_visual_references(n)
|
|
301
|
+
n = _expand_abbreviations(n)
|
|
302
|
+
n = _replace_symbols(n)
|
|
303
|
+
n = _one_sentence(n)
|
|
304
|
+
n = _ensure_period(n)
|
|
305
|
+
n = _cap_length(n, MAX_NOTE_LENGTH)
|
|
306
|
+
if n and n != ".":
|
|
307
|
+
reduced.append(n)
|
|
308
|
+
|
|
309
|
+
return reduced
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def apply_screen_reader(result: AssistResult) -> AssistResult:
|
|
313
|
+
"""Transform AssistResult for screen-reader profile.
|
|
314
|
+
|
|
315
|
+
This transformation:
|
|
316
|
+
1. Reduces plan steps (5 for High/Medium, 3 for Low)
|
|
317
|
+
2. Normalizes step language for TTS
|
|
318
|
+
3. Expands abbreviations
|
|
319
|
+
4. Removes parentheticals and visual references
|
|
320
|
+
5. Selects at most 1 SAFE command (none if Low confidence)
|
|
321
|
+
6. Reduces notes to 3 max
|
|
322
|
+
|
|
323
|
+
Invariants enforced:
|
|
324
|
+
- No invented facts (only rephrases existing content)
|
|
325
|
+
- No invented commands (SAFE commands verbatim from input)
|
|
326
|
+
- Deterministic output
|
|
327
|
+
"""
|
|
328
|
+
# Reduce and normalize plan
|
|
329
|
+
reduced_plan = reduce_plan(result.plan, result.confidence)
|
|
330
|
+
|
|
331
|
+
# Normalize safest next step
|
|
332
|
+
normalized_safest = normalize_safest_step(result.safest_next_step)
|
|
333
|
+
|
|
334
|
+
# Select single SAFE command (or None)
|
|
335
|
+
safe_cmd = select_safe_command(result.next_safe_commands, result.confidence)
|
|
336
|
+
safe_commands = [safe_cmd] if safe_cmd else []
|
|
337
|
+
|
|
338
|
+
# Reduce notes
|
|
339
|
+
reduced_notes = reduce_notes(result.notes)
|
|
340
|
+
|
|
341
|
+
return AssistResult(
|
|
342
|
+
anchored_id=result.anchored_id,
|
|
343
|
+
confidence=result.confidence,
|
|
344
|
+
safest_next_step=normalized_safest,
|
|
345
|
+
plan=reduced_plan,
|
|
346
|
+
next_safe_commands=safe_commands,
|
|
347
|
+
notes=reduced_notes,
|
|
348
|
+
)
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""Screen-reader profile renderer.
|
|
2
|
+
|
|
3
|
+
Renders AssistResult with screen-reader specific formatting:
|
|
4
|
+
- Spoken-friendly headers (no visual punctuation as meaning carriers)
|
|
5
|
+
- Fixed section order for predictability
|
|
6
|
+
- Step N: labels instead of numbers alone
|
|
7
|
+
- No parentheticals in output
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from typing import List
|
|
13
|
+
|
|
14
|
+
from ..render import AssistResult
|
|
15
|
+
from .screen_reader import generate_summary
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def render_screen_reader(result: AssistResult) -> str:
|
|
19
|
+
"""Render an AssistResult in screen-reader format.
|
|
20
|
+
|
|
21
|
+
Format:
|
|
22
|
+
ASSIST. Profile: Screen reader.
|
|
23
|
+
Anchored I D: <id or none>.
|
|
24
|
+
Confidence: High|Medium|Low.
|
|
25
|
+
|
|
26
|
+
Summary: <very short>.
|
|
27
|
+
|
|
28
|
+
Safest next step: <one sentence>.
|
|
29
|
+
|
|
30
|
+
Steps:
|
|
31
|
+
Step 1: <step>.
|
|
32
|
+
Step 2: <step>.
|
|
33
|
+
...
|
|
34
|
+
|
|
35
|
+
Next safe command:
|
|
36
|
+
<command>
|
|
37
|
+
|
|
38
|
+
Note: <note>.
|
|
39
|
+
OR
|
|
40
|
+
Notes:
|
|
41
|
+
<note>.
|
|
42
|
+
<note>.
|
|
43
|
+
"""
|
|
44
|
+
lines: List[str] = []
|
|
45
|
+
|
|
46
|
+
# Header (spoken-friendly)
|
|
47
|
+
lines.append("ASSIST. Profile: Screen reader.")
|
|
48
|
+
|
|
49
|
+
# Anchored ID (spelled out for TTS)
|
|
50
|
+
if result.anchored_id:
|
|
51
|
+
lines.append(f"Anchored I D: {result.anchored_id}.")
|
|
52
|
+
else:
|
|
53
|
+
lines.append("Anchored I D: none.")
|
|
54
|
+
|
|
55
|
+
lines.append(f"Confidence: {result.confidence}.")
|
|
56
|
+
lines.append("")
|
|
57
|
+
|
|
58
|
+
# Summary (one sentence)
|
|
59
|
+
summary = generate_summary(result)
|
|
60
|
+
lines.append(f"Summary: {summary}")
|
|
61
|
+
lines.append("")
|
|
62
|
+
|
|
63
|
+
# Safest next step
|
|
64
|
+
lines.append(f"Safest next step: {result.safest_next_step}")
|
|
65
|
+
lines.append("")
|
|
66
|
+
|
|
67
|
+
# Steps with "Step N:" labels
|
|
68
|
+
lines.append("Steps:")
|
|
69
|
+
for i, step in enumerate(result.plan, start=1):
|
|
70
|
+
lines.append(f"Step {i}: {step}")
|
|
71
|
+
|
|
72
|
+
# Next safe command (only if present)
|
|
73
|
+
if result.next_safe_commands:
|
|
74
|
+
lines.append("")
|
|
75
|
+
lines.append("Next safe command:")
|
|
76
|
+
# Command alone on its own line, no $ prefix
|
|
77
|
+
lines.append(result.next_safe_commands[0])
|
|
78
|
+
|
|
79
|
+
# Notes
|
|
80
|
+
if result.notes:
|
|
81
|
+
lines.append("")
|
|
82
|
+
if len(result.notes) == 1:
|
|
83
|
+
lines.append(f"Note: {result.notes[0]}")
|
|
84
|
+
else:
|
|
85
|
+
lines.append("Notes:")
|
|
86
|
+
for note in result.notes:
|
|
87
|
+
lines.append(note)
|
|
88
|
+
|
|
89
|
+
return "\n".join(lines) + "\n"
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""Low-vision assist block rendering.
|
|
2
|
+
|
|
3
|
+
Clear labels, spacing, short lines.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from dataclasses import dataclass, field
|
|
9
|
+
from typing import List, Literal, Optional, Tuple
|
|
10
|
+
|
|
11
|
+
Confidence = Literal["High", "Medium", "Low"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True)
|
|
15
|
+
class Evidence:
|
|
16
|
+
"""Source anchor for audit traceability.
|
|
17
|
+
|
|
18
|
+
Maps an output field back to its input source.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
field: str # e.g., "safest_next_step", "plan[0]"
|
|
22
|
+
source: str # e.g., "cli.error.fix[1]", "raw_text:Fix:2"
|
|
23
|
+
note: Optional[str] = None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass(frozen=True)
|
|
27
|
+
class AssistResult:
|
|
28
|
+
"""Structured assist result with optional audit metadata."""
|
|
29
|
+
|
|
30
|
+
anchored_id: Optional[str]
|
|
31
|
+
confidence: Confidence
|
|
32
|
+
safest_next_step: str
|
|
33
|
+
plan: List[str]
|
|
34
|
+
next_safe_commands: List[str] # SAFE-only in v0.1
|
|
35
|
+
notes: List[str]
|
|
36
|
+
|
|
37
|
+
# Optional audit metadata (does not affect rendering)
|
|
38
|
+
methods_applied: Tuple[str, ...] = field(default_factory=tuple)
|
|
39
|
+
evidence: Tuple[Evidence, ...] = field(default_factory=tuple)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def render_assist(result: AssistResult) -> str:
|
|
43
|
+
"""Render an AssistResult to low-vision-friendly text.
|
|
44
|
+
|
|
45
|
+
Format:
|
|
46
|
+
ASSIST (Low Vision):
|
|
47
|
+
- Anchored to: ID or (none)
|
|
48
|
+
- Confidence: High/Medium/Low
|
|
49
|
+
|
|
50
|
+
Safest next step:
|
|
51
|
+
<step>
|
|
52
|
+
|
|
53
|
+
Plan:
|
|
54
|
+
1) step
|
|
55
|
+
2) step
|
|
56
|
+
|
|
57
|
+
Next (SAFE):
|
|
58
|
+
<command>
|
|
59
|
+
|
|
60
|
+
Notes:
|
|
61
|
+
- note
|
|
62
|
+
"""
|
|
63
|
+
lines: List[str] = []
|
|
64
|
+
lines.append("ASSIST (Low Vision):")
|
|
65
|
+
|
|
66
|
+
if result.anchored_id:
|
|
67
|
+
lines.append(f"- Anchored to: {result.anchored_id}")
|
|
68
|
+
else:
|
|
69
|
+
lines.append("- Anchored to: (none)")
|
|
70
|
+
|
|
71
|
+
lines.append(f"- Confidence: {result.confidence}")
|
|
72
|
+
lines.append("")
|
|
73
|
+
lines.append("Safest next step:")
|
|
74
|
+
lines.append(f" {result.safest_next_step}")
|
|
75
|
+
lines.append("")
|
|
76
|
+
|
|
77
|
+
lines.append("Plan:")
|
|
78
|
+
for i, step in enumerate(result.plan[:5], start=1):
|
|
79
|
+
lines.append(f" {i}) {step}")
|
|
80
|
+
if len(result.plan) > 5:
|
|
81
|
+
lines.append(" ...")
|
|
82
|
+
|
|
83
|
+
if result.next_safe_commands:
|
|
84
|
+
lines.append("")
|
|
85
|
+
lines.append("Next (SAFE):")
|
|
86
|
+
for cmd in result.next_safe_commands[:3]:
|
|
87
|
+
lines.append(f" {cmd}")
|
|
88
|
+
|
|
89
|
+
if result.notes:
|
|
90
|
+
lines.append("")
|
|
91
|
+
lines.append("Notes:")
|
|
92
|
+
for n in result.notes[:5]:
|
|
93
|
+
lines.append(f" - {n}")
|
|
94
|
+
|
|
95
|
+
return "\n".join(lines) + "\n"
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://a11y-assist.dev/schemas/assist.request.schema.v0.1.json",
|
|
4
|
+
"title": "assist.request.v0.1",
|
|
5
|
+
"description": "Request schema for a11y-assist",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["profile", "input"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"profile": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"enum": ["lowvision"],
|
|
12
|
+
"description": "Accessibility profile to use"
|
|
13
|
+
},
|
|
14
|
+
"input": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"required": ["kind"],
|
|
17
|
+
"properties": {
|
|
18
|
+
"kind": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"enum": ["cli_error_json", "raw_text", "last_log"],
|
|
21
|
+
"description": "Type of input"
|
|
22
|
+
},
|
|
23
|
+
"path": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"description": "Path to input file"
|
|
26
|
+
},
|
|
27
|
+
"text": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"description": "Raw text input"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"additionalProperties": false
|
|
33
|
+
},
|
|
34
|
+
"preferences": {
|
|
35
|
+
"type": "object",
|
|
36
|
+
"properties": {
|
|
37
|
+
"max_steps": {
|
|
38
|
+
"type": "integer",
|
|
39
|
+
"minimum": 1,
|
|
40
|
+
"maximum": 10,
|
|
41
|
+
"description": "Maximum number of plan steps to return"
|
|
42
|
+
},
|
|
43
|
+
"show_next_command": {
|
|
44
|
+
"type": "boolean",
|
|
45
|
+
"description": "Whether to show suggested safe commands"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"additionalProperties": false
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"additionalProperties": false
|
|
52
|
+
}
|