@gobing-ai/knowledge-kit 0.0.9 → 0.0.10

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.
@@ -0,0 +1,185 @@
1
+ ---
2
+ name: audio-authoring
3
+ description: >-
4
+ Use the audio-authoring skill to author spoken-audio scripts from a brief —
5
+ "create an audio script", "write a podcast script", "generate a briefing",
6
+ "outline options for audio", "author a VoiceScript", "revise the script".
7
+ Runs briefing → outline → script with explicit operator gates; solo mode
8
+ ships first, dialogue/interview/narration are named extension points.
9
+ ---
10
+
11
+ # audio-authoring — spoken-audio authoring (create | briefing | outline | script)
12
+
13
+ ## Purpose
14
+
15
+ Turn a Markdown brief into an **approved VoiceScript** for spoken audio in a small
16
+ file-backed workspace. One fat skill with four operations — `create`, `briefing`,
17
+ `outline`, `script` — sharing one artifact contract, one VoiceScript contract, one
18
+ spoken-budget rule, resume behavior, and recovery guidance. This is the authoring
19
+ layer extracted from `kk-solo-podcast`; synthesis (TTS) and deterministic formats
20
+ are deliberately **out of scope**.
21
+
22
+ ## When to use
23
+
24
+ - A user asks to author spoken-audio content from a brief or topic ("create a podcast
25
+ script about X", "write the briefing for a 10-minute episode").
26
+ - A workflow `agent.run` step needs one authoring stage independently (briefing only,
27
+ outline options only, script from an approved outline).
28
+ - An operator resumes a half-finished audio workspace and expects existing approved
29
+ artifacts to be reused, not overwritten.
30
+
31
+ Do **not** use this skill for: deterministic broadcast-news scripting (that is the
32
+ `kk:dailynews-gen` generator plugin), text-to-speech synthesis itself (that is
33
+ `kk:voice-gen` — this skill's output is its input), or multi-speaker authoring
34
+ beyond the extension-point notes below.
35
+
36
+ ## Invocation contract
37
+
38
+ `$ARGUMENTS` (or the Skill call args) parse as:
39
+
40
+ ```
41
+ [operation] [--mode solo] --dir <work_dir> [--duration <min>] [--language <code>] [--profile <voice>] [--outline a|b|c] [--revise <feedback>] [--force]
42
+ ```
43
+
44
+ | Token | Meaning | Default |
45
+ | --- | --- | --- |
46
+ | `operation` | `create` (default) \| `briefing` \| `outline` \| `script` | `create` |
47
+ | `--mode <name>` | authoring mode | `solo` (only implemented mode; others fail loud) |
48
+ | `--dir <work_dir>` | workspace directory | required — an empty dir fails loud |
49
+ | `--duration <min>` | target spoken duration in minutes | `8` |
50
+ | `--language <code>` | spoken language code (enum below) | `en` |
51
+ | `--profile <voice>` | voice profile for the wrap step — **not** written into the VoiceScript | none |
52
+ | `--outline <a\|b\|c>` | explicit outline selection | operator must select when options are shown |
53
+ | `--revise <feedback>` | revision feedback for the script review gate | none (approve path) |
54
+ | `--force` | explicit operator approval to replace an existing artifact | off — never overwrite without it |
55
+
56
+ Operations are case-insensitive. An unknown operation fails loud and lists the four
57
+ valid operations. Flags may appear in any order (topic convention).
58
+
59
+ ## Artifact contract
60
+
61
+ All paths are relative to the workspace `--dir`. Every operation uses these exact
62
+ paths — the contract is the same whether the operation runs inside `create` or
63
+ directly.
64
+
65
+ | Artifact | Path | Written by |
66
+ | --- | --- | --- |
67
+ | Brief (input) | `brief.md` | supplied before invocation — topic phrase or Markdown brief |
68
+ | Briefing | `1-briefing/briefing.md` | `briefing` — thesis, takeaways, audience, duration, tone |
69
+ | Outline options | `2-outline/outline-option-a.md`, `outline-option-b.md`, `outline-option-c.md` | `outline` — always two or three (a and b required; c optional) |
70
+ | Approved outline | `2-outline/outline-approved.md` | `outline` — after explicit operator selection |
71
+ | VoiceScript | `3-script/voicescript.yaml` | `script` — from the approved outline only |
72
+
73
+ Each operation creates the directory it writes into (`1-briefing/`, `2-outline/`,
74
+ `3-script/`) when absent. No other files are created — no metadata, no JSON
75
+ manifests, no templates, no placeholders.
76
+
77
+ ## Modes
78
+
79
+ - **solo** (default; only implemented mode) — one voice, no `speakers` map, no
80
+ per-segment `profile` (the `--profile` value lands in the Doc[] wrap performed by
81
+ the workflow, never in the VoiceScript).
82
+ - **dialogue** (extension point) — two or more named speakers via the `speakers` map
83
+ and per-segment `speaker`; turns alternate, distinct voices.
84
+ - **interview** (extension point) — host + guest via `speakers`; host drives
85
+ questions, guest answers at length.
86
+ - **narration** (extension point) — single voice over long-form material; like solo
87
+ but paces for continuous narration rather than episode structure.
88
+
89
+ Requesting an unimplemented mode fails loud naming the mode and stating that only
90
+ `solo` is implemented. No multi-speaker authoring guidance beyond these notes.
91
+
92
+ ## Operations
93
+
94
+ ### create (default)
95
+
96
+ Sequence: `briefing` → `outline` (selection gate) → `script` (review gate), resuming
97
+ from any existing approved artifact:
98
+
99
+ 1. **Resolve the brief** — require `brief.md` under `--dir`; run the `briefing`
100
+ semantics.
101
+ 2. **Outline** — if `2-outline/outline-approved.md` is missing, run the `outline`
102
+ semantics (write options, selection gate). If it exists, reuse it — do not
103
+ regenerate.
104
+ 3. **Script** — if `3-script/voicescript.yaml` is missing, run the `script` semantics
105
+ (write + review gate). If it exists and is approved, report it as final — do not
106
+ rewrite.
107
+ 4. **Report** the final artifact paths and stop. Never re-run a completed step; never
108
+ overwrite an existing approved artifact without `--force`.
109
+
110
+ ### briefing
111
+
112
+ 1. **Prerequisite** (fail loud): `brief.md` missing → stop with recovery ("supply a
113
+ brief at `<dir>/brief.md` first"). `1-briefing/briefing.md` exists without
114
+ `--force` → stop before replacing.
115
+ 2. **Read** `brief.md` and write `1-briefing/briefing.md`: core thesis, key listener
116
+ takeaways, audience profile, target spoken duration (`--duration` minutes), tone,
117
+ and what material from the brief to emphasize or cut.
118
+
119
+ ### outline
120
+
121
+ 1. **Prerequisite** (fail loud): `1-briefing/briefing.md` missing → stop with
122
+ recovery ("run `briefing` or `create` first").
123
+ 2. **Resume**: `2-outline/outline-approved.md` exists → reuse it; without `--force`,
124
+ stop before replacing.
125
+ 3. **Write options** — read the briefing and write two or three genuinely distinct
126
+ outline options to `2-outline/outline-option-{a,b,c}.md` (a and b required; c
127
+ optional). Each option targets the total spoken duration from `--duration`.
128
+ 4. **Selection gate**: present the options with their paths and **wait for explicit
129
+ operator selection** — `--outline <a|b|c>` or an interactive answer. Do not
130
+ proceed without it. Copy the selected option **verbatim** to
131
+ `2-outline/outline-approved.md`.
132
+
133
+ ### script
134
+
135
+ 1. **Prerequisite** (fail loud): `2-outline/outline-approved.md` missing → stop with
136
+ recovery ("run `outline` or `create` first — never script before outline
137
+ approval").
138
+ 2. **Resume**: `3-script/voicescript.yaml` exists → without `--force` or `--revise`,
139
+ stop before replacing ("script exists at `<path>`; to revise pass `--revise
140
+ <feedback>`, to replace pass `--force`").
141
+ 3. **Write** `3-script/voicescript.yaml` from the approved outline only, obeying the
142
+ VoiceScript contract and the spoken-budget rule below. Solo mode shape: one
143
+ speaker, **no** `speakers` map, per-segment `profile` omitted. Emit only valid
144
+ YAML — no markdown fences, no repo or docs paths in the file body.
145
+ 4. **Review gate**: present the script; offer **approve** or **revision**. Bounded
146
+ revision: at most **3 revision rounds**; each round takes `--revise <feedback>`,
147
+ rewrites the script from the approved outline plus the feedback, and re-presents
148
+ it. After 3 rounds, stop and require an explicit operator decision — never loop
149
+ past the bound.
150
+ 5. **Executable check**: when the `validate-voicescript.ts` checker is discoverable
151
+ (`KK_WORKFLOWS_DIR` or `$HOME/.config/kk/workflows/`), run it against the written
152
+ file; it is the sole executable authority — the embedded contract below is the
153
+ authoring-time distillation of it.
154
+
155
+ ## VoiceScript contract
156
+
157
+ The authoring template lives at **`templates/voicescript.solo.yaml`** (relative to
158
+ this skill file) — read it first when authoring `3-script/voicescript.yaml`; it is a
159
+ valid-YAML skeleton with per-field constraint comments. The executable authority is
160
+ `plugins/kk/workflows/validate-voicescript.ts` (canonical source
161
+ `plugins/generations/voice-gen/src/voicescript.ts`); the template is its
162
+ authoring-time distillation. No other fields are valid authoring targets — do not
163
+ invent fields (no `default_profile`, no required `title`).
164
+
165
+ Field summary (the template carries the same information as inline comments):
166
+
167
+ | Field | Where | Constraint |
168
+ | --- | --- | --- |
169
+ | `language` | root | 23-language enum (see template) |
170
+ | `default_engine` | root | engine enum (7 engines, see template) |
171
+ | `speakers` | root | multi-speaker modes only; each entry requires `profile`; omit in solo |
172
+ | `segments` | root | required, non-empty |
173
+ | `text` | segment | required, 1..50000 chars |
174
+ | `instruct` | speaker/segment | <= 500 chars |
175
+ | `gap_ms` | segment | >= 0 |
176
+ | `max_chunk_chars` | segment | 100..5000 |
177
+ | `crossfade_ms` | segment | 0..500 |
178
+ | `speaker` | segment | must name a key of the `speakers` map |
179
+
180
+ ## Spoken-budget rule
181
+
182
+ Target spoken volume derives from `--duration` and `--language`: for `zh`, `ja`, or
183
+ `ko`, target **characters = duration × 220**; for every other language, target
184
+ **words = duration × 150**. Land within **±20%** of the target. Apply the rule when
185
+ outlining (each option) and when scripting (total across segments).
@@ -0,0 +1,25 @@
1
+ # Solo-podcast VoiceScript starter template.
2
+ # Fill the placeholders; delete comments before authoring is considered final.
3
+ # Executable contract: validate-voicescript.ts (canonical: voice-gen/src/voicescript.ts).
4
+ # No other fields are valid — do not invent fields (no `default_profile`, no `title`).
5
+
6
+ language: en # zh|en|ja|ko|de|fr|ru|pt|es|it|he|ar|da|el|fi|hi|ms|nl|no|pl|sv|sw|tr
7
+ # default_engine: qwen # optional; qwen|qwen_custom_voice|luxtts|chatterbox|chatterbox_turbo|tada|kokoro
8
+
9
+ # Multi-speaker modes only (dialogue/interview) — omit entirely in solo mode:
10
+ # speakers:
11
+ # <name>:
12
+ # profile: <voice-profile> # required per speaker
13
+ # engine: qwen # optional
14
+ # language: en # optional
15
+ # instruct: warm # optional, <= 500 chars
16
+
17
+ segments: # required, non-empty
18
+ - text: "Replace with the spoken sentence." # required, 1..50000 characters
19
+ gap_ms: 400 # optional, >= 0 — silence before next clip
20
+ # instruct: "warm" # optional, <= 500 characters
21
+ # engine: qwen # optional, per-segment override
22
+ # language: en # optional, per-segment override
23
+ # max_chunk_chars: 800 # optional, 100..5000
24
+ # crossfade_ms: 50 # optional, 0..500
25
+ # speaker: <name> # multi-speaker only; must key the speakers map
@@ -25,22 +25,21 @@ states:
25
25
  # Seed the verdict so the judge gate guards can be evaluated in --dry-run
26
26
  # (dry-run skips actions but still evaluates shell guards). A real run's
27
27
  # judge step overwrites this file before the gate is read.
28
- command: "echo '{\"verdict\":\"PASS\",\"score\":0.0}' > ${vars.verdictFile} && echo 'generating content...'"
28
+ command: 'echo ''{"verdict":"PASS","score":0.0}'' > ${vars.verdictFile} && echo ''generating content...'''
29
29
  - id: judge
30
30
  description: "Evaluate generated content via the judge skill (agent.run)"
31
31
  onEnter:
32
- # `agent.run` is registered by the kk workflow host: it spawns an agent that loads the
33
- # content-judge skill, evaluates the content against ${vars.rubric}, and writes the verdict
32
+ # `agent.run` is registered by the kk workflow host: it spawns an agent that invokes the
33
+ # kk:content-judge skill, evaluates the content against ${vars.rubric}, and writes the verdict
34
34
  # JSON to ${vars.verdictFile}. Under `spur workflow run` (dry-run), this action is
35
- # skipped — the seeded verdict above keeps the gate evaluable. See
36
- # plugins/kk/skills/content-judge/SKILL.md and references/workflow-integration.md.
35
+ # skipped — the seeded verdict above keeps the gate evaluable.
37
36
  - kind: agent.run
38
37
  options:
39
38
  role: reviewer
40
39
  input: |
40
+ Invoke the kk:content-judge skill.
41
41
  Evaluate the content at ${vars.contentFile} against the ${vars.rubric} rubric.
42
- Load plugins/kk/skills/content-judge/SKILL.md and its references/rubrics.md.
43
- Write the verdict JSON to ${vars.verdictFile} per the contract in SKILL.md.
42
+ Write the verdict JSON to ${vars.verdictFile} per the skill's verdict contract.
44
43
  Print the verdict path as the last line of stdout.
45
44
  expectFile: ${vars.verdictFile}
46
45
  - id: publish
@@ -83,6 +83,14 @@ states:
83
83
  if [ -n "${vars.plugins_path}" ]; then set -- --plugins-path "${vars.plugins_path}"; fi;
84
84
  VOICE_GEN_MP3="${vars.transcode_mp3}" kk executor run voice-gen --in "${vars.work_dir}/3-audio/docs.json" --out "${vars.work_dir}/3-audio/content.json" "$@"
85
85
 
86
+ - id: quality-control
87
+ description: "Verify audio quality, speech rate, and silence/repetition QC metrics"
88
+ onEnter:
89
+ - kind: shell
90
+ options:
91
+ command: >-
92
+ bun -e 'const content = JSON.parse(await Bun.file(process.argv[1]).text()); const qc = content.metadata?.qc; console.log("=== Voice Quality Control Report ==="); console.log("Overall Score: " + (qc ? qc.overallScore : 100) + "/100 | Passed: " + (qc ? qc.passed : true)); if (qc && qc.criticalIssues && qc.criticalIssues.length) { console.warn("QC Issues:\n" + qc.criticalIssues.map(function(i) { return " - " + i; }).join("\n")); } else { console.log("All audio segments passed quality control checks cleanly."); }' "${vars.work_dir}/3-audio/content.json"
93
+
86
94
  - id: done
87
95
  description: "Terminal — Daily AI news voice broadcast generated successfully"
88
96
  - id: failed
@@ -138,7 +146,13 @@ transitions:
138
146
  kind: always
139
147
 
140
148
  - from: generate
149
+ to: quality-control
150
+ description: "Audio generated -> run quality control validation"
151
+ guard:
152
+ kind: always
153
+
154
+ - from: quality-control
141
155
  to: done
142
- description: "Audio generated successfully -> complete"
156
+ description: "Quality control checks complete -> done"
143
157
  guard:
144
158
  kind: always
@@ -14,7 +14,7 @@ vars:
14
14
  publish_plugin: "surfdash-pub"
15
15
  source: "./source"
16
16
  work_dir: "./work"
17
- plugins_path: "./plugins"
17
+ plugins_path: "" # empty -> ADR-012 default discovery (package-shipped built-ins); set for checkout dev
18
18
 
19
19
  states:
20
20
  - id: ingest
@@ -22,21 +22,30 @@ states:
22
22
  onEnter:
23
23
  - kind: shell
24
24
  options:
25
- command: kk executor run ${vars.ingestion_plugin} --in ${vars.source} --out ${vars.work_dir}/docs.json --plugins-path ${vars.plugins_path}
25
+ command: >-
26
+ set --;
27
+ if [ -n "${vars.plugins_path}" ]; then set -- --plugins-path "${vars.plugins_path}"; fi;
28
+ kk executor run ${vars.ingestion_plugin} --in ${vars.source} --out ${vars.work_dir}/docs.json "$@"
26
29
 
27
30
  - id: generate
28
31
  description: Run content generator plugin to produce markdown content (content.json)
29
32
  onEnter:
30
33
  - kind: shell
31
34
  options:
32
- command: kk executor run ${vars.generator_plugin} --in ${vars.work_dir}/docs.json --out ${vars.work_dir}/content.json --plugins-path ${vars.plugins_path}
35
+ command: >-
36
+ set --;
37
+ if [ -n "${vars.plugins_path}" ]; then set -- --plugins-path "${vars.plugins_path}"; fi;
38
+ kk executor run ${vars.generator_plugin} --in ${vars.work_dir}/docs.json --out ${vars.work_dir}/content.json "$@"
33
39
 
34
40
  - id: publish
35
41
  description: Run publish plugin to deploy content and receive result (result.json)
36
42
  onEnter:
37
43
  - kind: shell
38
44
  options:
39
- command: kk executor run ${vars.publish_plugin} --in ${vars.work_dir}/content.json --out ${vars.work_dir}/result.json --plugins-path ${vars.plugins_path}
45
+ command: >-
46
+ set --;
47
+ if [ -n "${vars.plugins_path}" ]; then set -- --plugins-path "${vars.plugins_path}"; fi;
48
+ kk executor run ${vars.publish_plugin} --in ${vars.work_dir}/content.json --out ${vars.work_dir}/result.json "$@"
40
49
 
41
50
  - id: done
42
51
  description: Terminal — all three plugin steps succeeded
@@ -22,9 +22,8 @@ vars:
22
22
  outline: ""
23
23
  force: "false"
24
24
  rubric: "tech-accuracy"
25
- verdictFile: ".spur/run/${vars.__runId}-itc-verdict.json"
25
+ verdictFile: "" # empty -> ${vars.work_dir}/.itc-verdict.json (set by prepare)
26
26
  agent: ""
27
- __runId: "itc"
28
27
  __hitlAnswer: ""
29
28
  __hitlInput: ""
30
29
 
@@ -40,6 +39,7 @@ states:
40
39
  echo "missing work_dir" >&2; exit 1;
41
40
  fi;
42
41
  mkdir -p "${vars.work_dir}" "${vars.work_dir}/2-outline" "${vars.work_dir}/3-draft";
42
+ echo 0 > "${vars.work_dir}/.revise-count";
43
43
  if [ -n "${vars.topic}" ] && [ -n "${vars.input_file}" ]; then
44
44
  echo "XOR violation: both topic and input_file set" >&2; exit 1;
45
45
  fi;
@@ -66,7 +66,7 @@ states:
66
66
  role: scribe
67
67
  agent: ${vars.agent}
68
68
  input: |
69
- Load plugins/kk/skills/storm-research/SKILL.md.
69
+ Invoke the kk:storm-research skill.
70
70
  Run storm-research on the topic or input file specified in the brief at ${vars.work_dir}/brief.md.
71
71
 
72
72
  - id: outline-write
@@ -77,7 +77,7 @@ states:
77
77
  role: scribe
78
78
  agent: ${vars.agent}
79
79
  input: |
80
- Load plugins/kk/skills/${vars.writer}/SKILL.md.
80
+ Invoke the kk:${vars.writer} skill.
81
81
  Generate outline options (outline-option-a.md, outline-option-b.md, and optionally outline-option-c.md) in ${vars.work_dir}/2-outline/ from the brief at ${vars.work_dir}/brief.md using playbook ${vars.playbook}.
82
82
  Do not wait for operator selection; write the option files.
83
83
  expectFile: ${vars.work_dir}/2-outline/outline-option-a.md
@@ -122,7 +122,7 @@ states:
122
122
  role: scribe
123
123
  agent: ${vars.agent}
124
124
  input: |
125
- Load plugins/kk/skills/${vars.writer}/SKILL.md.
125
+ Invoke the kk:${vars.writer} skill.
126
126
  Author the technical draft at ${vars.work_dir}/3-draft/draft-article.md based on approved outline ${vars.work_dir}/2-outline/outline-approved.md and brief ${vars.work_dir}/brief.md using playbook ${vars.playbook}.
127
127
  Revision feedback: ${vars.__hitlInput}
128
128
  expectFile: ${vars.work_dir}/3-draft/draft-article.md
@@ -143,12 +143,8 @@ states:
143
143
  - kind: shell
144
144
  options:
145
145
  command: >-
146
- mkdir -p .spur/run;
147
- run_id="${vars.__runId}";
148
- if [ -z "$run_id" ]; then run_id="itc"; fi;
149
- count_file=".spur/run/$run_id-itc-revise-count";
150
- curr=$(cat "$count_file" 2>/dev/null || echo 0);
151
- echo $((curr + 1)) > "$count_file";
146
+ n=$(cat "${vars.work_dir}/.revise-count" 2>/dev/null || echo 0);
147
+ echo $((n + 1)) > "${vars.work_dir}/.revise-count";
152
148
  - kind: hitl.input
153
149
  options:
154
150
  prompt: "Provide specific revision feedback for ${vars.work_dir}/3-draft/draft-article.md:"
@@ -162,11 +158,11 @@ states:
162
158
  role: reviewer
163
159
  agent: ${vars.agent}
164
160
  input: |
165
- Load plugins/kk/skills/content-judge/SKILL.md and its references/rubrics.md.
161
+ Invoke the kk:content-judge skill.
166
162
  Evaluate the draft at ${vars.work_dir}/3-draft/draft-article.md against the ${vars.rubric} rubric.
167
- Write the verdict JSON to ${vars.verdictFile} per the contract in SKILL.md.
163
+ Write the verdict JSON to ${vars.work_dir}/.itc-verdict.json per the skill's verdict contract.
168
164
  Print the verdict path as the last line of stdout.
169
- expectFile: ${vars.verdictFile}
165
+ expectFile: ${vars.work_dir}/.itc-verdict.json
170
166
 
171
167
  - id: done
172
168
  description: "Terminal — IT content draft generated and approved successfully"
@@ -252,7 +248,7 @@ transitions:
252
248
  guard:
253
249
  kind: shell
254
250
  options:
255
- command: 'test "${vars.__hitlAnswer}" = "no" && { run_id="${vars.__runId}"; if [ -z "$run_id" ]; then run_id="itc"; fi; test "$(cat .spur/run/$run_id-itc-revise-count 2>/dev/null || echo 0)" -lt 3; }'
251
+ command: 'test "${vars.__hitlAnswer}" = "no" && test "$(cat "${vars.work_dir}/.revise-count" 2>/dev/null || echo 0)" -lt 3'
256
252
 
257
253
  - from: draft-review
258
254
  to: failed
@@ -260,7 +256,7 @@ transitions:
260
256
  guard:
261
257
  kind: shell
262
258
  options:
263
- command: 'test "${vars.__hitlAnswer}" = "no" && { run_id="${vars.__runId}"; if [ -z "$run_id" ]; then run_id="itc"; fi; test "$(cat .spur/run/$run_id-itc-revise-count 2>/dev/null || echo 0)" -ge 3; }'
259
+ command: 'test "${vars.__hitlAnswer}" = "no" && test "$(cat "${vars.work_dir}/.revise-count" 2>/dev/null || echo 0)" -ge 3'
264
260
 
265
261
  - from: draft-revise
266
262
  to: draft-write
@@ -274,7 +270,7 @@ transitions:
274
270
  guard:
275
271
  kind: shell
276
272
  options:
277
- command: 'v="$(jq -r .verdict ${vars.verdictFile} 2>/dev/null)"; test -z "$v" -o "$v" = PASS'
273
+ command: 'v="$(jq -r .verdict ${vars.work_dir}/.itc-verdict.json 2>/dev/null)"; test -z "$v" -o "$v" = PASS'
278
274
 
279
275
  - from: judge
280
276
  to: failed
@@ -282,4 +278,4 @@ transitions:
282
278
  guard:
283
279
  kind: shell
284
280
  options:
285
- command: 'v="$(jq -r .verdict ${vars.verdictFile} 2>/dev/null)"; test -n "$v" -a "$v" != PASS'
281
+ command: 'v="$(jq -r .verdict ${vars.work_dir}/.itc-verdict.json 2>/dev/null)"; test -n "$v" -a "$v" != PASS'