@opengsd/gsd-core 1.7.0-rc.1 → 1.7.0-rc.2
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 +20 -0
- package/.claude-plugin/plugin.json +1 -1
- package/.opencode/plugins/gsd-core.js +711 -0
- package/agents/gsd-advisor-researcher.md +2 -0
- package/agents/gsd-ai-researcher.md +1 -1
- package/agents/gsd-assumptions-analyzer.md +2 -0
- package/agents/gsd-code-fixer.md +2 -0
- package/agents/gsd-code-reviewer.md +2 -0
- package/agents/gsd-codebase-mapper.md +2 -0
- package/agents/gsd-debugger.md +2 -0
- package/agents/gsd-doc-writer.md +2 -0
- package/agents/gsd-eval-auditor.md +2 -0
- package/agents/gsd-executor.md +9 -6
- package/agents/gsd-integration-checker.md +2 -0
- package/agents/gsd-nyquist-auditor.md +2 -0
- package/agents/gsd-phase-researcher.md +2 -0
- package/agents/gsd-plan-checker.md +2 -0
- package/agents/gsd-planner.md +2 -0
- package/agents/gsd-project-researcher.md +2 -0
- package/agents/gsd-research-synthesizer.md +2 -0
- package/agents/gsd-roadmapper.md +2 -0
- package/agents/gsd-security-auditor.md +2 -0
- package/agents/gsd-ui-auditor.md +2 -0
- package/agents/gsd-ui-checker.md +2 -0
- package/agents/gsd-ui-researcher.md +2 -0
- package/agents/gsd-verifier.md +4 -2
- package/bin/install.js +118 -1
- package/gemini-extension.json +1 -1
- package/gsd-core/bin/gsd-tools.cjs +18 -7
- package/gsd-core/bin/lib/capability-loader.cjs +27 -9
- package/gsd-core/bin/lib/capability-registry.cjs +51 -49
- package/gsd-core/bin/lib/capability-source.cjs +22 -7
- package/gsd-core/bin/lib/capability-validator.cjs +24 -2
- package/gsd-core/bin/lib/commands.cjs +2 -1
- package/gsd-core/bin/lib/frontmatter.cjs +53 -6
- package/gsd-core/bin/lib/handshake-serialized.cjs +70 -0
- package/gsd-core/bin/lib/host-integration-sdk.cjs +53 -0
- package/gsd-core/bin/lib/host-integration.cjs +61 -0
- package/gsd-core/bin/lib/init.cjs +34 -6
- package/gsd-core/bin/lib/milestone.cjs +49 -10
- package/gsd-core/bin/lib/phase-id.cjs +18 -0
- package/gsd-core/bin/lib/phase.cjs +37 -27
- package/gsd-core/bin/lib/phases-command-router.cjs +4 -3
- package/gsd-core/bin/lib/probe-core.cjs +44 -4
- package/gsd-core/bin/lib/roadmap-command-router.cjs +3 -2
- package/gsd-core/bin/lib/roadmap-parser.cjs +21 -11
- package/gsd-core/bin/lib/roadmap.cjs +28 -20
- package/gsd-core/bin/lib/state-transition.cjs +15 -0
- package/gsd-core/bin/lib/state.cjs +27 -8
- package/gsd-core/bin/lib/validate.cjs +2 -1
- package/gsd-core/bin/lib/verify.cjs +6 -4
- package/gsd-core/bin/lib/workstream-inventory-builder.cjs +12 -2
- package/gsd-core/bin/lib/workstream-inventory.cjs +28 -0
- package/gsd-core/bin/shared/model-catalog.json +8 -8
- package/gsd-core/references/agent-skills-bootstrap.md +60 -0
- package/gsd-core/references/model-profiles.md +27 -0
- package/gsd-core/workflows/autonomous.md +22 -24
- package/gsd-core/workflows/complete-milestone.md +6 -10
- package/gsd-core/workflows/execute-phase.md +1 -1
- package/gsd-core/workflows/forensics.md +3 -3
- package/gsd-core/workflows/help/modes/full.md +1 -1
- package/gsd-core/workflows/milestone-summary.md +3 -3
- package/gsd-core/workflows/new-milestone.md +6 -0
- package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +42 -0
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +102 -0
- package/gsd-core/workflows/plan-phase/steps/windows-troubleshooting.md +23 -0
- package/gsd-core/workflows/plan-phase.md +3 -158
- package/gsd-core/workflows/review.md +7 -2
- package/gsd-core/workflows/settings-advanced.md +10 -10
- package/gsd-core/workflows/verify-work.md +1 -2
- package/package.json +3 -1
- package/scripts/run-tests.cjs +51 -1
- package/scripts/sync-manifest-versions.cjs +66 -14
- package/skills/gsd-review/SKILL.md +6 -0
|
@@ -10,7 +10,7 @@ const capabilities = {
|
|
|
10
10
|
"ai-integration": {
|
|
11
11
|
"id": "ai-integration",
|
|
12
12
|
"role": "feature",
|
|
13
|
-
"version": "1.7.0-rc.
|
|
13
|
+
"version": "1.7.0-rc.2",
|
|
14
14
|
"title": "AI design contract",
|
|
15
15
|
"description": "AI-SPEC design contract workflow for phases that build AI systems; owns the AI integration command, agents, and workflow.ai_integration_phase activation key.",
|
|
16
16
|
"tier": "full",
|
|
@@ -63,7 +63,7 @@ const capabilities = {
|
|
|
63
63
|
"antigravity": {
|
|
64
64
|
"id": "antigravity",
|
|
65
65
|
"role": "runtime",
|
|
66
|
-
"version": "1.7.0-rc.
|
|
66
|
+
"version": "1.7.0-rc.2",
|
|
67
67
|
"title": "Antigravity",
|
|
68
68
|
"description": "Google Antigravity IDE — nested under ~/.gemini/antigravity; probed across 1.x and 2.x layouts; Gemini hook event dialect; flat skill layout; tier-1 support.",
|
|
69
69
|
"tier": "core",
|
|
@@ -141,7 +141,7 @@ const capabilities = {
|
|
|
141
141
|
"assumption-delta": {
|
|
142
142
|
"id": "assumption-delta",
|
|
143
143
|
"role": "feature",
|
|
144
|
-
"version": "1.7.0-rc.
|
|
144
|
+
"version": "1.7.0-rc.2",
|
|
145
145
|
"title": "Assumption-delta architecture checkpoint",
|
|
146
146
|
"description": "Rarely-firing advisory checkpoint that triggers when a phase makes something plural, optional, or chosen that used to be singular, required, or derived. Surfaces one identity-model question (promote the new general representation to primary, or add it alongside?) so a silent primary-key drift does not accumulate into a later user-facing bug. Non-blocking; fires only on a detected signal.",
|
|
147
147
|
"tier": "full",
|
|
@@ -187,7 +187,7 @@ const capabilities = {
|
|
|
187
187
|
"audit": {
|
|
188
188
|
"id": "audit",
|
|
189
189
|
"role": "feature",
|
|
190
|
-
"version": "1.7.0-rc.
|
|
190
|
+
"version": "1.7.0-rc.2",
|
|
191
191
|
"title": "Audit",
|
|
192
192
|
"description": "Open-artifact audit and UAT-gap audit for milestone close gates; exposes `gsd-tools audit-uat` (cross-phase UAT outstanding items) and `gsd-tools audit-open` (structured open-artifact scan across debug, tasks, threads, todos, seeds, UAT, verification, context-questions).",
|
|
193
193
|
"tier": "full",
|
|
@@ -224,7 +224,7 @@ const capabilities = {
|
|
|
224
224
|
"augment": {
|
|
225
225
|
"id": "augment",
|
|
226
226
|
"role": "runtime",
|
|
227
|
-
"version": "1.7.0-rc.
|
|
227
|
+
"version": "1.7.0-rc.2",
|
|
228
228
|
"title": "Augment Code",
|
|
229
229
|
"description": "Augment Code CLI — commands + nested-skill artifact layout; settings-json hook surface; Claude hook event dialect; tier-2 support.",
|
|
230
230
|
"tier": "core",
|
|
@@ -327,7 +327,7 @@ const capabilities = {
|
|
|
327
327
|
"claude": {
|
|
328
328
|
"id": "claude",
|
|
329
329
|
"role": "runtime",
|
|
330
|
-
"version": "1.7.0-rc.
|
|
330
|
+
"version": "1.7.0-rc.2",
|
|
331
331
|
"title": "Claude Code",
|
|
332
332
|
"description": "Anthropic Claude Code — primary development runtime; tier-1 support with full hook surface and skills-based global install.",
|
|
333
333
|
"tier": "core",
|
|
@@ -411,7 +411,7 @@ const capabilities = {
|
|
|
411
411
|
"cline": {
|
|
412
412
|
"id": "cline",
|
|
413
413
|
"role": "runtime",
|
|
414
|
-
"version": "1.7.0-rc.
|
|
414
|
+
"version": "1.7.0-rc.2",
|
|
415
415
|
"title": "Cline",
|
|
416
416
|
"description": "Cline (VS Code extension) — global-only nested-skill layout; cline-rules hook surface (.clinerules); no hook events emitted; tier-2 support.",
|
|
417
417
|
"tier": "core",
|
|
@@ -472,7 +472,7 @@ const capabilities = {
|
|
|
472
472
|
"code-review": {
|
|
473
473
|
"id": "code-review",
|
|
474
474
|
"role": "feature",
|
|
475
|
-
"version": "1.7.0-rc.
|
|
475
|
+
"version": "1.7.0-rc.2",
|
|
476
476
|
"title": "Code review",
|
|
477
477
|
"description": "Source-file code review and review-fix workflow support for completed execution work.",
|
|
478
478
|
"tier": "full",
|
|
@@ -533,7 +533,7 @@ const capabilities = {
|
|
|
533
533
|
"codebuddy": {
|
|
534
534
|
"id": "codebuddy",
|
|
535
535
|
"role": "runtime",
|
|
536
|
-
"version": "1.7.0-rc.
|
|
536
|
+
"version": "1.7.0-rc.2",
|
|
537
537
|
"title": "CodeBuddy",
|
|
538
538
|
"description": "CodeBuddy (Tencent) — converted commands + skills artifact layout; settings-json hook surface; Claude hook event dialect; tier-2 support.",
|
|
539
539
|
"tier": "core",
|
|
@@ -636,7 +636,7 @@ const capabilities = {
|
|
|
636
636
|
"codex": {
|
|
637
637
|
"id": "codex",
|
|
638
638
|
"role": "runtime",
|
|
639
|
-
"version": "1.7.0-rc.
|
|
639
|
+
"version": "1.7.0-rc.2",
|
|
640
640
|
"title": "OpenAI Codex CLI",
|
|
641
641
|
"description": "OpenAI Codex CLI — shell-var command style; per-agent sandbox tiers; config.toml + hooks.json hook surface; tier-1 support.",
|
|
642
642
|
"tier": "core",
|
|
@@ -707,7 +707,7 @@ const capabilities = {
|
|
|
707
707
|
"copilot": {
|
|
708
708
|
"id": "copilot",
|
|
709
709
|
"role": "runtime",
|
|
710
|
-
"version": "1.7.0-rc.
|
|
710
|
+
"version": "1.7.0-rc.2",
|
|
711
711
|
"title": "GitHub Copilot",
|
|
712
712
|
"description": "GitHub Copilot (VS Code) — markdown config format; copilot-inline hook surface; no hook events emitted; flat skill nesting (unconfirmed recursive loader); tier-2 support.",
|
|
713
713
|
"tier": "core",
|
|
@@ -778,7 +778,7 @@ const capabilities = {
|
|
|
778
778
|
"cursor": {
|
|
779
779
|
"id": "cursor",
|
|
780
780
|
"role": "runtime",
|
|
781
|
-
"version": "1.7.0-rc.
|
|
781
|
+
"version": "1.7.0-rc.2",
|
|
782
782
|
"title": "Cursor",
|
|
783
783
|
"description": "Cursor IDE — skills + converted commands artifact layout; hooks.json surface; Claude hook event dialect; recursive skill loader (flat nesting); tier-2 support.",
|
|
784
784
|
"tier": "core",
|
|
@@ -881,7 +881,7 @@ const capabilities = {
|
|
|
881
881
|
"drift": {
|
|
882
882
|
"id": "drift",
|
|
883
883
|
"role": "feature",
|
|
884
|
-
"version": "1.7.0-rc.
|
|
884
|
+
"version": "1.7.0-rc.2",
|
|
885
885
|
"title": "Drift detection gates",
|
|
886
886
|
"description": "Drift detection gates for the planning loop. At execute:wave:post: a blocking schema drift gate (detects schema files changed without a database push) and a non-blocking codebase drift gate (detects structural additions not reflected in STRUCTURE.md). At plan:pre: a non-blocking, warn-only codebase drift gate (gated on workflow.plan_drift_precheck) that flags a stale codebase map before planning, so plans are authored against a fresh STRUCTURE.md instead of discovering drift mid-execution.",
|
|
887
887
|
"tier": "full",
|
|
@@ -959,7 +959,7 @@ const capabilities = {
|
|
|
959
959
|
"gap-analysis": {
|
|
960
960
|
"id": "gap-analysis",
|
|
961
961
|
"role": "feature",
|
|
962
|
-
"version": "1.7.0-rc.
|
|
962
|
+
"version": "1.7.0-rc.2",
|
|
963
963
|
"title": "Post-planning gap analysis",
|
|
964
964
|
"description": "Proactive, non-blocking post-planning coverage report. After all PLAN.md files are generated, cross-references every REQ-ID and D-ID from REQUIREMENTS.md and CONTEXT.md against plan bodies. Emits a Source | Item | Status table. Does not block phase advancement.",
|
|
965
965
|
"tier": "standard",
|
|
@@ -1000,7 +1000,7 @@ const capabilities = {
|
|
|
1000
1000
|
"gemini": {
|
|
1001
1001
|
"id": "gemini",
|
|
1002
1002
|
"role": "runtime",
|
|
1003
|
-
"version": "1.7.0-rc.
|
|
1003
|
+
"version": "1.7.0-rc.2",
|
|
1004
1004
|
"title": "Gemini CLI",
|
|
1005
1005
|
"description": "Google Gemini CLI — commands-only artifact layout (TOML); Gemini hook event dialect; settings-json hook surface; tier-2 support.",
|
|
1006
1006
|
"tier": "core",
|
|
@@ -1075,7 +1075,7 @@ const capabilities = {
|
|
|
1075
1075
|
"graphify": {
|
|
1076
1076
|
"id": "graphify",
|
|
1077
1077
|
"role": "feature",
|
|
1078
|
-
"version": "1.7.0-rc.
|
|
1078
|
+
"version": "1.7.0-rc.2",
|
|
1079
1079
|
"title": "Knowledge graph",
|
|
1080
1080
|
"description": "Build, query, and inspect the project knowledge graph in `.planning/graphs/`; exposes graphify CLI subcommands (build, query, status, diff) and the /gsd-graphify skill.",
|
|
1081
1081
|
"tier": "full",
|
|
@@ -1116,7 +1116,7 @@ const capabilities = {
|
|
|
1116
1116
|
"hermes": {
|
|
1117
1117
|
"id": "hermes",
|
|
1118
1118
|
"role": "runtime",
|
|
1119
|
-
"version": "1.7.0-rc.
|
|
1119
|
+
"version": "1.7.0-rc.2",
|
|
1120
1120
|
"title": "Hermes Agent",
|
|
1121
1121
|
"description": "Hermes Agent (NousResearch) — skills nest under skills/gsd/ category bucket; nested skill layout; settings-json hook surface; Claude hook event dialect; tier-2 support.",
|
|
1122
1122
|
"tier": "core",
|
|
@@ -1187,7 +1187,7 @@ const capabilities = {
|
|
|
1187
1187
|
"intel": {
|
|
1188
1188
|
"id": "intel",
|
|
1189
1189
|
"role": "feature",
|
|
1190
|
-
"version": "1.7.0-rc.
|
|
1190
|
+
"version": "1.7.0-rc.2",
|
|
1191
1191
|
"title": "Codebase intelligence",
|
|
1192
1192
|
"description": "Code-intelligence store for codebase querying, diff, snapshot, and API-surface extraction; exposes `gsd-tools intel` subcommands (query, status, update, diff, snapshot, patch-meta, validate, extract-exports, api-surface) and backs `/gsd-map-codebase` and `gsd-intel-updater`.",
|
|
1193
1193
|
"tier": "full",
|
|
@@ -1239,7 +1239,7 @@ const capabilities = {
|
|
|
1239
1239
|
"kilo": {
|
|
1240
1240
|
"id": "kilo",
|
|
1241
1241
|
"role": "runtime",
|
|
1242
|
-
"version": "1.7.0-rc.
|
|
1242
|
+
"version": "1.7.0-rc.2",
|
|
1243
1243
|
"title": "Kilo Code",
|
|
1244
1244
|
"description": "Kilo Code — XDG-based config dir; global skills at ~/.kilo/skills (separate from XDG config); flat command/ + skills artifact layout; no lifecycle hook registration; tier-2 support.",
|
|
1245
1245
|
"tier": "core",
|
|
@@ -1332,7 +1332,7 @@ const capabilities = {
|
|
|
1332
1332
|
"kimi": {
|
|
1333
1333
|
"id": "kimi",
|
|
1334
1334
|
"role": "runtime",
|
|
1335
|
-
"version": "1.7.0-rc.
|
|
1335
|
+
"version": "1.7.0-rc.2",
|
|
1336
1336
|
"title": "Kimi CLI",
|
|
1337
1337
|
"description": "Kimi CLI (Moonshot AI) — generic agents root at ~/.config/agents; skills + kimi-agents artifact layout; no hook surface; no hook events; tier-2 support.",
|
|
1338
1338
|
"tier": "core",
|
|
@@ -1406,7 +1406,7 @@ const capabilities = {
|
|
|
1406
1406
|
"mempalace": {
|
|
1407
1407
|
"id": "mempalace",
|
|
1408
1408
|
"role": "feature",
|
|
1409
|
-
"version": "1.7.0-rc.
|
|
1409
|
+
"version": "1.7.0-rc.2",
|
|
1410
1410
|
"title": "MemPalace memory",
|
|
1411
1411
|
"description": "Cross-session, cross-project memory: deliberate recall before discuss/plan and verbatim capture + temporal-KG sync at phase boundaries, via the MemPalace MCP server and CLI.",
|
|
1412
1412
|
"tier": "full",
|
|
@@ -1580,7 +1580,7 @@ const capabilities = {
|
|
|
1580
1580
|
"nyquist": {
|
|
1581
1581
|
"id": "nyquist",
|
|
1582
1582
|
"role": "feature",
|
|
1583
|
-
"version": "1.7.0-rc.
|
|
1583
|
+
"version": "1.7.0-rc.2",
|
|
1584
1584
|
"title": "Nyquist validation",
|
|
1585
1585
|
"description": "Validation coverage audit that maps executed work back to tests and manual-only evidence.",
|
|
1586
1586
|
"tier": "full",
|
|
@@ -1630,7 +1630,7 @@ const capabilities = {
|
|
|
1630
1630
|
"opencode": {
|
|
1631
1631
|
"id": "opencode",
|
|
1632
1632
|
"role": "runtime",
|
|
1633
|
-
"version": "1.7.0-rc.
|
|
1633
|
+
"version": "1.7.0-rc.2",
|
|
1634
1634
|
"title": "OpenCode",
|
|
1635
1635
|
"description": "OpenCode — XDG-based config dir; flat command/ + skills artifact layout; settings-json config format; no lifecycle hook registration; tier-2 support.",
|
|
1636
1636
|
"tier": "core",
|
|
@@ -1690,6 +1690,7 @@ const capabilities = {
|
|
|
1690
1690
|
},
|
|
1691
1691
|
"commandStyle": "slash-hyphen",
|
|
1692
1692
|
"hooksSurface": "none",
|
|
1693
|
+
"extensionEvents": "opencode",
|
|
1693
1694
|
"sandboxTier": "none",
|
|
1694
1695
|
"supportTier": 2,
|
|
1695
1696
|
"installSurface": "settings-json",
|
|
@@ -1718,7 +1719,7 @@ const capabilities = {
|
|
|
1718
1719
|
"pattern-mapper": {
|
|
1719
1720
|
"id": "pattern-mapper",
|
|
1720
1721
|
"role": "feature",
|
|
1721
|
-
"version": "1.7.0-rc.
|
|
1722
|
+
"version": "1.7.0-rc.2",
|
|
1722
1723
|
"title": "Pattern mapping",
|
|
1723
1724
|
"description": "Optional codebase-pattern mapping before planning; owns the pattern mapper agent and workflow.pattern_mapper activation key.",
|
|
1724
1725
|
"tier": "full",
|
|
@@ -1772,7 +1773,7 @@ const capabilities = {
|
|
|
1772
1773
|
"profile-pipeline": {
|
|
1773
1774
|
"id": "profile-pipeline",
|
|
1774
1775
|
"role": "feature",
|
|
1775
|
-
"version": "1.7.0-rc.
|
|
1776
|
+
"version": "1.7.0-rc.2",
|
|
1776
1777
|
"title": "Developer profiling pipeline",
|
|
1777
1778
|
"description": "Developer behavioral profiling from Claude Code session history; scans session JSONL files, extracts and samples user messages, and generates profile artifacts (USER-PROFILE.md, dev-preferences.md, CLAUDE.md sections). Exposes eight `gsd-tools` commands: scan-sessions, extract-messages, profile-sample (pipeline phase) and write-profile, profile-questionnaire, generate-dev-preferences, generate-claude-profile, generate-claude-md (output phase). Backs the /gsd-profile-user skill and gsd-user-profiler agent.",
|
|
1778
1779
|
"tier": "full",
|
|
@@ -1849,7 +1850,7 @@ const capabilities = {
|
|
|
1849
1850
|
"qwen": {
|
|
1850
1851
|
"id": "qwen",
|
|
1851
1852
|
"role": "runtime",
|
|
1852
|
-
"version": "1.7.0-rc.
|
|
1853
|
+
"version": "1.7.0-rc.2",
|
|
1853
1854
|
"title": "Qwen Code",
|
|
1854
1855
|
"description": "Qwen Code (Alibaba) — nested-skill artifact layout; settings-json hook surface; Claude hook event dialect; tier-2 support.",
|
|
1855
1856
|
"tier": "core",
|
|
@@ -1924,7 +1925,7 @@ const capabilities = {
|
|
|
1924
1925
|
"research": {
|
|
1925
1926
|
"id": "research",
|
|
1926
1927
|
"role": "feature",
|
|
1927
|
-
"version": "1.7.0-rc.
|
|
1928
|
+
"version": "1.7.0-rc.2",
|
|
1928
1929
|
"title": "Phase research",
|
|
1929
1930
|
"description": "Optional phase research before planning; owns the phase researcher agent and workflow.research activation key.",
|
|
1930
1931
|
"tier": "standard",
|
|
@@ -1976,7 +1977,7 @@ const capabilities = {
|
|
|
1976
1977
|
"schema-gate": {
|
|
1977
1978
|
"id": "schema-gate",
|
|
1978
1979
|
"role": "feature",
|
|
1979
|
-
"version": "1.7.0-rc.
|
|
1980
|
+
"version": "1.7.0-rc.2",
|
|
1980
1981
|
"title": "Schema push detection gate",
|
|
1981
1982
|
"description": "Detects ORM schema-relevant files in the phase scope during planning and injects a mandatory [BLOCKING] schema push task into the plan. Prevents false-positive verification where build/types pass because TypeScript types come from config, not the live database.",
|
|
1982
1983
|
"tier": "full",
|
|
@@ -2022,7 +2023,7 @@ const capabilities = {
|
|
|
2022
2023
|
"security": {
|
|
2023
2024
|
"id": "security",
|
|
2024
2025
|
"role": "feature",
|
|
2025
|
-
"version": "1.7.0-rc.
|
|
2026
|
+
"version": "1.7.0-rc.2",
|
|
2026
2027
|
"title": "Security enforcement",
|
|
2027
2028
|
"description": "Threat mitigation verification and ship-time security blocking for phases with security enforcement enabled.",
|
|
2028
2029
|
"tier": "full",
|
|
@@ -2121,7 +2122,7 @@ const capabilities = {
|
|
|
2121
2122
|
"tdd": {
|
|
2122
2123
|
"id": "tdd",
|
|
2123
2124
|
"role": "feature",
|
|
2124
|
-
"version": "1.7.0-rc.
|
|
2125
|
+
"version": "1.7.0-rc.2",
|
|
2125
2126
|
"title": "Test-driven development",
|
|
2126
2127
|
"description": "Injects TDD heuristics into the planner and enforces RED/GREEN gate compliance on type:tdd plans after execution. Owns workflow.tdd_mode; the --tdd CLI flag is the ephemeral override.",
|
|
2127
2128
|
"tier": "full",
|
|
@@ -2174,7 +2175,7 @@ const capabilities = {
|
|
|
2174
2175
|
"trae": {
|
|
2175
2176
|
"id": "trae",
|
|
2176
2177
|
"role": "runtime",
|
|
2177
|
-
"version": "1.7.0-rc.
|
|
2178
|
+
"version": "1.7.0-rc.2",
|
|
2178
2179
|
"title": "Trae IDE",
|
|
2179
2180
|
"description": "Trae IDE — nested-skill artifact layout; no hook surface (profile-marker-only config); tier-2 support.",
|
|
2180
2181
|
"tier": "core",
|
|
@@ -2260,7 +2261,7 @@ const capabilities = {
|
|
|
2260
2261
|
"ui": {
|
|
2261
2262
|
"id": "ui",
|
|
2262
2263
|
"role": "feature",
|
|
2263
|
-
"version": "1.7.0-rc.
|
|
2264
|
+
"version": "1.7.0-rc.2",
|
|
2264
2265
|
"title": "UI design contracts",
|
|
2265
2266
|
"description": "UI-SPEC design contract + retrospective UI audit for frontend phases.",
|
|
2266
2267
|
"tier": "full",
|
|
@@ -2355,7 +2356,7 @@ const capabilities = {
|
|
|
2355
2356
|
"windsurf": {
|
|
2356
2357
|
"id": "windsurf",
|
|
2357
2358
|
"role": "runtime",
|
|
2358
|
-
"version": "1.7.0-rc.
|
|
2359
|
+
"version": "1.7.0-rc.2",
|
|
2359
2360
|
"title": "Windsurf",
|
|
2360
2361
|
"description": "Windsurf (Codeium) — workspace workflow artifact layout for slash commands; no hook surface; no hook events; tier-2 support.",
|
|
2361
2362
|
"tier": "core",
|
|
@@ -3180,7 +3181,7 @@ const runtimes = {
|
|
|
3180
3181
|
"antigravity": {
|
|
3181
3182
|
"id": "antigravity",
|
|
3182
3183
|
"role": "runtime",
|
|
3183
|
-
"version": "1.7.0-rc.
|
|
3184
|
+
"version": "1.7.0-rc.2",
|
|
3184
3185
|
"title": "Antigravity",
|
|
3185
3186
|
"description": "Google Antigravity IDE — nested under ~/.gemini/antigravity; probed across 1.x and 2.x layouts; Gemini hook event dialect; flat skill layout; tier-1 support.",
|
|
3186
3187
|
"tier": "core",
|
|
@@ -3258,7 +3259,7 @@ const runtimes = {
|
|
|
3258
3259
|
"augment": {
|
|
3259
3260
|
"id": "augment",
|
|
3260
3261
|
"role": "runtime",
|
|
3261
|
-
"version": "1.7.0-rc.
|
|
3262
|
+
"version": "1.7.0-rc.2",
|
|
3262
3263
|
"title": "Augment Code",
|
|
3263
3264
|
"description": "Augment Code CLI — commands + nested-skill artifact layout; settings-json hook surface; Claude hook event dialect; tier-2 support.",
|
|
3264
3265
|
"tier": "core",
|
|
@@ -3361,7 +3362,7 @@ const runtimes = {
|
|
|
3361
3362
|
"claude": {
|
|
3362
3363
|
"id": "claude",
|
|
3363
3364
|
"role": "runtime",
|
|
3364
|
-
"version": "1.7.0-rc.
|
|
3365
|
+
"version": "1.7.0-rc.2",
|
|
3365
3366
|
"title": "Claude Code",
|
|
3366
3367
|
"description": "Anthropic Claude Code — primary development runtime; tier-1 support with full hook surface and skills-based global install.",
|
|
3367
3368
|
"tier": "core",
|
|
@@ -3445,7 +3446,7 @@ const runtimes = {
|
|
|
3445
3446
|
"cline": {
|
|
3446
3447
|
"id": "cline",
|
|
3447
3448
|
"role": "runtime",
|
|
3448
|
-
"version": "1.7.0-rc.
|
|
3449
|
+
"version": "1.7.0-rc.2",
|
|
3449
3450
|
"title": "Cline",
|
|
3450
3451
|
"description": "Cline (VS Code extension) — global-only nested-skill layout; cline-rules hook surface (.clinerules); no hook events emitted; tier-2 support.",
|
|
3451
3452
|
"tier": "core",
|
|
@@ -3506,7 +3507,7 @@ const runtimes = {
|
|
|
3506
3507
|
"codebuddy": {
|
|
3507
3508
|
"id": "codebuddy",
|
|
3508
3509
|
"role": "runtime",
|
|
3509
|
-
"version": "1.7.0-rc.
|
|
3510
|
+
"version": "1.7.0-rc.2",
|
|
3510
3511
|
"title": "CodeBuddy",
|
|
3511
3512
|
"description": "CodeBuddy (Tencent) — converted commands + skills artifact layout; settings-json hook surface; Claude hook event dialect; tier-2 support.",
|
|
3512
3513
|
"tier": "core",
|
|
@@ -3609,7 +3610,7 @@ const runtimes = {
|
|
|
3609
3610
|
"codex": {
|
|
3610
3611
|
"id": "codex",
|
|
3611
3612
|
"role": "runtime",
|
|
3612
|
-
"version": "1.7.0-rc.
|
|
3613
|
+
"version": "1.7.0-rc.2",
|
|
3613
3614
|
"title": "OpenAI Codex CLI",
|
|
3614
3615
|
"description": "OpenAI Codex CLI — shell-var command style; per-agent sandbox tiers; config.toml + hooks.json hook surface; tier-1 support.",
|
|
3615
3616
|
"tier": "core",
|
|
@@ -3680,7 +3681,7 @@ const runtimes = {
|
|
|
3680
3681
|
"copilot": {
|
|
3681
3682
|
"id": "copilot",
|
|
3682
3683
|
"role": "runtime",
|
|
3683
|
-
"version": "1.7.0-rc.
|
|
3684
|
+
"version": "1.7.0-rc.2",
|
|
3684
3685
|
"title": "GitHub Copilot",
|
|
3685
3686
|
"description": "GitHub Copilot (VS Code) — markdown config format; copilot-inline hook surface; no hook events emitted; flat skill nesting (unconfirmed recursive loader); tier-2 support.",
|
|
3686
3687
|
"tier": "core",
|
|
@@ -3751,7 +3752,7 @@ const runtimes = {
|
|
|
3751
3752
|
"cursor": {
|
|
3752
3753
|
"id": "cursor",
|
|
3753
3754
|
"role": "runtime",
|
|
3754
|
-
"version": "1.7.0-rc.
|
|
3755
|
+
"version": "1.7.0-rc.2",
|
|
3755
3756
|
"title": "Cursor",
|
|
3756
3757
|
"description": "Cursor IDE — skills + converted commands artifact layout; hooks.json surface; Claude hook event dialect; recursive skill loader (flat nesting); tier-2 support.",
|
|
3757
3758
|
"tier": "core",
|
|
@@ -3854,7 +3855,7 @@ const runtimes = {
|
|
|
3854
3855
|
"gemini": {
|
|
3855
3856
|
"id": "gemini",
|
|
3856
3857
|
"role": "runtime",
|
|
3857
|
-
"version": "1.7.0-rc.
|
|
3858
|
+
"version": "1.7.0-rc.2",
|
|
3858
3859
|
"title": "Gemini CLI",
|
|
3859
3860
|
"description": "Google Gemini CLI — commands-only artifact layout (TOML); Gemini hook event dialect; settings-json hook surface; tier-2 support.",
|
|
3860
3861
|
"tier": "core",
|
|
@@ -3929,7 +3930,7 @@ const runtimes = {
|
|
|
3929
3930
|
"hermes": {
|
|
3930
3931
|
"id": "hermes",
|
|
3931
3932
|
"role": "runtime",
|
|
3932
|
-
"version": "1.7.0-rc.
|
|
3933
|
+
"version": "1.7.0-rc.2",
|
|
3933
3934
|
"title": "Hermes Agent",
|
|
3934
3935
|
"description": "Hermes Agent (NousResearch) — skills nest under skills/gsd/ category bucket; nested skill layout; settings-json hook surface; Claude hook event dialect; tier-2 support.",
|
|
3935
3936
|
"tier": "core",
|
|
@@ -4000,7 +4001,7 @@ const runtimes = {
|
|
|
4000
4001
|
"kilo": {
|
|
4001
4002
|
"id": "kilo",
|
|
4002
4003
|
"role": "runtime",
|
|
4003
|
-
"version": "1.7.0-rc.
|
|
4004
|
+
"version": "1.7.0-rc.2",
|
|
4004
4005
|
"title": "Kilo Code",
|
|
4005
4006
|
"description": "Kilo Code — XDG-based config dir; global skills at ~/.kilo/skills (separate from XDG config); flat command/ + skills artifact layout; no lifecycle hook registration; tier-2 support.",
|
|
4006
4007
|
"tier": "core",
|
|
@@ -4093,7 +4094,7 @@ const runtimes = {
|
|
|
4093
4094
|
"kimi": {
|
|
4094
4095
|
"id": "kimi",
|
|
4095
4096
|
"role": "runtime",
|
|
4096
|
-
"version": "1.7.0-rc.
|
|
4097
|
+
"version": "1.7.0-rc.2",
|
|
4097
4098
|
"title": "Kimi CLI",
|
|
4098
4099
|
"description": "Kimi CLI (Moonshot AI) — generic agents root at ~/.config/agents; skills + kimi-agents artifact layout; no hook surface; no hook events; tier-2 support.",
|
|
4099
4100
|
"tier": "core",
|
|
@@ -4167,7 +4168,7 @@ const runtimes = {
|
|
|
4167
4168
|
"opencode": {
|
|
4168
4169
|
"id": "opencode",
|
|
4169
4170
|
"role": "runtime",
|
|
4170
|
-
"version": "1.7.0-rc.
|
|
4171
|
+
"version": "1.7.0-rc.2",
|
|
4171
4172
|
"title": "OpenCode",
|
|
4172
4173
|
"description": "OpenCode — XDG-based config dir; flat command/ + skills artifact layout; settings-json config format; no lifecycle hook registration; tier-2 support.",
|
|
4173
4174
|
"tier": "core",
|
|
@@ -4227,6 +4228,7 @@ const runtimes = {
|
|
|
4227
4228
|
},
|
|
4228
4229
|
"commandStyle": "slash-hyphen",
|
|
4229
4230
|
"hooksSurface": "none",
|
|
4231
|
+
"extensionEvents": "opencode",
|
|
4230
4232
|
"sandboxTier": "none",
|
|
4231
4233
|
"supportTier": 2,
|
|
4232
4234
|
"installSurface": "settings-json",
|
|
@@ -4255,7 +4257,7 @@ const runtimes = {
|
|
|
4255
4257
|
"qwen": {
|
|
4256
4258
|
"id": "qwen",
|
|
4257
4259
|
"role": "runtime",
|
|
4258
|
-
"version": "1.7.0-rc.
|
|
4260
|
+
"version": "1.7.0-rc.2",
|
|
4259
4261
|
"title": "Qwen Code",
|
|
4260
4262
|
"description": "Qwen Code (Alibaba) — nested-skill artifact layout; settings-json hook surface; Claude hook event dialect; tier-2 support.",
|
|
4261
4263
|
"tier": "core",
|
|
@@ -4330,7 +4332,7 @@ const runtimes = {
|
|
|
4330
4332
|
"trae": {
|
|
4331
4333
|
"id": "trae",
|
|
4332
4334
|
"role": "runtime",
|
|
4333
|
-
"version": "1.7.0-rc.
|
|
4335
|
+
"version": "1.7.0-rc.2",
|
|
4334
4336
|
"title": "Trae IDE",
|
|
4335
4337
|
"description": "Trae IDE — nested-skill artifact layout; no hook surface (profile-marker-only config); tier-2 support.",
|
|
4336
4338
|
"tier": "core",
|
|
@@ -4416,7 +4418,7 @@ const runtimes = {
|
|
|
4416
4418
|
"windsurf": {
|
|
4417
4419
|
"id": "windsurf",
|
|
4418
4420
|
"role": "runtime",
|
|
4419
|
-
"version": "1.7.0-rc.
|
|
4421
|
+
"version": "1.7.0-rc.2",
|
|
4420
4422
|
"title": "Windsurf",
|
|
4421
4423
|
"description": "Windsurf (Codeium) — workspace workflow artifact layout for slash commands; no hook surface; no hook events; tier-2 support.",
|
|
4422
4424
|
"tier": "core",
|
|
@@ -153,16 +153,31 @@ function _setCapabilitySourceHttpGet(fn) {
|
|
|
153
153
|
// ---------------------------------------------------------------------------
|
|
154
154
|
// Helpers
|
|
155
155
|
// ---------------------------------------------------------------------------
|
|
156
|
-
/**
|
|
157
|
-
|
|
156
|
+
/**
|
|
157
|
+
* Resolve the running GSD version; fail-closed to '0.0.0'.
|
|
158
|
+
*
|
|
159
|
+
* Prefer the authoritative `gsd-core/VERSION` the installer writes for EVERY runtime
|
|
160
|
+
* (libDir = gsd-core/bin/lib/, so `../../VERSION` = gsd-core/VERSION), so installed
|
|
161
|
+
* layouts report the true version even when the walked-up `../../../package.json` is
|
|
162
|
+
* absent or belongs to the user's own project (#1920). Fall back to the runtime-root
|
|
163
|
+
* package.json (dev/source tree), then fail-closed. Mirrors resolveVersionFrom() (#1383).
|
|
164
|
+
*/
|
|
165
|
+
function readHostVersion(libDir = __dirname) {
|
|
166
|
+
const SEMVER_PREFIX = /^\d+\.\d+\.\d+/;
|
|
158
167
|
try {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
168
|
+
const v = node_fs_1.default.readFileSync(node_path_1.default.join(libDir, '..', '..', 'VERSION'), 'utf8').trim();
|
|
169
|
+
if (SEMVER_PREFIX.test(v))
|
|
170
|
+
return v;
|
|
162
171
|
}
|
|
163
|
-
catch {
|
|
164
|
-
|
|
172
|
+
catch { /* not an installed tree (no gsd-core/VERSION) */ }
|
|
173
|
+
try {
|
|
174
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
175
|
+
const pkg = require(node_path_1.default.join(libDir, '..', '..', '..', 'package.json'));
|
|
176
|
+
if (pkg && typeof pkg.version === 'string' && SEMVER_PREFIX.test(pkg.version))
|
|
177
|
+
return pkg.version;
|
|
165
178
|
}
|
|
179
|
+
catch { /* runtime root has no package.json */ }
|
|
180
|
+
return '0.0.0';
|
|
166
181
|
}
|
|
167
182
|
/** Compute sha512-<base64> integrity over a buffer. */
|
|
168
183
|
function computeIntegrity(buf) {
|
|
@@ -704,7 +704,12 @@ const VALID_CONFIG_FORMATS = new Set(['settings-json', 'toml', 'markdown', 'mark
|
|
|
704
704
|
const VALID_CONFIG_HOME_KINDS = new Set(['dot-home', 'dot-home-nested', 'xdg', 'generic-agents-root']);
|
|
705
705
|
const VALID_COMMAND_STYLES = new Set(['slash-hyphen', 'shell-var']);
|
|
706
706
|
const VALID_HOOKS_SURFACES = new Set(['settings-json', 'codex-hooks-json', 'cursor-hooks-json', 'copilot-inline', 'cline-rules', 'none']);
|
|
707
|
-
const VALID_HOOK_EVENTS = new Set(['claude', 'gemini'
|
|
707
|
+
const VALID_HOOK_EVENTS = new Set(['claude', 'gemini']);
|
|
708
|
+
// extensionEvents — the plugin/extension-system event dialect (ADR-1239 amendment / #1943).
|
|
709
|
+
// DISTINCT from hookEvents (managed-hook dialect): extensionEvents describes the
|
|
710
|
+
// plugin-owned event subset imperative hosts expose (opencode / pi); 'none' = the
|
|
711
|
+
// host exposes no extension surface (engine owns the bus, e.g. VS Code).
|
|
712
|
+
const VALID_EXTENSION_EVENTS = new Set(['opencode', 'pi', 'none']);
|
|
708
713
|
const VALID_SANDBOX_TIERS = new Set(['none', 'codex-agent-sandbox']);
|
|
709
714
|
const VALID_ARTIFACT_KIND_NAMES = new Set(['commands', 'agents', 'skills', 'kimi-agents']);
|
|
710
715
|
const VALID_ARTIFACT_NESTINGS = new Set(['flat', 'nested']);
|
|
@@ -978,7 +983,9 @@ function validateRuntimeBody(cap) {
|
|
|
978
983
|
);
|
|
979
984
|
}
|
|
980
985
|
|
|
981
|
-
// hookEvents — optional; if present must be in closed
|
|
986
|
+
// hookEvents — optional; if present must be in closed enum (ADR-1016 Decision 5).
|
|
987
|
+
// Managed-hook dialect only (claude/gemini). The OpenCode extension-system event
|
|
988
|
+
// subset is NOT a hookEvents value — it is `extensionEvents` (ADR-1239 / #1943).
|
|
982
989
|
if (r.hookEvents !== undefined) {
|
|
983
990
|
if (r.hookEvents === '__proto__' || r.hookEvents === 'constructor' || r.hookEvents === 'prototype') {
|
|
984
991
|
errors.push('runtime.hookEvents "' + r.hookEvents + '" is a reserved name');
|
|
@@ -990,6 +997,20 @@ function validateRuntimeBody(cap) {
|
|
|
990
997
|
}
|
|
991
998
|
}
|
|
992
999
|
|
|
1000
|
+
// extensionEvents — optional; the extension-system event dialect (ADR-1239 amendment / #1943).
|
|
1001
|
+
// Distinct from hookEvents. Only imperative-embedding hosts (with a plugin/extension
|
|
1002
|
+
// API) set it; declarative hosts do not.
|
|
1003
|
+
if (r.extensionEvents !== undefined) {
|
|
1004
|
+
if (r.extensionEvents === '__proto__' || r.extensionEvents === 'constructor' || r.extensionEvents === 'prototype') {
|
|
1005
|
+
errors.push('runtime.extensionEvents "' + r.extensionEvents + '" is a reserved name');
|
|
1006
|
+
} else if (!VALID_EXTENSION_EVENTS.has(r.extensionEvents)) {
|
|
1007
|
+
errors.push(
|
|
1008
|
+
'runtime.extensionEvents must be one of: ' + [...VALID_EXTENSION_EVENTS].join(', ') +
|
|
1009
|
+
' (got: ' + JSON.stringify(r.extensionEvents) + ')',
|
|
1010
|
+
);
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
|
|
993
1014
|
// sandboxTier — closed 2-enum (ADR-1016 Decision 6); inline literal guard (CodeQL barrier)
|
|
994
1015
|
if (r.sandboxTier === '__proto__' || r.sandboxTier === 'constructor' || r.sandboxTier === 'prototype') {
|
|
995
1016
|
errors.push('runtime.sandboxTier "' + r.sandboxTier + '" is a reserved name');
|
|
@@ -2225,6 +2246,7 @@ module.exports = {
|
|
|
2225
2246
|
VALID_COMMAND_STYLES,
|
|
2226
2247
|
VALID_HOOKS_SURFACES,
|
|
2227
2248
|
VALID_HOOK_EVENTS,
|
|
2249
|
+
VALID_EXTENSION_EVENTS,
|
|
2228
2250
|
VALID_SANDBOX_TIERS,
|
|
2229
2251
|
VALID_ARTIFACT_KIND_NAMES,
|
|
2230
2252
|
VALID_ARTIFACT_NESTINGS,
|
|
@@ -1302,7 +1302,8 @@ function cmdStats(cwd, format, raw) {
|
|
|
1302
1302
|
const roadmapContent = extractCurrentMilestone(roadmapRaw, cwd);
|
|
1303
1303
|
// Matches both plain numeric (Phase 1:) and milestone-prefixed (Phase 2-01:) headings.
|
|
1304
1304
|
// Also tolerates optional [bracket-token] scope prefix on phase headings.
|
|
1305
|
-
|
|
1305
|
+
// #1729: `(?:\s*\([^)\n]*\))?` tolerates a pre-colon ( ) tag (literal mirror of OPTIONAL_PHASE_TAG_SOURCE).
|
|
1306
|
+
const headingPattern = /#{2,4}\s*(?:\[[^\]]+\]\s*)?Phase\s+([\w][\w.-]*)(?:\s*\([^)\n]*\))?\s*:\s*([^\n]+)/gi;
|
|
1306
1307
|
let match;
|
|
1307
1308
|
while ((match = headingPattern.exec(roadmapContent)) !== null) {
|
|
1308
1309
|
const key = normalizePhaseName(match[1]);
|
|
@@ -126,6 +126,49 @@ function extractFrontmatter(content) {
|
|
|
126
126
|
}
|
|
127
127
|
return frontmatter;
|
|
128
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Escape a string for emission inside a YAML double-quoted scalar (#1779).
|
|
131
|
+
* Backslash must be escaped first so the backslashes added for embedded quotes
|
|
132
|
+
* (and control chars) are not themselves doubled. Without this, a value
|
|
133
|
+
* carrying an indicator (`:`/`#`) that also contains a literal `"` serializes
|
|
134
|
+
* to invalid YAML, e.g. `upstream: "https://x (Tom; "Git. Ship. Done")"`. A
|
|
135
|
+
* literal newline/tab/control char inside the quotes likewise breaks (or
|
|
136
|
+
* silently alters) the scalar, so those are escaped to their YAML forms too.
|
|
137
|
+
*/
|
|
138
|
+
function escapeDoubleQuoted(s) {
|
|
139
|
+
return s
|
|
140
|
+
.replace(/\\/g, '\\\\')
|
|
141
|
+
.replace(/"/g, '\\"')
|
|
142
|
+
.replace(/\n/g, '\\n')
|
|
143
|
+
.replace(/\t/g, '\\t')
|
|
144
|
+
.replace(/\r/g, '\\r')
|
|
145
|
+
// Remaining C0 controls + DEL → \xHH (a valid YAML double-quoted escape).
|
|
146
|
+
.replace(/[\u0000-\u001f\u007f]/g, (c) => `\\x${c.charCodeAt(0).toString(16).padStart(2, '0')}`);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* A plain (unquoted) scalar that would mis-parse or round-trip lossily when
|
|
150
|
+
* emitted bare must instead go through the double-quoted + escaped form
|
|
151
|
+
* (#1779): the empty string (bare `k:` reloads as null), an embedded `"`/`\`
|
|
152
|
+
* or control char, a leading YAML indicator (quote, `&`/`*`/`!` anchor/alias/
|
|
153
|
+
* tag, `|`/`>` block scalar, flow `[]{},`, `#`, reserved `%`/`@`/backtick, or
|
|
154
|
+
* `-`/`?`/`:` before a space), or leading/trailing whitespace. This helper is
|
|
155
|
+
* the correctness complement of `escapeDoubleQuoted`: it broadens the *trigger*
|
|
156
|
+
* for quoting without broadening the lossy object-list handling deferred to
|
|
157
|
+
* #1572/#1660.
|
|
158
|
+
*/
|
|
159
|
+
function scalarNeedsDoubleQuoting(s) {
|
|
160
|
+
if (s === '')
|
|
161
|
+
return true;
|
|
162
|
+
if (/["\\\u0000-\u001f\u007f]/.test(s))
|
|
163
|
+
return true;
|
|
164
|
+
// Always-unsafe leading indicators, or leading/trailing whitespace.
|
|
165
|
+
if (/^[,[\]{}#&*!|>'"%@`]/.test(s) || /^\s|\s$/.test(s))
|
|
166
|
+
return true;
|
|
167
|
+
// `-` `?` `:` only start a plain scalar safely when NOT followed by a space.
|
|
168
|
+
if (/^[-?:](\s|$)/.test(s))
|
|
169
|
+
return true;
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
129
172
|
function reconstructFrontmatter(obj) {
|
|
130
173
|
const lines = [];
|
|
131
174
|
for (const [key, value] of Object.entries(obj)) {
|
|
@@ -141,7 +184,7 @@ function reconstructFrontmatter(obj) {
|
|
|
141
184
|
else {
|
|
142
185
|
lines.push(`${key}:`);
|
|
143
186
|
for (const item of value) {
|
|
144
|
-
lines.push(` - ${typeof item === 'string' && (item.includes(':') || item.includes('#')) ? `"${item}"` : item}`);
|
|
187
|
+
lines.push(` - ${typeof item === 'string' && (item.includes(':') || item.includes('#') || scalarNeedsDoubleQuoting(item)) ? `"${escapeDoubleQuoted(item)}"` : item}`);
|
|
145
188
|
}
|
|
146
189
|
}
|
|
147
190
|
}
|
|
@@ -160,7 +203,7 @@ function reconstructFrontmatter(obj) {
|
|
|
160
203
|
else {
|
|
161
204
|
lines.push(` ${subkey}:`);
|
|
162
205
|
for (const item of subval) {
|
|
163
|
-
lines.push(` - ${typeof item === 'string' && (item.includes(':') || item.includes('#')) ? `"${item}"` : item}`);
|
|
206
|
+
lines.push(` - ${typeof item === 'string' && (item.includes(':') || item.includes('#') || scalarNeedsDoubleQuoting(item)) ? `"${escapeDoubleQuoted(item)}"` : item}`);
|
|
164
207
|
}
|
|
165
208
|
}
|
|
166
209
|
}
|
|
@@ -189,14 +232,14 @@ function reconstructFrontmatter(obj) {
|
|
|
189
232
|
else {
|
|
190
233
|
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
191
234
|
const sv = String(subval);
|
|
192
|
-
lines.push(` ${subkey}: ${sv.includes(':') || sv.includes('#') ? `"${sv}"` : sv}`);
|
|
235
|
+
lines.push(` ${subkey}: ${sv.includes(':') || sv.includes('#') || scalarNeedsDoubleQuoting(sv) ? `"${escapeDoubleQuoted(sv)}"` : sv}`);
|
|
193
236
|
}
|
|
194
237
|
}
|
|
195
238
|
}
|
|
196
239
|
else {
|
|
197
240
|
const sv = String(value);
|
|
198
|
-
if (sv.includes(':') || sv.includes('#') || sv.startsWith('[') || sv.startsWith('{')) {
|
|
199
|
-
lines.push(`${key}: "${sv}"`);
|
|
241
|
+
if (sv.includes(':') || sv.includes('#') || sv.startsWith('[') || sv.startsWith('{') || scalarNeedsDoubleQuoting(sv)) {
|
|
242
|
+
lines.push(`${key}: "${escapeDoubleQuoted(sv)}"`);
|
|
200
243
|
}
|
|
201
244
|
else {
|
|
202
245
|
lines.push(`${key}: ${sv}`);
|
|
@@ -448,7 +491,11 @@ function parseMustHavesBlock(content, blockName) {
|
|
|
448
491
|
else {
|
|
449
492
|
const kvMatch = trimmed.match(/^(\w+):\s*"?([^"]*)"?\s*$/);
|
|
450
493
|
if (kvMatch) {
|
|
451
|
-
|
|
494
|
+
// Trim: a quoted value like `"backstop "` captures the inner trailing space in group 2.
|
|
495
|
+
// Left untrimmed, a hand-authored `must_haves` marker degrades (a `backstop` truth silently
|
|
496
|
+
// grades green instead of abstaining — #1905, the #1154 false-pass; also the sibling
|
|
497
|
+
// check_target/violationFixture path). Whitespace is never semantic in a scalar KV value.
|
|
498
|
+
const val = kvMatch[2].trim();
|
|
452
499
|
// Try to parse as number
|
|
453
500
|
(current)[kvMatch[1]] = /^\d+$/.test(val) ? parseInt(val, 10) : val;
|
|
454
501
|
}
|