@gobing-ai/knowledge-kit 0.0.36 → 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/.claude-plugin/marketplace.json +1 -1
- package/dist/board/collect/index.css +654 -16
- package/dist/board/collect/index.js +191 -64
- package/dist/board/daily-voice/index.css +679 -12
- package/dist/board/daily-voice/index.js +185 -66
- package/dist/board/itc/index.css +679 -13
- package/dist/board/itc/index.js +188 -66
- package/dist/index.js +2878 -152
- package/package.json +3 -2
- package/plugins/generations/content-gen/dist/index.js +158 -12
- package/plugins/generations/core-facts-gen/dist/index.js +158 -12
- package/plugins/generations/daily-article-gen/dist/index.js +158 -12
- package/plugins/generations/dailynews-gen/dist/index.js +180 -12
- package/plugins/generations/dailynews-gen/src/script-plan.ts +32 -0
- package/plugins/generations/episode-plan-gen/dist/index.js +158 -12
- package/plugins/generations/gemini-tts/README.md +4 -3
- package/plugins/generations/gemini-tts/dist/index.js +158 -12
- package/plugins/generations/image-gen/dist/index.js +158 -12
- package/plugins/generations/news-report-gen/dist/index.js +158 -12
- package/plugins/generations/omni-voice-gen/README.md +15 -4
- package/plugins/generations/omni-voice-gen/profiles.json +1 -2
- package/plugins/generations/voice-gen/dist/index.js +158 -12
- package/plugins/generations/voxcpm-tts/README.md +21 -1
- package/plugins/generations/voxcpm-tts/dist/index.js +173 -13
- package/plugins/generations/voxcpm-tts/scripts/audit-speaker-consistency.py +109 -0
- package/plugins/generations/voxcpm-tts/src/voxcpm-client.ts +28 -1
- package/plugins/ingestions/aihot-ingest/dist/index.js +158 -12
- package/plugins/ingestions/horizon-ingest/dist/index.js +158 -12
- package/plugins/ingestions/last30days-ingest/dist/index.js +158 -12
- package/plugins/ingestions/web-search/dist/index.js +158 -12
- package/plugins/kk/commands/workflow-run.md +56 -18
- package/plugins/kk/decisions/kk-itc.yaml +46 -0
- package/plugins/kk/decisions/kk-seo-keyword.yaml +57 -0
- package/plugins/kk/decisions/kk-seo-page.yaml +230 -0
- package/plugins/kk/decisions/kk-seo-pair.yaml +21 -0
- package/plugins/kk/decisions/kk-seo-site.yaml +90 -0
- package/plugins/kk/plugin.json +1 -1
- package/plugins/kk/publish-presets/chinese-article.json +14 -0
- package/plugins/kk/publish-presets/technical-article.json +14 -0
- package/plugins/kk/references/smart-seo-attribution.md +85 -0
- package/plugins/kk/scripts/daily-stages.ts +42 -2
- package/plugins/kk/scripts/daily-voice-style.zh.md +1 -1
- package/plugins/kk/scripts/itc-stages.ts +25 -118
- package/plugins/kk/scripts/kk-workflow-stages.ts +38 -1
- package/plugins/kk/scripts/seo-decisions.ts +477 -0
- package/plugins/kk/scripts/seo-enrich.ts +728 -0
- package/plugins/kk/scripts/seo-facts.ts +610 -0
- package/plugins/kk/scripts/seo-fetch.ts +766 -0
- package/plugins/kk/scripts/seo-report.ts +460 -0
- package/plugins/kk/scripts/seo-rules.ts +1882 -0
- package/plugins/kk/scripts/seo-stages.ts +1044 -0
- package/plugins/kk/skills/article-adapt/SKILL.md +2 -2
- package/plugins/kk/skills/smart-seo/SKILL.md +183 -0
- package/plugins/kk/skills/smart-seo/references/method.md +126 -0
- package/plugins/kk/skills/smart-seo/references/narrative.md +125 -0
- package/plugins/kk/skills/smart-seo/references/operations.md +202 -0
- package/plugins/kk/skills/smart-seo/references/seo-geo-sources.md +90 -0
- package/plugins/kk/workflows/feature-verification.yaml +28 -24
- package/plugins/kk/workflows/kk-daily-ai-voice2.yaml +86 -18
- package/plugins/kk/workflows/kk-itc-author.yaml +406 -0
- package/plugins/kk/workflows/kk-itc.yaml +208 -682
- package/plugins/kk/workflows/kk-smart-seo.yaml +251 -0
- package/plugins/publishings/bilibili-pub/dist/index.js +21782 -0
- package/plugins/publishings/bilibili-pub/dist/profile-check.js +20410 -0
- package/plugins/publishings/bilibili-pub/package.json +20 -0
- package/plugins/publishings/bilibili-pub/plugin.json +12 -0
- package/plugins/publishings/bilibili-pub/src/flow.ts +1296 -0
- package/plugins/publishings/bilibili-pub/src/index.ts +139 -0
- package/plugins/publishings/bilibili-pub/src/profile-check.ts +19 -0
- package/plugins/publishings/bilibili-pub/src/selectors.ts +222 -0
- package/plugins/publishings/bilibili-pub/tsconfig.json +4 -0
- package/plugins/publishings/cnblogs-pub/dist/index.js +21383 -0
- package/plugins/publishings/cnblogs-pub/dist/profile-check.js +20412 -0
- package/plugins/publishings/cnblogs-pub/package.json +19 -0
- package/plugins/publishings/cnblogs-pub/plugin.json +12 -0
- package/plugins/publishings/cnblogs-pub/src/flow.ts +708 -0
- package/plugins/publishings/cnblogs-pub/src/index.ts +172 -0
- package/plugins/publishings/cnblogs-pub/src/profile-check.ts +24 -0
- package/plugins/publishings/cnblogs-pub/src/selectors.ts +104 -0
- package/plugins/publishings/cnblogs-pub/tsconfig.json +4 -0
- package/plugins/publishings/csdn-pub/dist/index.js +21552 -0
- package/plugins/publishings/csdn-pub/dist/profile-check.js +20963 -0
- package/plugins/publishings/csdn-pub/package.json +19 -0
- package/plugins/publishings/csdn-pub/plugin.json +12 -0
- package/plugins/publishings/csdn-pub/src/index.ts +1178 -0
- package/plugins/publishings/csdn-pub/src/profile-check.ts +23 -0
- package/plugins/publishings/csdn-pub/tsconfig.json +4 -0
- package/plugins/publishings/emdash-pub/dist/index.js +158 -12
- package/plugins/publishings/emdash-pub/plugin.json +22 -1
- package/plugins/publishings/infoq-pub/dist/index.js +160 -12
- package/plugins/publishings/infoq-pub/dist/profile-check.js +160 -12
- package/plugins/publishings/infoq-pub/plugin.json +21 -0
- package/plugins/publishings/jike-pub/dist/index.js +21379 -0
- package/plugins/publishings/jike-pub/dist/profile-check.js +20951 -0
- package/plugins/publishings/jike-pub/package.json +19 -0
- package/plugins/publishings/jike-pub/plugin.json +12 -0
- package/plugins/publishings/jike-pub/src/index.ts +800 -0
- package/plugins/publishings/jike-pub/src/profile-check.ts +21 -0
- package/plugins/publishings/jike-pub/tsconfig.json +4 -0
- package/plugins/publishings/juejin-pub/dist/index.js +160 -12
- package/plugins/publishings/juejin-pub/dist/profile-check.js +160 -12
- package/plugins/publishings/juejin-pub/plugin.json +21 -0
- package/plugins/publishings/medium-pub/dist/index.js +158 -12
- package/plugins/publishings/medium-pub/plugin.json +22 -1
- package/plugins/publishings/podcast-pub/dist/index.js +158 -12
- package/plugins/publishings/qiita-pub/dist/index.js +158 -12
- package/plugins/publishings/qiita-pub/plugin.json +24 -1
- package/plugins/publishings/shipinhao-pub/dist/index.js +21715 -0
- package/plugins/publishings/shipinhao-pub/dist/profile-check.js +20431 -0
- package/plugins/publishings/shipinhao-pub/package.json +19 -0
- package/plugins/publishings/shipinhao-pub/plugin.json +12 -0
- package/plugins/publishings/shipinhao-pub/src/flow.ts +1323 -0
- package/plugins/publishings/shipinhao-pub/src/index.ts +173 -0
- package/plugins/publishings/shipinhao-pub/src/profile-check.ts +25 -0
- package/plugins/publishings/shipinhao-pub/src/selectors.ts +241 -0
- package/plugins/publishings/shipinhao-pub/tsconfig.json +4 -0
- package/plugins/publishings/sspai-pub/dist/index.js +21371 -0
- package/plugins/publishings/sspai-pub/dist/profile-check.js +20414 -0
- package/plugins/publishings/sspai-pub/package.json +19 -0
- package/plugins/publishings/sspai-pub/plugin.json +12 -0
- package/plugins/publishings/sspai-pub/src/flow.ts +624 -0
- package/plugins/publishings/sspai-pub/src/index.ts +167 -0
- package/plugins/publishings/sspai-pub/src/profile-check.ts +25 -0
- package/plugins/publishings/sspai-pub/src/selectors.ts +122 -0
- package/plugins/publishings/sspai-pub/tsconfig.json +4 -0
- package/plugins/publishings/substack-pub/dist/index.js +160 -12
- package/plugins/publishings/substack-pub/dist/profile-check.js +160 -12
- package/plugins/publishings/substack-pub/plugin.json +21 -0
- package/plugins/publishings/surfdash-pub/dist/index.js +158 -12
- package/plugins/publishings/surfdash-pub/plugin.json +22 -1
- package/plugins/publishings/threads-pub/dist/index.js +158 -12
- package/plugins/publishings/wechatmp-pub/dist/index.js +1669 -502
- package/plugins/publishings/wechatmp-pub/dist/profile-check.js +204 -21
- package/plugins/publishings/wechatmp-pub/plugin.json +32 -0
- package/plugins/publishings/wechatmp-pub/src/cgi-draft.ts +540 -0
- package/plugins/publishings/wechatmp-pub/src/cgi-media.ts +380 -0
- package/plugins/publishings/wechatmp-pub/src/cgi.ts +485 -0
- package/plugins/publishings/wechatmp-pub/src/flow.ts +104 -0
- package/plugins/publishings/weibo-pub/dist/index.js +160 -12
- package/plugins/publishings/weibo-pub/dist/profile-check.js +160 -12
- package/plugins/publishings/weibo-pub/plugin.json +35 -0
- package/plugins/publishings/x-pub/dist/index.js +160 -12
- package/plugins/publishings/x-pub/dist/profile-check.js +160 -12
- package/plugins/publishings/x-pub/plugin.json +40 -0
- package/plugins/publishings/xhs-pub/dist/index.js +160 -12
- package/plugins/publishings/xhs-pub/dist/profile-check.js +160 -12
- package/plugins/publishings/xhs-pub/plugin.json +37 -0
- package/plugins/publishings/xiaoyuzhou-pub/dist/index.js +21491 -0
- package/plugins/publishings/xiaoyuzhou-pub/dist/profile-check.js +20417 -0
- package/plugins/publishings/xiaoyuzhou-pub/package.json +19 -0
- package/plugins/publishings/xiaoyuzhou-pub/plugin.json +12 -0
- package/plugins/publishings/xiaoyuzhou-pub/src/flow.ts +826 -0
- package/plugins/publishings/xiaoyuzhou-pub/src/index.ts +174 -0
- package/plugins/publishings/xiaoyuzhou-pub/src/profile-check.ts +26 -0
- package/plugins/publishings/xiaoyuzhou-pub/src/selectors.ts +125 -0
- package/plugins/publishings/xiaoyuzhou-pub/tsconfig.json +4 -0
- package/plugins/publishings/zenn-pub/dist/index.js +158 -12
- package/plugins/publishings/zenn-pub/plugin.json +22 -1
- package/plugins/generations/omni-voice-gen/voices/robin-news.wav +0 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Smart SEO — sources, crawler policy and GEO limits
|
|
2
|
+
|
|
3
|
+
Every rule row carries the primary `sourceUrl` and the `sourceCheckedAt` date that justified it, and
|
|
4
|
+
the report header prints the method version's checked-at date. This reference is the refresh
|
|
5
|
+
procedure and the per-source limits — not a license to restate a source as a measurement.
|
|
6
|
+
|
|
7
|
+
## 1. Primary sources (checked 2026-10-14)
|
|
8
|
+
|
|
9
|
+
| Source | What it owns | Limit / unknown |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| [Google AI optimization guide](https://developers.google.com/search/docs/fundamentals/ai-optimization-guide) | Original, useful content plus technical access are what matter for Google AI surfaces. Special AI files, rigid chunking and schema are not eligibility requirements. | It promises no citation, ranking or inclusion. |
|
|
12
|
+
| [Google AI features](https://developers.google.com/search/docs/appearance/ai-features) | Snippet eligibility and indexing are prerequisites; crawl observations cannot verify inclusion. | Reporting surface is described inconsistently across Google pages and depends on the account; never freeze an availability claim. |
|
|
13
|
+
| [Google common crawlers](https://developers.google.com/crawling/docs/crawlers-fetchers/google-common-crawlers) | `Google-Extended` controls separate uses and does not control Search inclusion. | Robots groups express the site owner's **declared** policy only. |
|
|
14
|
+
| [OpenAI crawler documentation](https://developers.openai.com/api/docs/bots) | `OAI-SearchBot` is for search, `GPTBot` for training, `ChatGPT-User` is user-triggered with different semantics. | Blocking training is not a search defect; no OpenAI behavior is observable from the audit. |
|
|
15
|
+
| [Google Search updates](https://developers.google.com/search/updates) | Dated change log; FAQ rich results were fully retired on 2026-05-07 (eligibility had already been restricted to authoritative government/health sites in Aug/Sep 2023). | Any removal date must be re-read from this page, not from memory. |
|
|
16
|
+
| [PSI API notice](https://developers.google.com/speed/docs/insights/v5/get-started) | PSI setup and the announced CrUX removal from PSI. | The removal is announced, not completed — do not report it as done. |
|
|
17
|
+
| [Web Vitals](https://web.dev/articles/vitals) | Field p75 LCP ≤ 2.5 s, INP ≤ 200 ms, CLS ≤ 0.1 defines a Core Web Vitals pass. | Lab TBT cannot substitute for INP; a missing field sample is `unknown`, never zero. |
|
|
18
|
+
|
|
19
|
+
Supporting rule-level sources (RFC 9309 for robots matching, Google canonicalization and robots-meta
|
|
20
|
+
docs, sitemap docs) are recorded per row in `plugins/kk/scripts/seo-rules.ts` (`sourceUrl`).
|
|
21
|
+
|
|
22
|
+
## 2. Crawler policy — keep the three purposes separate
|
|
23
|
+
|
|
24
|
+
The audit reads the site's declared crawler policy and the audit's own requests. It cannot observe
|
|
25
|
+
what any other crawler did. When you explain crawler findings, name the purpose explicitly:
|
|
26
|
+
|
|
27
|
+
| Purpose | Typical user agents (as documented by their owners) | What a block means |
|
|
28
|
+
| --- | --- | --- |
|
|
29
|
+
| **Search / answer-surface indexing** | `Googlebot`, `Bingbot`, `OAI-SearchBot` | Affects eligibility for search and AI answer surfaces that use a search index. Operator intent required: a deliberate restriction is a decision, not a defect. |
|
|
30
|
+
| **Model training corpus** | `GPTBot`, `Google-Extended`, `ClaudeBot`, `CCBot` | A policy choice about training data. Blocking training is **not** a search defect, and allowing it is not a ranking or citation strategy. |
|
|
31
|
+
| **User-triggered fetch** | `ChatGPT-User` and similar on-demand fetchers | Different robots semantics: the fetch serves a user's explicit request. A block limits that user's session, not search eligibility. |
|
|
32
|
+
|
|
33
|
+
Rules the audit uses here: `robots_blocks_site` (adapted, critical), `ai_bots_blocked` and
|
|
34
|
+
`llms_txt_missing` (informational), `js_dependent` (informational). Report the observed directive,
|
|
35
|
+
the path it applies to and the operator-intent caveat — never "AI crawlers cannot see your site".
|
|
36
|
+
|
|
37
|
+
Also state what the audit itself did: its own crawl honors robots.txt, the declared `Crawl-delay`
|
|
38
|
+
and one shared page/request/byte/deadline budget, and it sends no credentials or cookies.
|
|
39
|
+
|
|
40
|
+
## 3. Source refresh procedure
|
|
41
|
+
|
|
42
|
+
Do this before changing a rule, re-publishing a rubric statement, or answering a question whose
|
|
43
|
+
answer depends on current engine behavior:
|
|
44
|
+
|
|
45
|
+
1. Open the rule's `sourceUrl` from the failing row (or the table above) and re-read the relevant
|
|
46
|
+
section. Do not refresh from a summary, a vendor README or a search-result snippet.
|
|
47
|
+
2. Record today's date as the new `sourceCheckedAt` for that rule and update `sourceUrl` if the
|
|
48
|
+
owner moved the page. Never silently keep an old checked-at date.
|
|
49
|
+
3. If the source contradicts the rule's current rationale, treat that as a **rule defect**: the
|
|
50
|
+
rationale, disposition and severity all change together, and the change is a method-version
|
|
51
|
+
change — not an in-run edit of a saved audit.
|
|
52
|
+
4. If two sources disagree, keep the more conservative reading, report the uncertainty, and say
|
|
53
|
+
which pages disagree. Vendor self-reported model agreement is not human calibration.
|
|
54
|
+
5. Never re-state an announced-but-incomplete change as shipped (for example the PSI/CrUX notice).
|
|
55
|
+
|
|
56
|
+
Audits stay reproducible: a saved `audit.json` keeps the `sourceCheckedAt` it was produced with,
|
|
57
|
+
and offline rescoring reuses the saved check rows rather than re-reading live sources.
|
|
58
|
+
|
|
59
|
+
## 4. GEO (generative-engine) diagnostics and their limits
|
|
60
|
+
|
|
61
|
+
GEO work in this method is **editorial diagnostics with explicit uncertainty**: intent
|
|
62
|
+
satisfaction, first-hand specificity, verifiable provenance, entity consistency and self-contained
|
|
63
|
+
answer-first facts. They are model judgments (`source: model`) with a maker and confidence, or
|
|
64
|
+
heuristic content checks — never measurements of an answer engine's behavior. The two `geo`
|
|
65
|
+
category rules and the page-level semantic decisions feed the action list exactly like other rows.
|
|
66
|
+
|
|
67
|
+
What this means in practice:
|
|
68
|
+
|
|
69
|
+
- Never state or imply that a change will produce citations, mentions, rankings or traffic.
|
|
70
|
+
- No synthetic visibility percentage is generated from a quality score. A visibility number exists
|
|
71
|
+
only when the operator supplied an imported snapshot (§5 of `operations.md`), and it is reported
|
|
72
|
+
with its source, window, platform and denominator.
|
|
73
|
+
- Locale-specific query and citation samples are dated snapshots, not live data. A missing
|
|
74
|
+
platform, denominator or sample count makes the row unusable — drop it rather than guess.
|
|
75
|
+
- "Answer-first" (heading fit, self-contained answer, next step) is an editorial rubric applied to
|
|
76
|
+
the observed page text. It is not a snippet or citation predictor.
|
|
77
|
+
- Where the evidence does not exist (a specific engine's answer for a specific query, an actual
|
|
78
|
+
citation rate, a training-corpus inclusion), say that it is unknown and name what would be needed
|
|
79
|
+
to know it. Live provider integration, rank tracking and Search Console OAuth are out of scope in
|
|
80
|
+
this version.
|
|
81
|
+
|
|
82
|
+
## 5. Vendors and third-party code
|
|
83
|
+
|
|
84
|
+
`vendors/` is reference-only: it is excluded from runtime and install resolution, and nothing may
|
|
85
|
+
be read or copied out of it into a shipped file. The audit is native Bun/TypeScript — no Python
|
|
86
|
+
path, no browser/rendering runtime, no bundled font assets. Vendor rule identities are retained for
|
|
87
|
+
traceability, but their behavior reflects the dispositions in `plugins/kk/references/smart-seo-attribution.md`
|
|
88
|
+
(shipped beside this skill), not the vendor's weighted grades or relative impact scale. The full vendor
|
|
89
|
+
review lives in the source repository at `docs/plans/2026-10-14-smart-seo-vendor-review.md`; it is
|
|
90
|
+
design-time context and is not installed, so never resolve a runtime path through it.
|
|
@@ -10,8 +10,20 @@
|
|
|
10
10
|
#
|
|
11
11
|
# Run: spur workflow run feature-verification.yaml --vars '{"featureId":"D63"}'
|
|
12
12
|
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
13
|
+
# No project-side override is required (task 1185, A33). Since the pass moved into the
|
|
14
|
+
# application (1176 / efd78f058) the bundled definition owns it end to end, so a
|
|
15
|
+
# project-layer copy of this file (plus a rooted port under `.spur/scripts/`) is a
|
|
16
|
+
# leftover — the port was written against an entry export contract that has since
|
|
17
|
+
# changed. Remove the override so this definition applies, or migrate the port to the
|
|
18
|
+
# current app-owned operation `runFeatureVerification` (the generated inline bundle's
|
|
19
|
+
# export). If a stale consumer is still reached, feature-lifecycle's `verifying` entry
|
|
20
|
+
# names it: the override path, the consumer script, the export it requires that the
|
|
21
|
+
# shipped entry no longer provides, and the entry path. Reinstalling or upgrading the
|
|
22
|
+
# plugin cannot supply a retired export — only the two remedies above can.
|
|
23
|
+
#
|
|
24
|
+
# Shape: verify -> done | failed. The onEnter step runs `spur feature verify`
|
|
25
|
+
# (D63 task 0915; script-absorption PR-5 retired the feature-verification-steps
|
|
26
|
+
# plugin script): it
|
|
15
27
|
# resolves this very definition for the verifier identity (name, source path,
|
|
16
28
|
# layer, definition digest), records the RUNNING receipt (run-scoped +
|
|
17
29
|
# feature-latest copies), registers the run-scoped receipt as a run artifact,
|
|
@@ -40,36 +52,28 @@ vars:
|
|
|
40
52
|
featureId: "X"
|
|
41
53
|
spurBin: "spur"
|
|
42
54
|
verificationCmd: "bun run spur-check"
|
|
55
|
+
# Operator-declared confidence level; empty derives it from the pass (HIGH when the selected
|
|
56
|
+
# definition's own command exited 0 with an unchanged proof-input digest, MEDIUM under a caller
|
|
57
|
+
# `--cmd` override, LOW otherwise). The completion boundary refuses a PASS carrying no level or
|
|
58
|
+
# LOW unless the receipt records the acknowledgement below.
|
|
59
|
+
confidence: ""
|
|
60
|
+
# Operator acknowledgement of a LOW level. It rides the receipt, so the transition reads it from
|
|
61
|
+
# the evidence rather than from whatever flags a later command happens to pass.
|
|
62
|
+
ackLowConfidence: "false"
|
|
43
63
|
__runId: ""
|
|
44
64
|
|
|
45
65
|
states:
|
|
46
66
|
- id: verify
|
|
47
67
|
description: >
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
actions fail closed — a locator/script failure, an unresolved or
|
|
53
|
-
non-installed root, an absent verifier, or a failing check yields a
|
|
54
|
-
non-PASS status — and always exit 0, so the transition guard routes
|
|
55
|
-
missing/corrupt/FAIL to `failed`.
|
|
68
|
+
Run the repo-wide check set via `spur feature verify`, which
|
|
69
|
+
records the bound evidence receipt (verifier identity, checked-input
|
|
70
|
+
digest, run identity) and the coarse status file, always exit 0 so the
|
|
71
|
+
transition guard routes missing/corrupt/FAIL to `failed`.
|
|
56
72
|
onEnter:
|
|
57
73
|
- kind: shell
|
|
58
74
|
options:
|
|
59
75
|
command: >-
|
|
60
|
-
|
|
61
|
-
if [ -n "$S" ] && [ -f "$S" ]; then node "$S" --run-id "$__runId" --spur-bin "$spurBin";
|
|
62
|
-
else echo "script-root failed closed — run 'superskill install sp --marketplace gobing-ai/spur'" >&2;
|
|
63
|
-
fi;
|
|
64
|
-
exit 0
|
|
65
|
-
- kind: shell
|
|
66
|
-
options:
|
|
67
|
-
command: >-
|
|
68
|
-
mkdir -p .spur/run;
|
|
69
|
-
DIR="$(jq -r 'select(.mode == "installed" and (.dir | type == "string") and .dir != "") | .dir' ".spur/run/$__runId-script-root.json" 2>/dev/null)" || DIR="";
|
|
70
|
-
[ -n "$DIR" ] && [ -f "$DIR/feature-verification-steps.mjs" ] && S="$DIR/feature-verification-steps.mjs";
|
|
71
|
-
[ -f "$S" ] && bun "$S" verify --feature-id "$featureId" --run-id "$__runId" --spur-bin "$spurBin" || printf 'FAIL feature-verification failed closed — unresolved root or verifier failure\n' > ".spur/run/$__runId-feature-verification.status";
|
|
72
|
-
exit 0
|
|
76
|
+
mkdir -p .spur/run; ACK=""; [ "$ackLowConfidence" = "true" ] && ACK="--ack-low-confidence"; $spurBin feature verify "$featureId" --run-id "$__runId" --confidence "$confidence" $ACK --no-logo || printf 'FAIL feature-verification failed closed — spur feature verify exited nonzero\n' > ".spur/run/$__runId-feature-verification.status"; exit 0
|
|
73
77
|
|
|
74
78
|
- id: done
|
|
75
79
|
description: Terminal — repo-wide checks passed and the receipt is bound.
|
|
@@ -80,7 +84,7 @@ states:
|
|
|
80
84
|
transitions:
|
|
81
85
|
- from: verify
|
|
82
86
|
to: done
|
|
83
|
-
description: Repo-wide checks passed —
|
|
87
|
+
description: Repo-wide checks passed — `spur feature verify` completed the receipt with PASS.
|
|
84
88
|
guard:
|
|
85
89
|
kind: shell
|
|
86
90
|
options:
|
|
@@ -22,10 +22,13 @@ vars:
|
|
|
22
22
|
window: "24h"
|
|
23
23
|
language: "zh"
|
|
24
24
|
voice_profile: "robin-news"
|
|
25
|
-
# Voice driver switch —
|
|
26
|
-
# |
|
|
27
|
-
#
|
|
28
|
-
|
|
25
|
+
# Voice driver switch — voxcpm (voxcpm-tts) | gemini (gemini-tts) | voicebox (voice-gen)
|
|
26
|
+
# | ominivoice (omni-voice-gen). The generate tier below mirrors the fallback order, and the
|
|
27
|
+
# fit/duration gates take their spoken-char rate from this var — switching drivers here is enough.
|
|
28
|
+
# 2026-10-15 production test (operator decision): voxcpm first, then gemini, then omni. voxcpm
|
|
29
|
+
# rendered that episode in 21.8 min at a measured 5.19 字/秒 (fitted at 5.2); if the audio verdict
|
|
30
|
+
# is good this is the standing order, otherwise revert this default to "gemini".
|
|
31
|
+
vdriver: "voxcpm"
|
|
29
32
|
intro_music: ".works/kk-daily-ai-voice/AI每日资讯_8秒播客片头.mp3"
|
|
30
33
|
surfdash_root: "/Users/robin/xprojects/surfdash"
|
|
31
34
|
title: ""
|
|
@@ -258,7 +261,7 @@ nodes:
|
|
|
258
261
|
command: >-
|
|
259
262
|
kk store pool-count "${vars.work_dir}/21-plan/${vars.run_date}_04_quality-control-content_candidates.json" --min 1
|
|
260
263
|
&& test "${vars.plan_translate_enabled}" = "true"
|
|
261
|
-
&& !
|
|
264
|
+
&& ! jq -e --argjson n "$(jq '.metadata.docs|length' "${vars.work_dir}/21-plan/${vars.run_date}_04_quality-control-content_candidates.json")" 'type=="array" and length==$n and all(.[];type=="object")' "${vars.work_dir}/21-plan/${vars.run_date}_03_plan_plan.json"
|
|
262
265
|
action:
|
|
263
266
|
kind: agent.run
|
|
264
267
|
# 0238 R2: a stochastic executor no-op must not end the run here — the retry sibling decides.
|
|
@@ -268,21 +271,28 @@ nodes:
|
|
|
268
271
|
agent: ${vars.agent}
|
|
269
272
|
# ADR-115 error tier: keep this prompt <= 1000 chars (0133 R3; 0138 R4a copy discipline).
|
|
270
273
|
# The anchor is shared with plan-translate-retry so the two attempts cannot drift apart.
|
|
274
|
+
# 20261015 forensics: headless agy's terminal sandbox denies workspace writes for EVERY
|
|
275
|
+
# shell command (command() rules are promptless-but-sandboxed; unsandboxed() is dead), so
|
|
276
|
+
# the producer must deliver via the file-write tool; and the condition gate checks JSON
|
|
277
|
+
# validity (array, length == candidates docs, all objects) because a pi token-cap staged
|
|
278
|
+
# write once flowed 4/12 items downstream. Keep both when editing prompt or condition.
|
|
271
279
|
input: &plan-translate-input |
|
|
272
|
-
Read ${vars.work_dir}/21-plan/${vars.run_date}_04_quality-control-content_candidates.json
|
|
273
|
-
For needsTranslation items
|
|
274
|
-
Titles read as
|
|
275
|
-
Copy discipline: reader-facing news copy — no scaffold labels (「可做角度」「为什么现在值得注意」「社区讨论」「背景」「潜在影响」「影响」), no
|
|
276
|
-
Keep
|
|
277
|
-
|
|
280
|
+
Read ${vars.work_dir}/21-plan/${vars.run_date}_04_quality-control-content_candidates.json; metadata.docs (Doc[]) is the plan.
|
|
281
|
+
For needsTranslation items adapt "title", "body" and "metadata.brief" into spoken simplified Chinese — keep every fact, number, name, quote, hedge (口播全长改编,不摘要不省略), body ≈0.6–0.7× source.
|
|
282
|
+
Titles read as news; keep product/model names and body URLs verbatim, use 「」 not ASCII quotes.
|
|
283
|
+
Copy discipline: reader-facing news copy — no scaffold labels (「可做角度」「为什么现在值得注意」「社区讨论」「背景」「潜在影响」「影响」), no hedging labels (「读者宜另行核实」「仍待验证」) — merge or drop.
|
|
284
|
+
Keep id/sourceUri/mediaType/metadata as-is; no comments/trailing commas.
|
|
285
|
+
Deliver with your file-write tool (headless agy sandbox blocks shell writes); the file must end as ONE valid JSON array — no split markers/placeholders.
|
|
286
|
+
Output the JSON array — same length and order — to ${vars.work_dir}/21-plan/${vars.run_date}_03_plan_plan.json.
|
|
278
287
|
expectFile: ${vars.work_dir}/21-plan/${vars.run_date}_03_plan_plan.json
|
|
279
288
|
allowAppend: false
|
|
280
289
|
|
|
281
290
|
- id: plan-translate-retry
|
|
282
291
|
description: >-
|
|
283
|
-
Bounded recovery for plan-translate (0238 R2): runs only when the primary settled without
|
|
284
|
-
expectFile, retries the same input on a different
|
|
285
|
-
fails the run loudly instead of letting an
|
|
292
|
+
Bounded recovery for plan-translate (0238 R2): runs only when the primary settled without a
|
|
293
|
+
VALID expectFile (missing or contract-violating JSON), retries the same input on a different
|
|
294
|
+
tier, and carries NO onError — a second miss fails the run loudly instead of letting an
|
|
295
|
+
untranslated or truncated plan flow downstream.
|
|
286
296
|
dependsOn: [plan-translate]
|
|
287
297
|
condition:
|
|
288
298
|
kind: shell
|
|
@@ -290,7 +300,7 @@ nodes:
|
|
|
290
300
|
command: >-
|
|
291
301
|
kk store pool-count "${vars.work_dir}/21-plan/${vars.run_date}_04_quality-control-content_candidates.json" --min 1
|
|
292
302
|
&& test "${vars.plan_translate_enabled}" = "true"
|
|
293
|
-
&& !
|
|
303
|
+
&& ! jq -e --argjson n "$(jq '.metadata.docs|length' "${vars.work_dir}/21-plan/${vars.run_date}_04_quality-control-content_candidates.json")" 'type=="array" and length==$n and all(.[];type=="object")' "${vars.work_dir}/21-plan/${vars.run_date}_03_plan_plan.json"
|
|
294
304
|
action:
|
|
295
305
|
kind: agent.run
|
|
296
306
|
options:
|
|
@@ -457,7 +467,7 @@ nodes:
|
|
|
457
467
|
# ADR-115 error tier: keep this prompt <= 1000 chars.
|
|
458
468
|
input: |
|
|
459
469
|
Read ${vars.work_dir}/21-plan/${vars.run_date}_03_plan_plan.json — a JSON array of docs; don't edit it. Also read the style contract ${vars.work_dir}/24-script/${vars.run_date}_08_script-write_style.md and obey its char caps, duration budget and banned phrases.
|
|
460
|
-
For each doc write a `lead` (a spoken bridge, not containing the title) and an `insight` (
|
|
470
|
+
For each doc write a `lead` (a spoken bridge, not containing the title) and an `insight` (a take, not a recap: the narration just read that doc's facts — never restate its facts, numbers or wording; give only your angle, judgment or what-to-watch, no new facts, keep hedges(据报道), no new degree words).
|
|
461
471
|
intro/outro hook only in-scope items; no greeting or sign-off — the builder adds both. 选题边界:政治/外交、贸易管制、军事、公共政策争议、社会公共事件条目绝不复述;读文章 22-article/*_06_article-write_body.md,其文末注记点名的 id 一并进 excluded,各配中文原因。
|
|
462
472
|
Output only JSON {"version":1,"intro":"…","outro":"…","items":[{"id":"…","lead":"…","insight":"…"}],"excluded":[{"id":"…","reason":"…"}]} to ${vars.work_dir}/24-script/${vars.run_date}_08_script-write_plan.json. Exactly one `items` entry per doc not in `excluded`.
|
|
463
473
|
expectFile: ${vars.work_dir}/24-script/${vars.run_date}_08_script-write_plan.json
|
|
@@ -535,7 +545,7 @@ nodes:
|
|
|
535
545
|
kk stage daily-wrap-docs "${vars.work_dir}" "${vars.run_date}" "${vars.voice_profile}"
|
|
536
546
|
|
|
537
547
|
- id: generate
|
|
538
|
-
description: "
|
|
548
|
+
description: "Voice tier, primary driver (vars.vdriver — voxcpm while the 2026-10-15 production test runs). onError: continue — the fallback siblings below are the loud chain (same pattern as 0238 R2)."
|
|
539
549
|
# wrap-docs is a data dependency, not a sibling: daily-generate reads its _10_wrap-docs_docs.json
|
|
540
550
|
# as the TTS input. Without this edge the two nodes race in the same wave (0212 dogfood finding).
|
|
541
551
|
dependsOn: [script, safety, review, wrap-docs]
|
|
@@ -547,18 +557,76 @@ nodes:
|
|
|
547
557
|
action:
|
|
548
558
|
kind: shell
|
|
549
559
|
options:
|
|
560
|
+
onError: continue
|
|
550
561
|
command: >-
|
|
551
562
|
OMNIVOICE_SPEED=1.06 kk stage daily-generate "${vars.work_dir}" "${vars.run_date}" "${vars.plugins_path}" "${vars.transcode_mp3}" "${vars.vdriver}" "1" "${vars.episode_max_minutes}"
|
|
552
563
|
|
|
564
|
+
# Driver fallback chain (2026-10-15, operator decision): voxcpm -> gemini -> omni. Each sibling
|
|
565
|
+
# runs the same stage with a pinned driver; its condition re-checks the pool AND that NO upstream
|
|
566
|
+
# driver left a valid, passing whole-document Content (the stage stamps metadata.generator with
|
|
567
|
+
# its plugin id and the cache ignores foreign-driver sections, so a failed attempt can neither be
|
|
568
|
+
# relabeled nor mix voices). Non-final siblings continue on error; the last one is loud.
|
|
569
|
+
- id: generate-fallback
|
|
570
|
+
description: "Voice tier fallback 1: gemini (gemini-tts) when the primary driver left no valid Content"
|
|
571
|
+
dependsOn: [generate]
|
|
572
|
+
condition:
|
|
573
|
+
kind: shell
|
|
574
|
+
options:
|
|
575
|
+
command: >-
|
|
576
|
+
kk store pool-count "${vars.work_dir}/21-plan/${vars.run_date}_04_quality-control-content_candidates.json" --min 1
|
|
577
|
+
&& ! jq -e '(.metadata.generator == "kk:voxcpm-tts" or .metadata.generator == "kk:gemini-tts") and .metadata.qc.passed == true' "${vars.work_dir}/30-audio/${vars.run_date}_11_generate_content.json"
|
|
578
|
+
action:
|
|
579
|
+
kind: shell
|
|
580
|
+
options:
|
|
581
|
+
onError: continue
|
|
582
|
+
command: >-
|
|
583
|
+
kk stage daily-generate "${vars.work_dir}" "${vars.run_date}" "${vars.plugins_path}" "${vars.transcode_mp3}" "gemini" "1" "${vars.episode_max_minutes}"
|
|
584
|
+
|
|
585
|
+
- id: generate-fallback2
|
|
586
|
+
description: "Voice tier fallback 2 (last, loud): omni-voice-gen when neither voxcpm nor gemini delivered"
|
|
587
|
+
dependsOn: [generate-fallback]
|
|
588
|
+
condition:
|
|
589
|
+
kind: shell
|
|
590
|
+
options:
|
|
591
|
+
command: >-
|
|
592
|
+
kk store pool-count "${vars.work_dir}/21-plan/${vars.run_date}_04_quality-control-content_candidates.json" --min 1
|
|
593
|
+
&& ! jq -e '(.metadata.generator == "kk:voxcpm-tts" or .metadata.generator == "kk:gemini-tts" or .metadata.generator == "kk:omni-voice-gen") and .metadata.qc.passed == true' "${vars.work_dir}/30-audio/${vars.run_date}_11_generate_content.json"
|
|
594
|
+
action:
|
|
595
|
+
kind: shell
|
|
596
|
+
options:
|
|
597
|
+
command: >-
|
|
598
|
+
OMNIVOICE_SPEED=1.06 kk stage daily-generate "${vars.work_dir}" "${vars.run_date}" "${vars.plugins_path}" "${vars.transcode_mp3}" "ominivoice" "1" "${vars.episode_max_minutes}"
|
|
599
|
+
|
|
553
600
|
- id: intro
|
|
554
601
|
description: "Prepend the 8s intro sting (intro_music var; empty = skip), update duration/audioPath"
|
|
555
|
-
dependsOn: [generate]
|
|
602
|
+
dependsOn: [generate, generate-fallback, generate-fallback2]
|
|
556
603
|
action:
|
|
557
604
|
kind: shell
|
|
558
605
|
options:
|
|
559
606
|
command: >-
|
|
560
607
|
kk stage daily-intro "${vars.work_dir}" "${vars.run_date}" "${vars.intro_music}"
|
|
561
608
|
|
|
609
|
+
# ---- advisory voice audit (2026-10-16): never fails the run ----
|
|
610
|
+
# The 20261015 episode shipped 59 different speakers because an instruct-mode profile pins none,
|
|
611
|
+
# and nothing but a human listening caught it. This grades the final render by per-segment median
|
|
612
|
+
# F0 (a speaker change swings it tens of Hz) and prints the table plus a PASS/FAIL line. It is
|
|
613
|
+
# deliberately advisory: `|| true` keeps its non-zero exit out of the run, and onError covers a
|
|
614
|
+
# missing venv (the check needs librosa from the voxcpm plugin's environment).
|
|
615
|
+
- id: voice-audit
|
|
616
|
+
description: "Advisory speaker-consistency audit of the joined episode (warn-only, never fails the run)"
|
|
617
|
+
dependsOn: [intro]
|
|
618
|
+
condition:
|
|
619
|
+
kind: shell
|
|
620
|
+
options:
|
|
621
|
+
command: >-
|
|
622
|
+
test -f "${vars.work_dir}/30-audio/${vars.run_date}_11_generate_content.json"
|
|
623
|
+
action:
|
|
624
|
+
kind: shell
|
|
625
|
+
options:
|
|
626
|
+
command: >-
|
|
627
|
+
kk stage daily-voice-audit "${vars.work_dir}" "${vars.run_date}" "${vars.plugins_path}"
|
|
628
|
+
onError: continue
|
|
629
|
+
|
|
562
630
|
- id: duration
|
|
563
631
|
description: "Measured duration gate: under episode_min_minutes the run refuses and closes as no-content (refusal artifact + emptied candidates, exit 0 — 0266); above episode_max_minutes it still fails loud. Duration is authoritative."
|
|
564
632
|
dependsOn: [intro]
|